2

I have an array of hashes:

[{ item_id: 1, relationship_1: 1, relationship_2: 1, value: 'go' },
 { item_id: 2, relationship_1: 2, relationship_2: 2, value: 'stop' },
 { item_id: 3, relationship_1: 2, relationship_2: 1, value: 'stop' }, #remove
 { item_id: 4, relationship_1: 3, relationship_2: 1, value: 'go' },
 { item_id: 5, relationship_1: 1, relationship_2: 2, value: 'go' }] #remove

I want the lines commented to be removed. The need is to remove all lines that have relationship_1 and value in common. The only way I can think of is:

items.each do |i|
  items.each do |k|
    if i.item_id != k.item_id and i.relationship_1 == k.relationship_1 and i.value == k.value
      items.remove(k)
    end
  end
end

This is not working as intended. What is the most "Ruby" way to remove those offending items?

Phrogz
  • 296,393
  • 112
  • 651
  • 745
Jeremy B.
  • 9,168
  • 3
  • 45
  • 57
  • How do you define "similar"? Also please read about [the difference between `&&`/`||` & `and`/`or` in Ruby](http://devblog.avdi.org/2010/08/02/using-and-and-or-in-ruby/). They are **not** the same. – Andrew Marshall Mar 13 '12 at 17:52
  • In this case I mean by having a specific set of values that are equal, there wasn't really a better way to word it in the title. – Jeremy B. Mar 13 '12 at 18:03

3 Answers3

3

group_by{ |item| [item.relationship_1, item.value] }.values.map(&:first)?

UPDATE

Oops, it was a hash:

group_by{ |item| [item[:relationship_1], item[:value]] }.values.map(&:first)

or

group_by{ |item| item.values_at(:relationship_1, :value) }.values.map(&:first)

Victor Moroz
  • 9,167
  • 1
  • 19
  • 23
3

Unfortunately, uniq_by isn't available in Ruby core. Pull it in with require 'activesupport'.

items.uniq_by {|h| [h[:replationship_1], h[:value]] }

Edit: As noted by @mu below, Ruby 1.9's uniq also works:

items.uniq{|h| [h[:replationship_1], h[:value]] }
Phrogz
  • 296,393
  • 112
  • 651
  • 745
Austin Taylor
  • 5,437
  • 1
  • 23
  • 29
  • Fortunately I am using Rails 3. I didn't want extra requirements if it didn't need them. Seeing as these objects are ActiveResource objects, this will work great. Thank you. – Jeremy B. Mar 13 '12 at 18:04
  • 1
    [The implementation of `uniq_by`](https://github.com/rails/rails/blob/7194b393a611727fb36e8f586910e75db1bae746/activesupport/lib/active_support/core_ext/array/uniq_by.rb#L6) is (i think) actually rather clever and worthy of inspection. – Andrew Marshall Mar 13 '12 at 18:07
  • 3
    Nonsense, sort of. 1.9's [`Array#uniq`](http://ruby-doc.org/core-1.9.3/Array.html#method-i-uniq) can take a block and `Array#uniq` certainly is in the core. – mu is too short Mar 13 '12 at 18:08
  • @muistooshort I thought it did, but I was surprised when I looked at the docs and the method's signature doesn't state it takes a block so I didn't even bother to look at the examples. (Thankfully this doc issue is fixed in [Ruby trunk](https://github.com/ruby/ruby/blob/trunk/array.c#L3608).) – Andrew Marshall Mar 13 '12 at 18:22
  • @muistooshort Good call. Didn't know that. – Austin Taylor Mar 13 '12 at 18:41
  • @AndrewMarshall (and Austin): To be fair, the documentation isn't exactly clear and explicit, nice to see that it is being fixed. – mu is too short Mar 14 '12 at 00:22
1

Maybe this function will help. I found it mentioned in this thread, and if I am not wrong it is part of latest ruby on rails.

a.uniq_by {|t| [t.replationship_1, t.value]}
Community
  • 1
  • 1
Boris Strandjev
  • 46,145
  • 15
  • 108
  • 135