середа, 6 квітня 2016 р.

Сравнение ассоциативных массивов по нескольким ключам

Ну, раз решил что блог будет про говнокод, тогда начнём.
Допустим ситуацию. Есть два вложенных ассоциативных массива данных. Нужно узнать, есть ли у них "похожие" записи, учитывая при сравнении похожести значения только некоторые из ключей. Я проиллюстрирую:
// при сравнении обращаем внимание только на ключи массива `param1` и `param2`
// то есть $data[0] похожа по значимым ключам $data_src[2]
// а так же $data[1] похожа $data_src[3]
$data_src = array(
  0 => array('id' => 1, 'param1' => 0, 'param2' => 0, 'value' => 0.01),
  1 => array('id' => 2, 'param1' => 1, 'param2' => 0, 'value' => 0.02),
  2 => array('id' => 3, 'param1' => 0, 'param2' => 1, 'value' => 0.03),
  3 => array('id' => 4, 'param1' => 1, 'param2' => 1, 'value' => 0.04) 
);
$data = array(
  0 => array('param1' => 0, 'param2' => 1, 'value' => 0.11),
  1 => array('param1' => 1, 'param2' => 1, 'value' => 0.12)
);
В моём случае я столкнулся с необходимостью такого анализа, когда писал парсер (распознавалку) файлов с прайс-листами. Там цена зависела сразу от нескольких параметров и мне нужно было запросить все цены прайса, уже существующие в базе данных и сравнить их с новыми ценами. Потом по результатам разобраться, какие вставлять, какие обновлять, какие даже удалять (если они существовали в БД, а в импортируемом файле цен с таким набором параметров уже не было).

Самым очевидным (для меня) было "проиндексировать" значения этих значимых ключей, и потом искать совпадение по этой индексированной строке:
// индексируем исходный массив
$index_src = array();
foreach ($data_src as $i => $row) {
  $index_src[$i] = serialize(array(
    'param1' => $row['param1'],
    'param2' => $row['param2']
  ));
}
$index_src = array_flip($index_src);

// ищем совпадения
$similar = array();
foreach ($data as $i => $row) {
  $str = serialize(array(
    'param1' => $row['param1'],
    'param2' => $row['param2']
  ));
  if (array_key_exists($str, $index_src)) {
    $similar[$i] = $index_src[$str];
  }
}
// получаем массив с индексами похожих массивов 
// $similar = array(
//    0 => 2,
//    1 => 3
// );
Цель достигнута конечно, но меня не отпускает ощущение, что это не самое оптимальное решение. Хотя не спорю, по рукам нужно бить линейкой за поиск оптимального решения в задаче, выполняемой в лучшем случае раз в месяц.

Немає коментарів :

Дописати коментар