DEV Community

Miguel Jimenez
Miguel Jimenez

Posted on • Edited on

Array Set Operators in Ruby

Ruby comes equipped with a bunch of amazing operators for Arrays.

Let's say I am working on lists of animals.

animals_list = %w(duck tiger snake)
other_animals_list = %w(wolf duck tiger)
Enter fullscreen mode Exit fullscreen mode

I might want to merge both lists, without duplicates.

master_list = animals_list.concat(other_animals_list).uniq

#=> ["duck", "tiger", "snake", "wolf"]
Enter fullscreen mode Exit fullscreen mode

Semantically, it feels too heavy to do two method calls for something so intuitive as a list without duplicates. Gladly, Ruby gives us the union operator

master_list = animals_list | other_animals_list

#=> ["duck", "tiger", "snake", "wolf"]
Enter fullscreen mode Exit fullscreen mode

How neat is that?

I might also want to extract which animals are common to both lists. Let's say I do something like

all_animals = animals_list.concat(other_animals_list)
common_to_both = all_animals.keep_if { |animal| all_animals.count(animal) > 1 }.uniq

#=> ["duck", "tiger"]

common_to_both = all_animals.select {|animal| all_animals.count(animal) > 1 }

#=> ["duck", "tiger"]
Enter fullscreen mode Exit fullscreen mode

Both approaches are heavy-handed and require two variable declarations. Again, Ruby has us covered with the intersection operator

common_to_both = animals_list & other_animals_list

#=> ["duck", "tiger"]
Enter fullscreen mode Exit fullscreen mode

We also can use the subtraction operator to compare arrays and see elements that are not shared

uniq_to_animals_list = animals_list - other_animals_list
#=> ["wolf"]

uniq_to_other_animals_list = other_animals_list - animals_list
#=> ["snake"]
Enter fullscreen mode Exit fullscreen mode

Another neat thing is that we can combine these operators with the equals operator. Let's say I want to update a list with elements of other lists, but I don't want to keep any duplicates.

dirty_animal_lists = [["dolphin", "duck", "duck", "duck"],["lemur", "snake", "snake", "snake"]] 

dirty_animal_lists.each_with_object([]) { |list, clean_list| clean_list |= list }

#=> ["duck", "tiger", "snake", "dolphin", "lemur"]
Enter fullscreen mode Exit fullscreen mode

The only downside to this approach is that animals_list gets reassigned every single iteration and it might be too inefficient if you are working with huge things. For such cases, take a look at the Set documentation.

Top comments (0)