Объединение хэшей

Проблема

Требуется создать новый хэш, содержащий элементы двух существующих хэшей.

Решение

Интерпретируйте хэши как списки и объедините их так, как это делается со списками:
%merged = (%A, %B);
Для экономии памяти можно организовать перебор элементов и построить новый хэш следующим образом:
%merged = ();
while ( ($k, $v) = each(%A) ) {
  $merged{$k} = $v;
}
while ( ($k, $v) = each(%B) ) {
  $merged{$k} = $v;
}

Комментарий

В первом варианте используется списковая эквивалентность, о которой говорилось во введении.
(%А, %В) интерпретируется как список пар «ключ/значение». Когда он присваивается объединенному хэшу %merged, Perl преобразует список пар снова в хэш. Рассмотрим, как эта методика реализуется на практике:
%drink_color = ( Galliano => "yellow",
"Mai Tai" => "blue"  );
%ingested_colors = (%drink_color, %food_color);
Ключи обоих входных хэшей присутствуют в выходном не более одного раза. Если в хэшах найдутся совпадающие ключи, в итоговый хэш включается тот ключ, который встретился последним.
Прямое присваивание компактно и наглядно, но при больших размерах хэшей оно приводит к большим расходам памяти. Это связано с тем, что перед выполнением присваивания итоговому хэшу Perl разворачивает оба хэша во временный список. Пошаговое объединение с помощью each, показанное ниже, избавит вас от этих затрат. Заодно вы сможете решить, как поступать с совпадающими ключами.
С применением each первый фрагмент записывается следующим образом:
%drink_color = (Galliano => "yellow",
                "Mai Tai" -> "blue" );
%substance_color = ();
while (($k, $v) = each %food_color) {
  $substance_color{$k} = $v;
}
while (($k, $v) = each %drink_color) {
  $substance_color{$k} = $v;
}
Обратите внимание на повторяющийся код присваивания в циклах while. Проблема решается так:
foreach $substanceref (\%food_color, \%drink_color ) {
  while (($k, $v) = each %substanceref) {
    $substance_color{$k) = $v;
  }
}
Если в объединяемых хэшах присутствуют одинаковые ключи, можно вставить код для обработки дубликатов:
foreach $substanceref (\%food_color, \%drink_color ) {
  while (($k, $v) = each %substanceref ) {
    if (exists $substance_color{$k}) {
      print "Warning: $k seen twice. Using the first definition. \n";
      next;
    }
    $substance_color{$k} = $v;
  }
}
В частном случае присоединения одного хэша к другому можно воспользоваться срезом для получения более элегантной записи:
@all_colors{keys %new_colors} = values %new_colors;
Потребуется память в объеме, достаточном для хранения списков всех ключей и значений %new_colors. Как и в первом варианте, расходы памяти при большом размере списков могут сделать эту методику неприемлемой.

См. также

Описание функции each



2013-09-10 17:05:19

Proverte kod v komentariyah gde pro list tam oshibki detskie




Оставить комментарий:
Ваше Имя:
Email:
Антибот: *  
Ваш комментарий: