Ruby удаление дубликатов из массива на основе ключа => значение

#ruby #array-unique

#ruby #массив-уникальный

Вопрос:

У меня есть массив музыкальных треков, и в этом массиве одна и та же песня может отображаться несколько раз из-за того, что она выпущена на нескольких альбомах. Я пытаюсь удалить их из массива, чтобы в списке отображались только истинные уникальные объекты.

Хэш выглядит примерно так:

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

Мне нужен способ удаления дубликатов на основе Title ключа. В любом случае, как это сделать?

Ответ №1:

Если вы используете 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
  

Комментарии:

1. Большое спасибо за помощь!!!! Каждый день, когда я занимаюсь разработкой Ruby, я начинаю становиться счастливее / лучше

Ответ №2:

Array#uniq! Метод в 1.9 принимает блок, поэтому, если ваш хэш h равен:

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

Если вы находитесь в версии 1.8, вы можете подделать это с помощью:

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

Я предполагаю, что вы хотите изменить его на месте.

Комментарии:

1. Ах! Я не знал, что это было в 1.9, спасибо за совет. Очевидно, что если вы используете 1.9, это правильный ответ.

2. @DuoSRX: кажется, это не так хорошо известно, и это не совсем хорошо документировано (вы должны сделать вывод из примеров). Правильный ответ — это тот, который выполняет работу 🙂

3. Что делать, если вам нужно, чтобы запись была уникальной более чем на одно значение? У меня такая же ситуация, но нужно проверить, что название, исполнитель и композитор совпадают. С uniq блоком я могу использовать только одно значение!

4. @kakubei: Что такое %w[a b] == %w[a b] ? Я подозреваю, что это решение вашей проблемы.

Ответ №3:

Хотя другие методы верны, я добавлю немного дополнительного сахара, который я нашел в другом месте на SO.

Использование этого расширения символа:

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

Вместо написания простых итеративных блоков, таких как

foo_array.each{ |foo| foo.update_bar("baz") } теперь вы можете использовать

foo_array.each amp;:update_bar.with("baz")

Аналогично тому, как вы могли бы написать maybe_nil.try(:[], "key")

foo_array.uniq{ |foo| foo["key"] } теперь идентично

foo_array.uniq(amp;:[].with("key"))

Я надеюсь, что это поможет