Jak
Jak

Reputation: 3243

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', ...}]

Upvotes: 7

Views: 6731

Answers (4)

sangeethkumar
sangeethkumar

Reputation: 821

Try this solution..

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


a = []
output = []
input.collect do |i|
  input.delete(i) if !a.include?(i[:name])
  output << i if !a.include?(i[:name])
  a << i[:name] if !a.include?(i[:name])
end


output = [{:some_key=>"value", :name=>"Kutty", :score=>2}, 
          {:some_key=>"value", :name=>"Baba", :score=>5}] 

UPDATED

output = {}
input.each do |e|
  ref = output[e[:name]]
  if ref && ref[:score] > e[:score]
    #nothing
  else
    output[e[:name]] = e
  end
end

check output:

puts output.values

Upvotes: 4

Joachim Isaksson
Joachim Isaksson

Reputation: 181097

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.

Upvotes: 17

Jakobinsky
Jakobinsky

Reputation: 1294

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

Upvotes: 4

Thilo
Thilo

Reputation: 17735

input.uniq{|hash| hash[:name]}

Upvotes: 1

Related Questions