Ответ 1
В Ruby 1.9 попробуйте выполнить
a.uniq! {|e| e[:color] }
Я чувствую, что это может быть улучшено (общее чувство в рубине). Я пытаюсь uniq массив хэшей на основе значения. В этом примере я хочу цвета элементов. Мосс и снег - обманщики.
# remove unique array of hashes based on a hash value
a = [
{ :color => "blue", :name => "water" },
{ :color => "red", :name => "fire" },
{ :color => "white", :name => "wind" },
{ :color => "green", :name => "earth" },
{ :color => "green", :name => "moss" },
{ :color => "white", :name => "snow" }
]
# remove moss and snow
uniques = []
a.each_with_index do |r, i|
colors = uniques.collect {|e| e[:color]}
if !colors.include? r[:color]
uniques.push r
else
a[i] = nil
end
end
a.compact!
puts a
Откроется
{:color=>"blue", :name=>"water"}
{:color=>"red", :name=>"fire"}
{:color=>"white", :name=>"wind"}
{:color=>"green", :name=>"earth"}
Что является "правильным", однако я чувствую, что это чрезмерно. Мой опыт с .map.inject ограничен, и эти передовые методы ускользают от меня. Если кто-то может изменить это, это может помочь мне понять еще одну технику.
В Ruby 1.9 попробуйте выполнить
a.uniq! {|e| e[:color] }
Я бы пошел с методами Array reject
или select
:
require 'pp'
a = [
{ :color => "blue", :name => "water" },
{ :color => "red", :name => "fire" },
{ :color => "white", :name => "wind" },
{ :color => "green", :name => "earth" },
{ :color => "green", :name => "moss" },
{ :color => "white", :name => "snow" }
]
pp a.reject{ |h| %w[moss snow].include?( h[:name]) }
# >> [{:color=>"blue", :name=>"water"},
# >> {:color=>"red", :name=>"fire"},
# >> {:color=>"white", :name=>"wind"},
# >> {:color=>"green", :name=>"earth"}]
В качестве альтернативы вы можете быть уверены в этом, а select
те, которые вы хотите сохранить:
pp a.select{ |h| %w[water fire wind earth].include?( h[:name] ) }
# >> [{:color=>"blue", :name=>"water"},
# >> {:color=>"red", :name=>"fire"},
# >> {:color=>"white", :name=>"wind"},
# >> {:color=>"green", :name=>"earth"}]
На самом деле вы не имеете дело с хэшами, это массив, который содержит хеши, поэтому не позволяйте им путать вас. Методы массива, такие как reject
и select
, являются основными методами фильтрации нежелательных или сохраняемых элементов.
В вашем примере кода вы теряете из виду свою цель: вам нужны элементы, отбрасывающие "мох" и "снег", которые не являются элементами. Отфильтруйте неэлементы, и вы останетесь с правильными/реальными элементами хэшей. Оттуда вы можете извлечь правильные цвета.
Еще одна проблема, с которой нужно следить за использованием uniq
, является позиционным, другими словами, она ищет первое уникальное значение и отклоняет последующие. Это не было очевидно в вашем коде, потому что ваш массив был последовательно того же порядка, что и вы тестировали. Если вы перетасовали заказ, хотя...:
2.times do
pp a.shuffle.uniq{ |h| h[:color] }
end
Pass # 1...
# [{:color=>"red", :name=>"fire"},
# {:color=>"white", :name=>"wind"},
# {:color=>"green", :name=>"moss"},
# {:color=>"blue", :name=>"water"}]
Pass # 2...
# [{:color=>"green", :name=>"earth"},
# {:color=>"blue", :name=>"water"},
# {:color=>"red", :name=>"fire"},
# {:color=>"white", :name=>"snow"}]
Вдруг мы видим, что и "мох", и "снег" проникают в результаты, хотя цвета уникальны. Это тонкая добыча, на которую вы должны следить.