7

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', ...}]
3
  • I basically don't want duplicate hash entry in the array!. And i want it based more score. Commented Mar 7, 2012 at 11:42
  • If I understand your comment correctly, your given output is wrong. Kutty's highest score is 4. Commented Mar 7, 2012 at 12:29
  • yes mark.. Anyway I got solution.. Just an conditional operator is need to change. Thanks for the find.. I ll update my ques. Commented Mar 8, 2012 at 8:30

4 Answers 4

17

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.

Sign up to request clarification or add additional context in comments.

Comments

4
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

1 Comment

It is not working.. I 'm getting the same result.. I 'm using ruby 1.8.7. Any way it helps me.
4

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

1 Comment

Thanks Sangeeth.. your solution is working fine but i'm waitng for more answers. since i need a better approach.
1
input.uniq{|hash| hash[:name]}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.