39 Stimmen

Wie kann ich ein Array von Hashes filtern, um nur die Schlüssel in einem anderen Array zu erhalten?

Ich versuche, eine Teilmenge der Schlüssel für jeden Hash in einem Array zu erhalten.

Die Hashes sind in Wirklichkeit viel größer, aber ich dachte mir, das ist leichter zu verstehen:

[
  {
    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
  }
]

Ich möchte nur die id y start Werte.

Ich habe es versucht:

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

aber dies gibt ein leeres Array zurück.

53voto

Andrew Marshall Punkte 92252

Dies sollte das bewirken, was Sie wollen:

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

Potenziell schnellere (aber etwas weniger schöne) Lösung:

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

Wenn Sie return_keys dynamisch zu sein:

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

Beachten Sie, dass in Ihrem Code, select wählt Elemente aus dem Array auf, da Sie es aufgerufen haben, aber die im Array enthaltenen Hashes werden nicht geändert.

Wenn Sie sich Sorgen um die Leistung machen, habe ich alle hier aufgeführten Lösungen einem Benchmarking unterzogen ( Code ):

                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)

37voto

mu is too short Punkte 411765

Wenn Sie zufällig Rails verwenden (oder es Ihnen nichts ausmacht, ActiveSupport ganz oder teilweise einzubinden), können Sie Hash#slice :

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

Hash#slice macht etwas zusätzliche Arbeit unter der Haube, aber es ist wahrscheinlich schnell genug, dass Sie es für kleine Hashes nicht bemerken werden und die Klarheit ist ziemlich schön.

2voto

tadman Punkte 200181

Eine bessere Lösung ist es, einen Hash als Index zu verwenden, anstatt ein lineares Array für jeden Schlüssel zu suchen:

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"}]

Ich habe dies angepasst, um Symbole als Schlüsselnamen zu verwenden, um Ihrer Definition von events .

Dies kann noch verbessert werden, indem man die return_keys als direkter Treiber:

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

Das Ergebnis ist das gleiche. Wenn die Teilmenge, die Sie extrahieren, tendenziell viel kleiner ist als das Original, könnte dies die beste Vorgehensweise sein.

1voto

Cary Swoveland Punkte 100335

In Anbetracht der Tatsache, dass die Effizienz ein Anliegen zu sein scheint, würde ich Folgendes vorschlagen.

Code

require 'set'

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

Diese verwendet Raute#Auswahl die im Gegensatz zu Aufzählbar#Auswählen gibt einen Hashwert zurück. Ich habe konvertiert keeper_keys zu einem Set für schnelles Nachschlagen.

Beispiele

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]

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X