1

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.

4 Answers 4

2

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.

Sign up to request clarification or add additional context in comments.

7 Comments

Isn't o+n going to create a new array each time? Can you use o<<n.first instead?
@John, yes, though each will be marked for garbage collection as soon as it's replaced by the next one.
If we're talking array allocation, each_with_object already allocates one for each enumerated key, value pair. To be super optimized, it could use each_pair and a pre-instantiated object instead.
@Drenmi, That's still just extra O(n) complexity. The quadratic is potentially more serious - especially if it is widely used.
@CarySwoveland, It's definitely quadratic in 2.2.1 according to a quick test I just did comparing { |_,o,n| o+n } to { |_,o,n| o<<n.first}. So something to keep in mind when using this pattern with mutables
|
1
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}

1 Comment

I think, {"83886080"=>[:sda], "16384"=>[:sdb, :sdc]}.to_a.select{|k, v| v.size > 1} will give the output: [["16384", [:sdb, :sdc]]] which is slightly off from the expected output. You may want to do something like this: {"83886080"=>[:sda], "16384"=>[:sdb, :sdc]}.select{|k, v| v.size > 1}.values.flatten.
0

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]

Comments

0

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.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.