#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"))
Я надеюсь, что это поможет