2015-10-19 27 views
1

如何找出具有相同value_entries的數組的元素。由於代碼是紅寶石,看起來更好的方法。從紅寶石中返回具有相同值的數組的鍵

輸入

"block_device": { 
    "sda": { 
    "size": "83886080", 
    "removable": "0", 
    "model": "VBOX HARDDISK", 
    "rev": "1.0", 
    "state": "running", 
    "timeout": "30", 
    "vendor": "ATA", 
    "rotational": "1" 
    }, 
    "sdb": { 
    "size": "16384", 
    "removable": "0", 
    "model": "VBOX HARDDISK", 
    "rev": "1.0", 
    "state": "running", 
    "timeout": "30", 
    "vendor": "ATA", 
    "rotational": "1" 
    }, 
    "sdc": { 
    "size": "16384", 
    "removable": "0", 
    "model": "VBOX HARDDISK", 
    "rev": "1.0", 
    "state": "running", 
    "timeout": "30", 
    "vendor": "ATA", 
    "rotational": "1" 
    } 
} 

示例代碼塊:

devicesForRaid = [] 
deviceHolder = [] 
node['block_device'].each do |deviceName,deviceProperty| 
    deviceHolder.push(deviceName,deviceProperty['size'])  #['sda'=>'83886080','sdb'=>'16384','sdc'=>'16384'] 
end 

deviceHolder.each do | deviceName,deviceSize| 

    # how to get deviceName who all having same size 

    if(deviceSize_match_found){ 
     devicesForRaid.push(deviceName) 
    } 
end 

預期輸出:

devicesForRaid = ['sdb','sdc'] 

試驗方法:

使用棧, 推第一元件入堆棧,並與陣元的其餘部分相比較。

如果找到匹配項,將該元素推入堆棧。

示例代碼塊完成或更好的代碼高度讚賞。

回答

1
res = Hash.new { |h, k| h[k] = [] } 
node['block_device'].each{|k, v| res[v[:size]]<<k} 

給出:

=> {"83886080"=>[:sda], "16384"=>[:sdb, :sdc]} 

我想你想通過res尋找值與2個或更多

res.to_a.select{|k, v| v.size > 1} 
+0

我覺得'{「83886080」=> [:sda],「16384」=> [:sdb,:sdc]}。to_a.select {| k,v | v.size> 1}'會輸出:[[[「16384」,[:sdb,:sdc]]]',它與預期的輸出略有偏差。你可能想要做這樣的事情:'{「83886080」=> [:sda],「16384」=> [:sdb,:sdc]}選擇{| k,v | v.size> 1} .values。flatten'。 –

0

你可以做這樣的長度(假設block_device是輸入數據散列中的一個鍵):

hash = input_data[:block_device] 
new_hash = Hash.new{ |h, k| h[k] = [] } 
hash.each do |k, v| 
    new_hash[v[:size]] << k 
end 
p new_hash 
# => {"83886080"=>[:sda], "16384"=>[:sdb, :sdc]} 

從這new_hash,你可以很容易地提取您所需的數據。

例如如果要提取具有規模超過1的元素,你可以這樣做:

p new_hash.select { |k,v| v.length > 1 }.values.flatten 
# => [:sdb, :sdc] 
2

你可以這樣做:

input_hash[:block_device].each_with_object({}) { |(k,g),h| 
    h.update(g[:size]=>[k]) { |_,o,n| o+n } } 
    #=> {"83886080"=>[:sda], "16384"=>[:sdb, :sdc]} 

它使用的Hash#update(又名merge!)的形式採用該塊:

{ |_,o,n| o+n } 

確定兩個散列中存在的鍵的值被合併。

+0

「o + n」每次都不會創建一個新的數組嗎?你可以用'o << n.first'來代替嗎? –

+0

@John,是的,雖然每一個都會被標記爲垃圾收集,只要它被下一個垃圾收集器取代。 –

+0

當然,但它使最差的情況下複雜性二次方。在枚舉卷時可能不顯着,儘管 –

0

如何使用group_by

node[:block_device] 
    .group_by {|device, attributes| attributes[:size] } 
    .map {|size, devices| devices.size > 1 ? devices.map(&:first) : nil } 
    .compact 
    .flatten 
=> [:sdb, :sdc] 

我認爲這種方式很容易理解你在做什麼。