Uniq by Ruby中的object属性

sut*_*tee 118 ruby arrays ruby-on-rails unique

选择数组中对于一个或多个属性唯一的对象的最优雅方法是什么?

这些对象存储在ActiveRecord中,因此使用AR的方法也可以.

张健健*_*张健健 192

使用Array#uniq带块:

@photos = @photos.uniq { |p| p.album_id }
Run Code Online (Sandbox Code Playgroud)

  • 您可以使用to_proc(http://www.ruby-doc.org/core-1.9.3/Symbol.html#method-i-to_proc)改进它:`@ photos.uniq&:album_id` (19认同)
  • 这是[ruby 1.9](http://ruby-doc.org/core-1.9.2/Array.html#method-i-uniq)及更高版本的正确答案. (5认同)
  • +1.而对于早期的红宝石,总会有"需要'后退'.":-) (2认同)

Dan*_*aft 22

uniq_by方法添加到项目中的Array.它的作用类似于sort_by.所以,uniq_byuniqsort_bysort.用法:

uniq_array = my_array.uniq_by {|obj| obj.id}
Run Code Online (Sandbox Code Playgroud)

实施:

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
Run Code Online (Sandbox Code Playgroud)

请注意,它返回一个新数组,而不是修改当前的数组.我们还没有编写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
Run Code Online (Sandbox Code Playgroud)

  • 这个答案已经过时了.Ruby> = 1.9有一个Array#uniq,其中一个块就是这样,就像在接受的答案中一样. (7认同)

mis*_*lav 17

在数据库级别上执行:

YourModel.find(:all, :group => "status")
Run Code Online (Sandbox Code Playgroud)


小智 11

您可以使用此技巧从数组中的几个属性元素中选择唯一:

@photos = @photos.uniq { |p| [p.album_id, p.author_id] }
Run Code Online (Sandbox Code Playgroud)


Ale*_*x M 6

我原本建议select在Array上使用该方法.以机智:

[1, 2, 3, 4, 5, 6, 7].select{|e| e%2 == 0} 让我们[2,4,6]回来.

但是如果你想要第一个这样的对象,请使用detect.

[1, 2, 3, 4, 5, 6, 7].detect{|e| e>3}给了我们4.

不过,我不确定你的目的是什么.


Hea*_*ead 5

我喜欢jmah使用Hash来强制执行唯一性.这里有几种皮肤猫的方法:

objs.inject({}) {|h,e| h[e.attr]=e; h}.values
Run Code Online (Sandbox Code Playgroud)

这是一个不错的1-liner,但我怀疑这可能会更快一点:

h = {}
objs.each {|e| h[e.attr]=e}
h.values
Run Code Online (Sandbox Code Playgroud)


小智 5

将Array#uniq与块一起使用:

objects.uniq {|obj| obj.attribute}
Run Code Online (Sandbox Code Playgroud)

或者更简洁的方法:

objects.uniq(&:attribute)
Run Code Online (Sandbox Code Playgroud)