2012-03-02 11 views
25

Próbuję uzyskać podzbiór kluczy dla każdego skrótu w tablicy.Jak mogę filtrować tablicę skrótów, aby uzyskać tylko klucze w innej tablicy?

mieszań są faktycznie znacznie większy, ale pomyślałem, to jest łatwiejsze do zrozumienia:

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

chcę uzyskać tylko wartości id i start.

Próbowałem:

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

ale zwraca pustą tablicę.

Odpowiedz

40

ten powinien robić to, co chcesz:

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

Potencjalnie szybsze (ale nieco mniej ładny) rozwiązanie:

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

Jeśli potrzebujesz return_keys być dynamiczna:

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 

Zauważ, że w Twoim kodzie select wybiera elementy z array, ponieważ właśnie to wywołałeś, ale nie zmienia haszy zawartych w tablicy.

Jeżeli obawiasz się o wydajność, mam odwzorować wszystkich rozwiązań wymienionych tutaj (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) 
+0

dla N kluczy 'events' i klucze M w każdym mieszania i klucze P na wewnętrznej tablicy, to występuje w ** O (MNP) ** prędkości która mogłaby być niepokojąco powolnym. – tadman

+1

@tadman Zobacz zaktualizowaną odpowiedź z rozwiązaniem O (N). –

+0

@tadman Chociaż, myślę, że to naprawdę O (NP)? Nie sądzę, że jest coś szybciej. Zakładając, że P jest bardzo małe, nie powinno to jednak wpływać na złożoność czasu. –

2

Lepszym rozwiązaniem jest użycie skrótu jako indeksu zamiast robić liniowy układ lookup dla każdego klucza:

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

ja regulować, aby używać symboli jako nazw klawiszy, aby dopasować swoją definicję events.

ten można dodatkowo poprawić za pomocą return_keys jako bezpośredni kierowcy:

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 

Rezultat jest taki sam. Jeśli wyodrębniany podzbiór wydaje się być znacznie mniejszy niż oryginał, może to być najlepsze podejście.

+1

Jeśli jesteś ciekawy, przetestowałem wszystkie rozwiązania tutaj i opublikowałem wyniki w mojej odpowiedzi ':)'. –

28

Jeśli zdarzy się za pomocą szyn (lub nie przeszkadza ciągnąc w całości lub w części ActiveSupport), które następnie można użyć Hash#slice:

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

Hash#slice robi jakąś dodatkową pracę pod kołdrą, ale to chyba wystarczająco szybko, że nie zauważysz go dla małych skrótów, a jasność jest całkiem niezła.

+5

Właściwie musisz "wymagać" active_support/core_ext'', jeśli nie masz w Railsach. Rozszerzenia rdzeniowe muszą być ładowane jawnie, więc po prostu 'require 'active_support'' nie działa. (Mówię to, ponieważ ten drugi jest tym, co większość uważa za "wciągnięcie całego ActiveSupport".) –

+0

Jeśli chodzi o prędkość, zobacz moją odpowiedź dla benchmarków ':)'. –

0

Biorąc pod uwagę, że wydajność wydaje się być problemem, proponuję następujące.

Kod

require 'set' 

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

używa Hash#select, który w odróżnieniu od Enumerable#select, zwraca hash. Przekonwertowałem keeper_keys na zestaw do szybkiego wyszukiwania.

Przykłady

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] 
Powiązane problemy