Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Ruby remove duplicate entries in array of hashes but based on more than one value

I've seen numerous questions about this but only with one key, never for multiple keys.

I have the following array of hashes:

a = [{:name=>"Yes, Yes, Yes", :artist=>"Some Dude", :composer=> 'First Dude', :duration=>"3:21"},
 {:name=>"Chick on the Side", :artist=>"Another Dude", :duration=>"3:20"},
 {:name=>"Luv Is", :duration=>"3:13"},
 {:name=>"Yes, Yes, Yes", :artist=>"Some Dude", :composer=> 'First Dude', :duration=>"2"},
 {:name=>"Chick on the Side", :artist=>"Another Dude"}]

a.uniq won't work here because the duration is different or might not even exist. I have a unique key set up in the database that does not allow duplicate entries by the same name, artist and composer so I sometimes get errors when people have duplicate entries for these 3 keys.

Is there a way to run uniq that would check for those 3 keys? I tried a block like this:

 new_tracks.uniq do |a_track|
   a_track[:name]
   a_track[:artist]
   a_track[:composer]
 end

But that ignores anything where the key is not present (any entry without a composer does not meet the above criteria for example).

I could always use just the :name key but that would mean I'm getting rid of potentially valid tracks in compilations that have the same title but different artist or composer.

This is with Ruby 2.0.

like image 766
kakubei Avatar asked Dec 13 '13 12:12

kakubei


People also ask

How do you remove duplicates from an array in Ruby?

With the uniq method you can remove ALL the duplicate elements from an array. Let's see how it works! Where the number 1 is duplicated. Calling uniq on this array removes the extra ones & returns a NEW array with unique numbers.

How do you remove duplicates from an array of arrays?

To remove duplicates from an array: First, convert an array of duplicates to a Set . The new Set will implicitly remove duplicate elements. Then, convert the set back to an array.

What does .uniq do in Ruby?

uniq is a Ruby method that returns a new array by removing duplicate elements or values of the array. The array is traversed in order and the first occurrence is kept.

What is the difference between array and hash in Ruby?

Ruby's arrays and hashes are indexed collections. Both store collections of objects, accessible using a key. With arrays, the key is an integer, whereas hashes support any object as a key. Both arrays and hashes grow as needed to hold new elements.


2 Answers

uniq accepts a block. If a block is given, it will use the return value of the block for comparison.

Your code was close to the solution, but in your code the return value was only a_track[:composer] which is the last evaluated statement.

You can join the attributes you want into a string and return that string.

new_tracks.uniq { |track| [track[:name], track[:artist], track[:composer]].join(":") }

A possible refactoring is

new_tracks.uniq { |track| track.attributes.slice('name', 'artist', 'composer').values.join(":") }

Or add a custom method in your model that performs the join, and call it

class Track < ActiveRecord::Base
  def digest
    attributes.slice('name', 'artist', 'composer').values.join(":")
  end
end

new_tracks.uniq(&:digest)
like image 126
Simone Carletti Avatar answered Sep 22 '22 23:09

Simone Carletti


Another way to do it is to use values_at. if you don't want to use slice and join

a.uniq {|hash| hash.values_at(:name, :composer, :artist)}
like image 45
sujay Avatar answered Sep 23 '22 23:09

sujay