Группировка ключей ассоциативного массива — в том же порядке

#php #arrays

#php #массивы

Вопрос:

У меня есть следующие 2 массива, и я хотел бы их объединить. Меня больше интересуют ключи, чем их значения. Я хотел бы воспользоваться этим

 $arr1 = array(
  'tom' => "1", 
  'sally' => "20"   // unique
  'larry' => "2", 
  'kate' => "3",
  'dave' => "23"    //unique
);

$arr2 = array(
  'tom' => "11", 
  'larry' => "12", 
  'drummer' => "2", // unique
  'kate' => "7",
  'nick' => "3"     //unique
);
  

и превратите это во что-то вроде этого

 $arr = array(
  'tom',
  'sally',     //unique from arr1, ended up here because she's before larry
  'drummer',   //unique from arr2, ended up here because he's after larry
  'larry', 
  'kate',
  'dave',     //unique from arr1, ended up here because he's after the last 2 similar
  'nick'      //unique from arr2, ended up here because he's after the last 2 similar
);
  

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

Комментарии:

1. Порядок не имеет смысла для меня. Было бы логично и осуществимо, если бы «барабанщик» шел после «Ларри» в конечном массиве. В вашем примере они расположены в обратном порядке по сравнению с исходным массивом, что кажется довольно произвольным. Тогда почему перед «kate» не стоит также «nick»?

2. упс, опечатка 🙂 буду редактировать.

Ответ №1:

Как правило, вам нужен нетривиальный алгоритм. Это называется сопоставлением последовательностей или самой длинной общей проблемой подпоследовательности. Я не думаю, что есть встроенная функция PHP для вычисления этого. Как только у вас будут совпадения, вы можете обработать несогласованные элементы между ними. Просто обратите внимание, что может быть несколько общих подпоследовательностей, поэтому не всегда будет возможно, чтобы все элементы располагались в том же порядке, что и в исходных массивах, если вы действительно хотите такого рода слияния.

Если вам не нужен наилучший возможный результат, вы могли бы попробовать приближение, подобное этому, которое жадно ищет совпадения в 4 следующих элементах:

 $result = array();

$i = 0;
$j = 0;
while ($i < count($arr1)) {
    // Look for a matching item in the next four items of $arr2
    $k = 0;
    while ($k < 4) {
        // Do we have a match?
        if ($arr1[$i] == $arr2[$j $k]) {
            // Add items from $arr2 that are before the matching item
            while ($k-- > 0) {
                $result[] = $arr2[$j];
                $j  ;
            }
            $j  ;
            break;
        }
        $k  ;
    }
    // Add the current item fro $arr1
    $result[] = $arr1[$i];
    $i  ;
}
// Add the remaining items from $arr2
while ($j < count($arr2)) {
    $result[] = $arr2[$j];
    $j  ;
}

$result = array_unique($result);
  

Комментарии:

1. По какой-то причине мои правки / попытки не отображаются в сообщении. Возможно, потребуется некоторое время, чтобы появилось отредактированное новое содержимое. Но то, что ты говоришь, Лукас, верно. барабанщик теперь охотится за Ларри, как логически ожидалось

2. Да, этот ответ основан на текущей версии. Для предыдущего порядка вам все равно нужно было бы получить LCS, но порядок несогласованных элементов был бы не таким четким.

3. У вас есть идеи, как мне разобраться с этим. Это не абсолютно необходимая функция, но было бы неплохо иметь, поэтому я подумал, почему бы не попробовать заставить ее работать. Я думаю, что LCS в моем случае может и не понадобиться. Я думал просмотреть второй массив, посмотреть, является ли что-то уникальным, затем попытаться сопоставить, где это подходит.