Как я могу отфильтровать массив хэшей, чтобы получить только ключи в другом массиве? - PullRequest
29 голосов
/ 02 марта 2012

Я пытаюсь получить подмножество ключей для каждого хэша в массиве.

Хеши на самом деле намного больше, но я понял, что это легче понять:

[
  {
    id:2,
    start: "3:30",
    break: 30,
    num_attendees: 14
  },
  {
    id: 3,
    start: "3: 40",
    break: 40,
    num_attendees: 4
  },
  {
    id: 4,
    start: "4: 40",
    break: 10,
    num_attendees: 40
  }
]

Я хочу получить только значения id и start.

Я пытался:

return_keys = ['id','start']
return_array = events.select{|key,val|  key.to_s.in? return_keys}

, но это возвращает пустой массив.

Ответы [ 4 ]

44 голосов
/ 02 марта 2012

Это должно делать то, что вы хотите:

events.map do |hash|
  hash.select do |key, value|
    [:id, :start].include? key
  end
end

Потенциально более быстрое (но несколько менее симпатичное) решение:

events.map do |hash|
  { id: hash[:id], start: hash[:start] }
end

Если вам нужно return_keys, чтобы быть динамичным:

return_keys = [:id, :start]
events.map do |hash|
  {}.tap do |new_hash|
    return_keys.each do |key|
      new_hash[key] = hash[key]
    end
  end
end

Обратите внимание, что в вашем коде select выбирает элементы из массива , поскольку это то, что вы назвали, но не изменяет хэши, содержащиеся в массиве.

Если вы беспокоитесь о производительности, я протестировал все перечисленные здесь решения ( код ):

                user     system      total        real
amarshall 1  0.140000   0.000000   0.140000 (  0.140316)
amarshall 2  0.060000   0.000000   0.060000 (  0.066409)
amarshall 3  0.100000   0.000000   0.100000 (  0.101469)
tadman 1     0.140000   0.010000   0.150000 (  0.145489)
tadman 2     0.110000   0.000000   0.110000 (  0.111838)
mu           0.130000   0.000000   0.130000 (  0.128688)
32 голосов
/ 02 марта 2012

Если вы используете Rails (или не возражаете против использования ActiveSupport полностью или частично), вы можете использовать Hash#slice:

return_array = events.map { |h| h.slice(:id, :start) }

Hash#slice выполняет некоторую дополнительную работу под обложками, но, вероятно, она достаточно быстра, чтобы вы не заметили ее для небольших хешей, и ясность довольно хорошая.

2 голосов
/ 02 марта 2012

Лучшее решение - использовать хеш в качестве индекса вместо поиска линейного массива для каждого ключа:

events = [{id:2, start:"3:30",break:30,num_attendees:14},{id:3, start:"3:40",break:40,num_attendees:4},{id:4, start:"4:40",break:10,num_attendees:40}]

return_keys = [ :id, :start ]

# Compute a quick hash to extract the right values: { key => true }
key_index = Hash[return_keys.collect { |key| [ key, true ] }]

return_array = events.collect do |event|
  event.select do |key, value|
    key_index[key]
  end
end

# => [{:id=>2, :start=>"3:30"}, {:id=>3, :start=>"3:40"}, {:id=>4, :start=>"4:40"}]

Я настроил это, чтобы использовать символы в качестве имен ключей в соответствии с вашим определениемиз events.

Это можно еще улучшить, используя return_keys в качестве прямого драйвера:

events = [{id:2, start:"3:30",break:30,num_attendees:14},{id:3, start:"3:40",break:40,num_attendees:4},{id:4, start:"4:40",break:10,num_attendees:40}]

return_keys = [ :id, :start ]

return_array = events.collect do |event|
  Hash[
    return_keys.collect do |key|
      [ key, event[key] ]
    end
  ]
end

Результат тот же.Если извлекаемое подмножество имеет тенденцию быть намного меньше исходного, это может быть лучшим подходом.

0 голосов
/ 16 февраля 2016

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

код

require 'set'

def keep_keys(arr, keeper_keys)
  keepers = keeper_keys.to_set
  arr.map { |h| h.select { |k,_| keepers.include?(k) } }
end

Используется Hash # select , который, в отличие от Enumerable # select , возвращает хэш. Я преобразовал keeper_keys в набор для быстрого поиска.

Примеры

arr = [{ id:2, start: "3:30", break: 30 },
       { id: 3, break: 40, num_attendees: 4 },
       { break: 10, num_attendees: 40 }]

keep_keys arr, [:id, :start]
  #=> [{:id=>2, :start=>"3:30"}, {:id=>3}, {}] 
keep_keys arr, [:start, :break]
  #=> [{:start=>"3:30", :break=>30}, {:break=>40}, {:break=>10}] 
keep_keys arr, [:id, :start, :cat]
  #=> [{:id=>2, :start=>"3:30"}, {:id=>3}, {}] 
keep_keys arr, [:start]
  #=> [{:start=>"3:30"}, {}, {}] 
keep_keys arr, [:cat, :dog]
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...