Answers:
使用Array#uniq
带块:
@photos = @photos.uniq { |p| p.album_id }
require 'backports'
:-)
@photos.uniq &:album_id
将uniq_by
方法添加到项目中的Array中。类似于sort_by
。所以,uniq_by
是uniq
的sort_by
是sort
。用法:
uniq_array = my_array.uniq_by {|obj| obj.id}
实现:
class Array
def uniq_by(&blk)
transforms = []
self.select do |el|
should_keep = !transforms.include?(t=blk[el])
transforms << t
should_keep
end
end
end
请注意,它返回一个新数组,而不是就地修改当前数组。我们尚未编写uniq_by!
方法,但是如果您愿意的话,它应该足够简单。
编辑:Tribalvibes指出该实现是O(n ^ 2)。更好的是(未经测试)...
class Array
def uniq_by(&blk)
transforms = {}
select do |el|
t = blk[el]
should_keep = !transforms[t]
transforms[t] = true
should_keep
end
end
end
您可以使用此技巧从数组中的多个属性元素中选择唯一的元素:
@photos = @photos.uniq { |p| [p.album_id, p.author_id] }
如果我正确地理解了您的问题,那么我将通过比较编组对象以确定是否任何属性发生变化的准hacky方法来解决此问题。以下代码末尾的注入将是一个示例:
class Foo
attr_accessor :foo, :bar, :baz
def initialize(foo,bar,baz)
@foo = foo
@bar = bar
@baz = baz
end
end
objs = [Foo.new(1,2,3),Foo.new(1,2,3),Foo.new(2,3,4)]
# find objects that are uniq with respect to attributes
objs.inject([]) do |uniqs,obj|
if uniqs.all? { |e| Marshal.dump(e) != Marshal.dump(obj) }
uniqs << obj
end
uniqs
end
Rails也有一个 #uniq_by
方法。
现在,如果您可以对属性值进行排序,则可以完成以下操作:
class A
attr_accessor :val
def initialize(v); self.val = v; end
end
objs = [1,2,6,3,7,7,8,2,8].map{|i| A.new(i)}
objs.sort_by{|a| a.val}.inject([]) do |uniqs, a|
uniqs << a if uniqs.empty? || a.val != uniqs.last.val
uniqs
end
这是针对1属性的唯一标记,但是可以通过词典顺序完成相同的操作...