af83

Soyez unique, utilisez des Sets

En Ruby, on utilise très souvent les deux structures composites que sont les tableaux et les hashs. Mais la bibliothèque standard ne se limite pas à ces deux là.

Je fais toujours une grimace quand je vois du code qui ressemble à ça :

foos = []
data.each do |data|
  foo = transform(data)
  foos << foo unless foos.include?(foo)
end
do_something_with(foos)

Ce code construit un tableau d'objets sans doublon. Pour cela, avant d'insérer un élément dans le tableau, il vérifie que celui-ci n'est pas déjà présent dans le code.

Or, pour ce besoin précis, Ruby propose des Sets, c'est-à-dire un ensemble non ordonné d'éléments uniques. L'exemple précédent devient :

require "set"
foos = Set.new
data.each do |data|
  foos << transform(data)
end
do_something_with(foos)

Les Sets sont des Enumerables qui s'utilisent un peu comme des tableaux, mais qui évitent tout doublon :

require "set"
foos = [3, 2, 1].to_set
foos << 2
foos  # ~> #<Set: {3, 2, 1}>

En dehors de l'aspect pratique, les Sets sont également plus performants que les tableaux pour ce cas d'usage. Dans le cas du tableau, avant d'ajouter un élément, il faut parcourir tout le tableau pour vérifier que l'élément n'est pas déjà présent. Par contre, les Sets utilisent des Hashs pour le stockage et le temps d'insertion d'un élément ne dépendra pas du nombre d'éléments dans le Set.

Une variante intéressante des Sets sont les SortedSets. Ils sont similaires aux Sets mais garantissent que l'on accède à leurs éléments dans l'ordre. Ce sera sûrement plus clair sur un exemple :

require "set"
foos = SortedSet.new
foos << 3
foos << 1
foos << 2
foos << 2
foos.to_a  # ~> [1, 2, 3]

Voilà, j'espère que la prochaine fois que vous aurez besoin d'une collection d'éléments uniques, vous penserez à utiliser les Sets pour m'éviter une grimace le jour où j'irais lire votre code sur github ;-)

blog comments powered by Disqus