如何以最快/最简单的方式基于特定键值或从方法返回的结果,移除对象数组中的重复项?
例如,我有20个XML元素节点,它们都具有相同的名称,但它们具有不同的“text”值,其中一些是重复的。我想通过说“如果element.text == previous_element.text,则将其删除”来移除重复项。在Ruby中,我该如何用最短的代码实现这个功能?
我已经知道了如何移除简单字符串/整数值的重复项,但不知道如何操作对象。
如何以最快/最简单的方式基于特定键值或从方法返回的结果,移除对象数组中的重复项?
例如,我有20个XML元素节点,它们都具有相同的名称,但它们具有不同的“text”值,其中一些是重复的。我想通过说“如果element.text == previous_element.text,则将其删除”来移除重复项。在Ruby中,我该如何用最短的代码实现这个功能?
我已经知道了如何移除简单字符串/整数值的重复项,但不知道如何操作对象。
以下是标准的哈希方式。请注意使用 ||=
运算符,它是一种更方便的(a ||= b
)方法,可以写成 a = b unless a
。
array.inject({}) do |hash,item|
hash[item.text]||=item
hash
end.values.inspect
你也可以用一行代码实现。
这个脚本需要进行 O(n) 次字符串text
的相等性检查。 当你看到哈希表时,这就是所覆盖的范围。
这就是全部:
Hash[*a.map{|x| [x.text, x]}].values
短?没错。
(星号是可选的;似乎在1.8.6中是必需的)。
例如:
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>]
无聊的部分:这是我使用的小测试类:
class Thing
attr_reader :text
def initialize(text)
@text = text
end
def inspect
"#<Thing #{text}>"
end
end
ary.map{|x| x.last}
和 ary.map(&:last)
是等价的。 - Petera.map{|x| [x.text, x]}
?我已经仔细检查过了,看起来没问题... - Peter使用带有块的 Array#uniq
。在您的情况下:
array.uniq(&:text) # => array with duplicated `text` removed
这个功能是在Ruby 1.9.2中引入的,所以如果使用早期版本,您可以使用backports
,并使用require 'backports/1.9.2/array/uniq'