2016-07-13 10 views
0

Ich brauche eine Ruby-Funktion, die einen Hash als Eingabe (Schlüssel sind Symbole und Werte sind Arrays of Numerics) und gibt die Liste der Schlüssel zurück, deren zugeordnete Arrays den gleichen ersten Wert haben. HierRuby 'group_by'-ähnliche Methode für Hash

ist ein Beispiel:

h={ 
    :k1 => [2,3,5,12], 
    :k2 => [9,5,6,10], 
    :k3 => [2,4,5, 8], 
} 

f(h) # should return [[:k1,:k3]] 

... weil 2 erscheint als dem gleichen Wert in den beiden Feldern zugeordnet : k1 und : k3. Das return-Objekt ist ein array-Array (weil mehrere Schlüsselgruppen die gleichen ersten Array-Werte haben können).

Bisher habe ich nur die Arrays selbst gruppiert:

def f(h) 
    h.values.group_by{|ary| ary.first} 
end 

# returns {2=>[[2, 3, 5, 12], [2, 4, 5, 8]], 9=>[[9, 5, 6, 10]]} 

Antwort

2

Warum nicht einfach group_by als Titel Ihrer Frage verwenden, schlägt vor:

h2 = h.group_by { |k, v| v.first } 

Dieses Sie so etwas wie dieses gibt:

{2=>[[:k1, [2, 3, 5, 12]], [:k3, [2, 4, 5, 8]]], 9=>[[:k2, [9, 5, 6, 10]]]} 

Sie können dann zur Weiterverarbeitung verwenden diese. Willst du nur die Schlüssel?

h3 = h2.values.map { |v| v.map(&:first) } 

Nur diejenigen mit mehr als einem Schlüssel wollen?

h3.reject { |v| v.length < 2 } 

Oder auf h2 direkt:

h2.reject { |k, v| v.length < 2 } 
+0

Ich war einfach diese Methode für Hash nicht bewusst. Danke ! – JCLL

0

Vielleicht können Sie so etwas wie dieses

def get_same_first_value(h) 
    h.each_with_object(Hash.new { |k, v| k[v] = [] }) do |(sym, arr), exp| 
    exp[arr.min] << sym 
    end.select { |k, v| v.size != 1 }.values 
end 

h = { 
    :k1 => [2, 3, 5, 12], 
    :k2 => [9, 5, 6, 10], 
    :k3 => [2, 4, 5, 8], 
} 

get_same_first_value(h) 
# => [[:k1, :k3]] 
1

ich mit dieser hässlichen Sache kam verwenden:

h.inject({}) do |memo, (key, array)| 
    memo[array[0]] ||= [] 
    memo[array[0]] << key 
    memo 
end.detect do |(key, values)| 
    values.size > 1 
end.last 

Im Wesentlichen wird der Hash in der folgenden Form neu zugeordnet:

{first_item_in_array => keys_that_contain_it} 

Oder in unserem Fall:

{2=>[:k1, :k3]} 

Dann es erkennt nur das erste Paar, das mehr als ein Spiel hat und gibt es:

[:k1, :k3] 

Hoffnung, das hilft!