Уникальный по массиву хэшей, основанный на значении - PullRequest
34 голосов
/ 30 января 2011

Я чувствую, что это можно улучшить (обычное чувство в рубине). Я пытаюсь 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 ограничен, и эти передовые методы ускользают от меня. Если бы кто-то мог повторно учесть это, это могло бы помочь мне понять другую краткую технику.

Ответы [ 3 ]

76 голосов
/ 30 января 2011

В Ruby 1.9 попробуйте следующее

a.uniq! {|e| e[:color] }
6 голосов
/ 30 января 2011

Я бы выбрал методы массива 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"}]

Внезапномы видим, что и «мох», и «снег» подкрадываются к результатам, хотя цвета уникальны.Это тонкие хитрости, которые вы должны остерегаться.

1 голос
/ 25 апреля 2018

Для тех, кто хочет еще более короткий вариант правильного ответа от Стива Вильгельма ,

BEWARE

a.uniq!(&:color)

НЕ РАБОТАЕТ для массива хэшей, как и

a[1].color

тоже не сработает.

Для получения дополнительной информации об операторе & прочитайте эту ссылку или комментарии к этому вопросу , которые в свою очередь содержат множество ссылок на ресурсы.

С другой стороны, вы можете получить метод Symbol # to_proc, работающий с использованием лямбд, как объясняется здесь , хотя это может быть просто усложняющим делом и, конечно, не будет более короткой версией правильного ответ. Тем не менее, это очень интересные знания.

Спасибо mukesh-kumar-gupta за хедз-ап

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...