Reputation: 49
How to find out elements of array having same value_entries. As code is in ruby, looking better approach.
Input
"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"
}
}
Sample Code Block:
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
Expected Output:
devicesForRaid = ['sdb','sdc']
Trial way:
using stack, push 1st element onto stack, and comparing with rest of array element.
if match found, push that element onto stack.
Sample code block completion or better code highly appreciated.
Upvotes: 1
Views: 349
Reputation: 101
How about using 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]
I think this way is easy to understand what you are doing.
Upvotes: 0
Reputation: 34328
You can do it this way (assuming block_device
is a key in your input data hash):
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]}
From this new_hash
, you can extract your required data easily.
e.g. if you want to extract the elements that has a size more than 1, you can do this:
p new_hash.select { |k,v| v.length > 1 }.values.flatten
# => [:sdb, :sdc]
Upvotes: 0
Reputation: 110675
You can do this:
input_hash[:block_device].each_with_object({}) { |(k,g),h|
h.update(g[:size]=>[k]) { |_,o,n| o+n } }
#=> {"83886080"=>[:sda], "16384"=>[:sdb, :sdc]}
This uses the form of Hash#update (aka merge!
) that employs the block:
{ |_,o,n| o+n }
to determine the values of keys that are present in both hashes being merged.
Upvotes: 2
Reputation: 304147
res = Hash.new { |h, k| h[k] = [] }
node['block_device'].each{|k, v| res[v[:size]]<<k}
gives:
=> {"83886080"=>[:sda], "16384"=>[:sdb, :sdc]}
I guess you want to look through res
for values with length of 2 or more
res.to_a.select{|k, v| v.size > 1}
Upvotes: 1