基于键值对,Ruby如何从数组中删除重复项

7

我有一个音乐曲目数组,由于在多个专辑中发布,同一首歌可能会多次出现在该数组中。我正在尝试从数组中删除它们,以便列表中只显示真正的唯一项。

哈希表看起来像这样:

"tracks" => [
    [0] {
        "id" => 1,
        "Title" => "Intergalactic",
        "ArtistName" => "Beastie Boys"
    },
    [1] {
        "id" => 2,
        "Title" => "Intergalactic",
        "ArtistName" => "Beastie Boys"
    }
]

我需要一种方法来根据Title键删除重复项。有什么办法可以做到这一点吗?

3个回答

11
如果你正在使用ActiveSupport,你可以使用uniq_by,像这样:
tracks.uniq_by {|track| track["title"]}

如果没有提供,你可以轻松地自行实现。 查看这里。

# File activesupport/lib/active_support/core_ext/array/uniq_by.rb, line 6
  def uniq_by
    hash, array = {}, []
    each { |i| hash[yield(i)] ||= (array << i) }
    array
  end

非常感谢您的帮助!!!每天我进行Ruby开发,我都会变得更加快乐/优秀。 - dennismonsewicz

10

在1.9版本中,Array#uniq!方法可以接受一个块参数,因此如果你有一个哈希表h,那么可以这样使用:

h['tracks'].uniq! { |x| x['Title'] }

如果你使用的是1.8版本,你可以通过以下方式模拟:

h['tracks'] = h['tracks'].group_by { |x| x['Title'] }.values.map(&:first)

我假设您想要就地修改它。


啊!我不知道它在1.9里,谢谢提醒。显然,如果你正在使用1.9,这就是正确的答案。 - DuoSRX
@DuoSRX:它似乎并不是很出名,而且文档也不是很详细(你必须从示例中推断)。一个正确的答案就是能完成工作的答案 :) - mu is too short
如果您需要通过多个值使条目唯一怎么办?我有同样的情况,但需要检查标题、艺术家和作曲家是否相同。使用 uniq 块时,我只能使用一个值! - kakubei
@kakubei:%w[a b] == %w[a b]是什么意思?我怀疑这就是你问题的解决方案。 - mu is too short

0

虽然其他方法是正确的,但我会加入一些额外的糖果,这些糖果我在 Stack Overflow 上找到了。

使用 Symbol 的这个扩展:

class Symbol
  def with(*args, &block)
    ->(caller, *rest) { caller.send(self, *rest, *args, &block) }
  end
end

现在你可以使用 foo_array.each &:update_bar.with("baz") 代替简单的迭代块 foo_array.each{ |foo| foo.update_bar("baz") }

类似于你可能会写 maybe_nil.try(:[], "key")...

foo_array.uniq{ |foo| foo["key"] } 现在与 foo_array.uniq &:[]["key"] 相同。

foo_array.uniq(&:[].with("key"))

我希望这能有所帮助。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接