Fastest/One-liner way to remove duplicates (by key) in Ruby Array?
What's the fa开发者_如何转开发stest/one-liner way to remove duplicates in an array of objects, based on a specific key:value, or a result returned from a method?
For instance, I have 20 XML Element nodes that are all the same name, but they have different "text" values, some of which are duplicates. I would like to remove the duplicates by saying "if element.text == previous_element.text, remove it". How do I do that in Ruby in the shortest amount of code?
I've seen how to do it for simple string/integer values, but not for objects.
Here's the standard hashy way. Note the use of ||=
operator, which is a more convenient (a ||= b
) way to write a = b unless a
.
array.inject({}) do |hash,item|
hash[item.text]||=item
hash
end.values.inspect
You can do it in a single line either.
The script needs O(n) equality checks of text
strings. That's what's covered under O(n) when you see a hash.
This does it all:
Hash[*a.map{|x| [x.text, x]}].values
short? yep.
(asterisk is optional; seems to be required for 1.8.6).
For example:
a = [Thing.new('a'), Thing.new('b'), Thing.new('c'), Thing.new('c')]
=> [#<Thing a>, #<Thing b>, #<Thing c>, #<Thing c>]
Hash[a.map{|x| [x.text, x]}].values
=> [#<Thing a>, #<Thing b>, #<Thing c>]
Boring part: here's the little test class I used:
class Thing
attr_reader :text
def initialize(text)
@text = text
end
def inspect
"#<Thing #{text}>"
end
end
Use Array#uniq
with a block. In your case:
array.uniq(&:text) # => array with duplicated `text` removed
This was introduced in Ruby 1.9.2, so if using an earlier version, you can use backports
with require 'backports/1.9.2/array/uniq'
精彩评论