简体   繁体   中英

Puppet: Deep merge of an array into a Hash

I have a nested array in puppet

$rules = [ [service1, rule1], [service1, rule2], [service2, rule3], [service3, rule4] ]

Which I need to convert to the following hash

$rules_hash = {
  'service1' => ['rule1', 'rule2'],
  'service2' => ['rule3'],
  'service3' => ['rule4'],
}

I tried using the built-in Hash() function but it is not an option since when there are duplicate keys it returns only the last instance of that key, leaving me with an incomplete hash of only one value per key.

I have also tried using reduce() to iterate the array and create a string "rule1 rule2" for the values with a common key, however using reduce() the nested array gets flattened and it becomes impossible to differentiate between the key and value of the hash I want to create without specifically declaring what element of the array should be a key (which becomes unfeasible if the array has a lot of different keys).

There are multiple ways to do it, but this one is pretty clean. It starts out by using the built-in group_by function to do the heavy lifting: this gets from an array to a hash in which the keys are the ones you want, but the values are arrays of the original arrays. For example, given...

 $rules = [ [service1, rule1], [service1, rule2], [service2, rule3], [service3, rule4] ]

... this...

$rules.group_by |$rule| { $rule[0] }

... groups by the first element of each of the member arrays to yield this hash:

{
  service1 => [[service1, rule1], [service1, rule2]],
  service2 => [[service2, rule3]],
  service3 => [[service3, rule4]]
}

. You will recognize that that's related to what you were after, but not quite there. However, the values in the resulting hash are well suited to be converted to the wanted ones by application of the map() function:

[[service1, rule1], [service1, rule2]].map |$sr| { $sr[1] }
# yields [ rule1, rule2 ]

That can be applied to the intermediate hash on a per-element basis by use of the reduce() function in conjunction with Puppet's built in hash-merging operator ( + ). Overall, that might look something like this:

$rules = [ [service1, rule1], [service1, rule2], [service2, rule3], [service3, rule4] ]

$rules_hash = $rules.group_by |$rule| { $rule[0] } .reduce({}) |$memo, $entry| {
  $memo + { $entry[0] => $entry[1].map |$rule| { $rule[1] } }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM