2012-03-10 20 views
24

यह प्रश्न this question के विपरीत है।एक नेस्टेड हैश को एक फ्लैट हैश में परिवर्तित करना

तरह

{ 
    :a => { 
     :b => {:c => 1, :d => 2}, 
     :e => 3, 
    }, 
    :f => 4, 
} 

एक नेस्टेड हैश क्या सबसे अच्छा तरीका है एक फ्लैट हैश में तरह

{ 
    [:a, :b, :c] => 1, 
    [:a, :b, :d] => 2, 
    [:a, :e] => 3, 
    [:f] => 4, 
} 
+3

तो क्या आप चाबियों की एक सरणी चाहते हैं जिससे मूल्य बढ़ जाए? – Linuxios

उत्तर

15

एक और तरीका है:

def flat_hash(h,f=[],g={}) 
    return g.update({ f=>h }) unless h.is_a? Hash 
    h.each { |k,r| flat_hash(r,f+[k],g) } 
    g 
end 

h = { :a => { :b => { :c => 1, 
         :d => 2 }, 
       :e => 3 }, 
     :f => 4 } 

flat_hash(h) #=> {[:a, :b, :c]=>1, [:a, :b, :d]=>2, [:a, :e]=>3, [:f]=>4} 
+0

यह बहुत तेज़ है। – sawa

+0

मुझे पता है रूबी बॉक्स के बाहर टीसीओ का जरूरी समर्थन नहीं करता है, लेकिन अगर आपने यहां 'जी' वापस नहीं किया है, तो क्या यह पूंछ-कॉल अनुकूलित होगा? – rusty

+0

मैंने "tail-call अनुकूलित" शब्द सुना है लेकिन मुझे नहीं पता कि इसका क्या अर्थ है। शायद एक कंप्यूटर वैज्ञानिक आपके प्रश्न का उत्तर दे सकता है। –

5

यह कन्वर्ट करने के लिए आप सबसे अच्छा रास्ता देने के लिए एक प्रयास यह नहीं है को देखते हुए ऐसा करो, लेकिन यह एक तरीका है: पी

def flatten(hash) 
    return {[] => hash} if !hash.is_a?(Hash) 
    map = {} 
    hash.each_pair do |key1, value1| 
    flatten(value1).each_pair do |key2, value2| 
     map[[key1] + key2] = value2 
    end 
    end 
    return map 
end 

यह आपके लिए काम करता है उदाहरण के लिए, इस परिणाम का उत्पादन:

{[:a, :b, :c]=>1, [:a, :b, :d]=>2, [:a, :e]=>3, [:f]=>4} 

यह परिणाम उत्पन्न नहीं कर सकता है यदि आप खाली हैंश होने पर उम्मीद करते हैं।

15

बहुत मासै Mittmann के समाधान

def flat_hash(h, k = []) 
    new_hash = {} 
    h.each_pair do |key, val| 
    if val.is_a?(Hash) 
     new_hash.merge!(flat_hash(val, k + [key])) 
    else 
     new_hash[k + [key]] = val 
    end 
    end 
    new_hash 
end 

संपादित करने के लिए इसी तरह की: भव्यता के लिए पुनर्स्थापन। लगभग तेज़ होना चाहिए।

def flat_hash(hash, k = []) 
    return {k => hash} unless hash.is_a?(Hash) 
    hash.inject({}){ |h, v| h.merge! flat_hash(v[-1], k + [v[0]]) } 
end 
+0

यह एक सबसे तेज़ दौड़ गया। धन्यवाद। – sawa

+1

@sawa: बस भविष्य के लिए एक टिप: यदि आप एक तेज समाधान चाहते हैं, तो अगली बार इस प्रश्न में इसका उल्लेख करें। आमतौर पर पाइथन या रूबी जैसे गतिशील भाषाओं में मुख्य मानदंड गठबंधन और एकता है। यदि आप विशेष रूप से प्रदर्शन के लिए भी पूछते हैं, तो आप अधिक बेहतर अनुकूल उत्तर प्राप्त कर सकते हैं :) –

+1

@sawa: लालित्य के लिए refactored। – Kyle

8

मेरे प्रयास:

def flatten_hash(h) 
    return { [] => h } unless h.is_a?(Hash) 
    Hash[h.map { |a,v1| flatten_hash(v1).map { |b,v2| [[a] + b, v2] } }.flatten(1)] 
end 

बुरा चर नाम के लिए क्षमा करें, एक पंक्ति में फिट करने के लिए किया था।

3

एक कार्यात्मक दृष्टिकोण (एक वैकल्पिक कार्यान्वयन के लिए history देखें):

def recursive_flatten(hash) 
    hash.flat_map do |key, value| 
    if value.is_a?(Hash) 
     recursive_flatten(value).map { |ks, v| [[key] + ks, v] } 
    else 
     [[[key], value]] 
    end 
    end.to_h 
end 
1

@ कैरी-swoveland तरीका से प्रेरित होकर, लेकिन हैश कक्षा में:

class Hash 
    def deep_flatten(previous_key=[]) 
    flat_hash = {} 
    self.each do |key, value| 
     next_key = previous_key+[key] 
     flat_hash.update(value.is_a?(Hash) ? value.deep_flatten(next_key) : {next_key=>value}) 
    end 
    return flat_hash 
    end 
end 

h = { :a => { :b => { :c => 1, :d => 2 }, :e => 3 }, :f => 4 } 

h.deep_flatten #=> {[:a, :b, :c]=>1, [:a, :b, :d]=>2, [:a, :e]=>3, [:f]=>4} 
0

DeepEnumerable का उपयोग कर एक घोषणात्मक समाधान:

require 'deep_enumerable' 

h = { :a => { :b => { :c => 1, :d => 2 }, :e => 3 }, :f => 4 } 

h.deep_each.map do |k, v| 
    [DeepEnumerable.deep_key_to_array(k), v] 
end.to_h 

या, जो उन लोगों के बिंदु से मुक्त शैली

h.deep_each.to_h.shallow_map_keys(&DeepEnumerable.method(:deep_key_to_array)) 
1

सरणी समर्थन/पठनीय नाम/गति/stringified परिणाम चाबी के लिए कोई अद्यतन पसंद करते हैं के लिए

def flat_hash(input, base = nil, all = {}) 
    if input.is_a?(Array) 
    input = input.each_with_index.to_a.each(&:reverse!) 
    end 

    if input.is_a?(Hash) || input.is_a?(Array) 
    input.each do |k, v| 
     flat_hash(v, base ? "#{base}.#{k}" : k, all) 
    end 
    else 
    all[base] = input 
    end 

    all 
end 
संबंधित मुद्दे