Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Remove duplicate from an array in ruby

I want to output an array of hashes with the name being unique to all hashes. How would I go about doing this using ruby?

This is my input:

input = [{:name => "Kutty", :score => 2, :some_key => 'value', ...},
         {:name => "Kutty", :score => 4, :some_key => 'value', ...},
         {:name => "Baba", :score => 5, :some_key => 'value', ...}]

I want the output to look like this:

  output = [{:name => "Kutty", :score => 4, :some_key => 'value', ...},
            {:name => "Baba", :score => 5, :some_key => 'value', ...}]
like image 463
Jak Avatar asked Mar 07 '12 11:03

Jak


People also ask

How do I remove a duplicate element from an array?

We can remove duplicate element in an array by 2 ways: using temporary array or using separate index. To remove the duplicate element from array, the array must be in sorted order. If array is not sorted, you can sort it by calling Arrays. sort(arr) method.

How do you delete an element from an array in Ruby?

Ruby | Array delete() operation Array#delete() : delete() is a Array class method which returns the array after deleting the mentioned elements. It can also delete a particular element in the array. Syntax: Array. delete() Parameter: obj - specific element to delete Return: last deleted values from the 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.


2 Answers

To just remove duplicates based on :name, simply try;

output = input.uniq { |x| x[:name] }

Demo here.

Edit: Since you added a sorting requirement in the comments, here's how to select the entry with the highest score for every name if you're using Rails, I see you already got an answer for "standard" Ruby above;

output = input.group_by { |x| x[:name] }
              .map {|x,y|y.max_by {|x|x[:score]}}

A little explanation may be in order; the first line groups the entries by name so that each name gets its own array of entries. The second line goes through the groups, name by name, and maps each name group to the entry with the highest score.

Demo here.

like image 117
Joachim Isaksson Avatar answered Oct 16 '22 09:10

Joachim Isaksson


input = [{:name => "Kutty", :score => 2, :some_key => 'value'},{:name => "Kutty", :score => 4, :some_key => 'value'},{:name => "Baba", :score => 5, :some_key => 'value'}]
p input.uniq { |e| e[:name] }

The above solution works for ruby > 1.9, for older versions of ruby you could use something along these lines:

input = [{:name => "Kutty", :score => 2, :some_key => 'value'},{:name => "Kutty", :score => 4, :some_key => 'value'},{:name => "Baba", :score => 5, :some_key => 'value'}]
unames = []
new_input = input.delete_if { |e|
  if unames.include?(e[:name])
    true
  else
    unames << e[:name]
    false
  end
}
p new_input
like image 24
Jakobinsky Avatar answered Oct 16 '22 10:10

Jakobinsky