Рубиновый хэш, полученный из динамического ключа и значения (MIB SNMP) - PullRequest
0 голосов
/ 31 декабря 2018

Я новичок на ruby, у меня есть хеш-данные, как показано ниже.

person = {
  "PoolName.11.22.33":"pool_a",
  "PoolMemberName.11.22.33.11":"member_pool_a1",
  "PoolMemberScore.11.22.33.11":0,
  "PoolName.11.22.44":"pool_b",
  "PoolMemberName.11.22.44.11":"member_pool_b1",
  "PoolMemberName.11.22.44.12":"member_pool_b2",
  "PoolMemberScore.11.22.44.11":2,
  "PoolMemberScore.11.22.44.12":3,
  "PoolName.11.22.55":"pool_c",
  "PoolMemberName.11.22.55.11":"member_pool_c1",
  "PolMemberName.11.22.55.12":"member_pool_c2",
  "PoolMemberName.11.22.55.13":"member_pool_c3",
  "PoolMemberScore.11.22.55.11":11,
  "PoolMemberScore.11.22.55.12":22,
  "PoolMemberScore.11.22.55.13":33
}

Могу ли я получить результаты, подобные следующим:

"pool_a.member_pool_a1" : 0,
"pool_b.member_pool_b1" : 2,
"pool_b.member_pool_b2" : 3,
"pool_c.member_pool_c1" : 11,
"pool_c.member_pool_c2" : 22,
"pool_c.member_pool_c3" : 33

1 Ответ

0 голосов
/ 31 декабря 2018
person.
  slice_before { |_,v| v.is_a?(String) &&
    v.match?(/\Apool_\p{Lower}{,2}\z/) }.
  each_with_object({}) do |((_, pool), *rest),h|
    pool_str = pool + ".member_pool_"
    rest.group_by { |k,_| k[/(?:\.\d+)+\z/] }.
         each do |_,((_,s),(_,n))|
           (s,n = n,s) if n.is_a?(String)
           h[(pool_str + s[/[^_]+\z/]).to_sym] = n
         end  
  end
  #=> {:"pool_a.member_pool_a1"=>0,
  #    :"pool_b.member_pool_b1"=>2,
  #    :"pool_b.member_pool_b2"=>3,
  #    :"pool_c.member_pool_c1"=>11,
  #    :"pool_c.member_pool_c2"=>22,
  #    :"pool_c.member_pool_c3"=>33} 

Шаги следующие: 1 .

c = person.slice_before { |_,v| v.is_a?(String) &&
      v.match?(/\Apool_\p{Lower}{,2}\z/) }
  #=> #<Enumerator: #<Enumerator::Generator:0x00005d500f652950>:each> 

Мы можем увидеть значения, которые будут генерироваться этим перечислителем, преобразовав его в массив.

c.to_a
  #=> [[[:"PoolName.11.22.33", "pool_a"],
  #     [:"PoolMemberName.11.22.33.11", "member_pool_a1"],
  #     [:"PoolMemberScore.11.22.33.11", 0]],
  #    [[:"PoolName.11.22.44", "pool_b"],
  #     [:"PoolMemberName.11.22.44.11", "member_pool_b1"], 
  #     [:"PoolMemberName.11.22.44.12", "member_pool_b2"],
  #     [:"PoolMemberScore.11.22.44.11", 2],
  #     [:"PoolMemberScore.11.22.44.12", 3]],
  #    [[:"PoolName.11.22.55", "pool_c"],
  #     [:"PoolMemberName.11.22.55.11", "member_pool_c1"],
  #     [:"PolMemberName.11.22.55.12", "member_pool_c2"],
  #     [:"PoolMemberName.11.22.55.13", "member_pool_c3"],
  #     [:"PoolMemberScore.11.22.55.11", 11],
  #     [:"PoolMemberScore.11.22.55.12", 22],
  #     [:"PoolMemberScore.11.22.55.13", 33]]]

Как видно, c генерирует 3 массива, по одному для каждого из трех пулов, "a", "b" и "c".См. Enumerable # slice_before .Продолжая,

d = c.each_with_object({})
  #=> #<Enumerator: #<Enumerator:
  # #<Enumerator::Generator:0x00005d500f652950>:each>
  #   :each_with_object({})> 

d можно рассматривать как составной перечислитель , хотя у Ruby такого понятия нет.См. Enumerable # each_with_object .Первый элемент генерируется и передается в блок, а переменные блока присваиваются этому значению.

((_, pool), *rest),h = d.next
  #=> [[[:"PoolName.11.22.33", "pool_a"],
  #     [:"PoolMemberName.11.22.33.11", "member_pool_a1"], 
  #     [:"PoolMemberScore.11.22.33.11", 0]], {}]

Мы видим, что переменные блока теперь имеют следующие значения:

pool
  #=> "pool_a" 
rest
  #=> [[:"PoolMemberName.11.22.33.11", "member_pool_a1"],
  #    [:"PoolMemberScore.11.22.33.11", 0]]
h #=> {} 

Разбиение массивов на интересующие их компоненты называется «декомпозиция массива» (поиск "Разложение массива").Он также известен как неоднозначность массива .Это очень мощная и полезная техника.Обратите внимание, что _ является допустимой, но несколько особенной локальной переменной.Основная причина использования подчеркивания (или имени переменной, начинающегося с подчеркивания) заключается в информировании читателя о том, что эта переменная не используется в последующих вычислениях.Продолжая,

pool_str = pool + ".member_pool_"
  #=> "pool_a.member_pool_" 
e = rest.group_by { |k,_| k[/(?:\.\d+)+\z/] }
  #=> {".11.22.33.11"=>[
  #     [:"PoolMemberName.11.22.33.11", "member_pool_a1"],
  #     [:"PoolMemberScore.11.22.33.11", 0]]} 

См. Enumerable # group_by .Продолжая,

g = e.each
  #=> #<Enumerator:
  #    {".11.22.33.11"=>[
  #      [:"PoolMemberName.11.22.33.11", "member_pool_a1"],
  #      [:"PoolMemberScore.11.22.33.11", 0]]}:each> 

Много счетчиков, а?Опять же, первый элемент перечислителя генерируется и передается в блок, а переменным блока присваиваются значения:

p,((q,s),(r,n)) = g.next
  #=> [".11.22.33.11",
  #   [[:"PoolMemberName.11.22.33.11", "member_pool_a1"],
  #    [:"PoolMemberScore.11.22.33.11", 0]]]
p #=> ".11.22.33.11"
q #=> :"PoolMemberName.11.22.33.11"
s #=> "member_pool_a1"
r #=> :"PoolMemberScore.11.22.33.11"
n #=> 0

p, q и r не используются в вычислениях блока,По этой причине я использовал _ для всех трех из этих переменных:

each do |_,((_,s),(_,n))| ...

Эта декомпозиция массива может выглядеть чрезвычайно сложной, но на самом деле это не так.Просто сравните расположение скобок в строке, приведенной выше, с расположением скобок в возвращаемом значении g.next, показанном выше.

Теперь выполняется вычисление блока.Мы не можем быть уверены, что два элемента g.next находятся в правильном порядке (хотя здесь они есть), поэтому мы обращаем их вспять при необходимости.

(s,n = n,s) if n.is_a?(String)
  #=> nil 
s #=> "member_pool_a1" 
n #=> 0 

i = s[/[^_]+\z/]
  #=> "a1" 
j = pool_str + i
  #=> "pool_a.member_pool_a1" 
k = j.to_sym
  #=> :"pool_a.member_pool_a1" 
h[k] = n
  #=> 0 
h #=> {:"pool_a.member_pool_a1"=>0} 

Поскольку g.size #=> 1 мы закончили с g,Поэтому следующим шагом является генерация следующего элемента d (пул "b"):

((_, pool), *rest),h = d.next
  #=> [[[:"PoolName.11.22.44", "pool_b"],
  #     [:"PoolMemberName.11.22.44.11", "member_pool_b1"],
  #     [:"PoolMemberName.11.22.44.12", "member_pool_b2"],
  #     [:"PoolMemberScore.11.22.44.11", 2], 
  #     [:"PoolMemberScore.11.22.44.12", 3]],
  #    {:"pool_a.member_pool_a1"=>0}] 
pool
  #=> "pool_b"
rest
  #=> [[:"PoolMemberName.11.22.44.11", "member_pool_b1"],
  #    [:"PoolMemberName.11.22.44.12", "member_pool_b2"],
  #    [:"PoolMemberScore.11.22.44.11", 2],
  #    [:"PoolMemberScore.11.22.44.12", 3]]
h #=> {:"pool_a.member_pool_a1"=>0}

Обратите внимание, как была изменена блочная переменная h.Остальные расчеты аналогичны.

1 Опытные рубины: подробное предупреждение!

...