array_diff() с многомерными массивами

С помощью array_diff()Я могу сравнивать и удалять похожие элементы, но что если у меня есть следующие массивы?

Array1

Array
(
    [0] => Array
        (
            [ITEM] => 1
        )

    [1] => Array
        (
            [ITEM] => 2
        )

    [2] => Array
        (
            [ITEM] => 3
        )
)

array2

Array
(
    [0] => Array
        (
            [ITEM] => 2
        )

    [1] => Array
        (
            [ITEM] => 3
        )

    [2] => Array
        (
            [ITEM] => 1
        )
    [3] => Array
        (
            [ITEM] => 4
        )
)

Я хочу отфильтровать подобные предметы; результат должен вернуть 4. Как я могу изменить свой массив, чтобы я мог использовать array_diff()?

9 ответов

Решение

Я, вероятно, перебрал бы исходные массивы и сделал бы их одномерными... что-то вроде

foreach($array1 as $aV){
    $aTmp1[] = $aV['ITEM'];
}

foreach($array2 as $aV){
    $aTmp2[] = $aV['ITEM'];
}

$new_array = array_diff($aTmp1,$aTmp2);

Вы можете определить пользовательскую функцию сравнения, используя array_udiff(),

function udiffCompare($a, $b)
{
    return $a['ITEM'] - $b['ITEM'];
}

$arrdiff = array_udiff($arr2, $arr1, 'udiffCompare');
print_r($arrdiff);

Выход:

Array
(
    [3] => Array
        (
            [ITEM] => 4
        )
)

Это использует и сохраняет существующую структуру массивов, которую, я полагаю, вы хотите.

Еще один забавный подход с json_encode хитрость (может быть полезна, если вам нужно "сырое" сравнение некоторых сложных значений в массиве первого уровня):

// Compare all values by a json_encode
$diff = array_diff(array_map('json_encode', $array1), array_map('json_encode', $array2));

// Json decode the result
$diff = array_map('json_decode', $diff);

Пара решений с использованием array_filter которые менее производительны, чем array_udiff решение для больших массивов, но которые более просты и гибки:

$array1 = [
    ['ITEM' => 1],
    ['ITEM' => 2],
    ['ITEM' => 3],
];

$array2 = [
    ['ITEM' => 2],
    ['ITEM' => 3],
    ['ITEM' => 1],
    ['ITEM' => 4],
];

$arrayDiff = array_filter($array2, function ($element) use ($array1) {
    return !in_array($element, $array1);
});

// OR

$arrayDiff = array_filter($array2, function ($array2Element) use ($array1) {
    foreach ($array1 as $array1Element) {
        if ($array1Element['ITEM'] == $array2Element['ITEM']) {
            return false;
        }
    }
    return true;
});

Как всегда с array_filter, Обратите внимание, что array_filter сохраняет ключи исходного массива, так что если вы хотите $arrayDiff чтобы быть нулевым, сделать $arrayDiff = array_values($arrayDiff); после array_filter вызов.

Вы можете использовать приведенный ниже код, чтобы получить разницу

$a1 = Array(
    [0] => Array(
            [ITEM] => 1
        )
    [1] => Array(
            [ITEM] => 2
        )
    [2] => Array(
            [ITEM] => 3
        )
    );

$a2 = Array(
    [0] => Array(
            [ITEM] => 2
        )
    [1] => Array(
            [ITEM] => 3
        )

    [2] => Array(
            [ITEM] => 1
        )
    [3] => Array(
            [ITEM] => 4
        ));

array_diff(array_column($a1, 'ITEM'), array_column($a2, 'ITEM'));

Возникла та же проблема, но мой многомерный массив имеет различные ключи в отличие от вашего "ПУНКТА" последовательно в каждом массиве.

Решил это с помощью: $result = array_diff_assoc($array2, $array1);

Ссылка: PHP: array_diff_assoc

Доверяйте тому, что разработчики PHP оптимизировали array_udiff()превзойти все другие методы, которые могли бы сделать то же самое.

Что касается вашего сценария, вы ищете фильтрацию, которая оценивает данные в пределах «значения» первого уровня (строки данных). В пользовательской функции конкретный столбец должен быть изолирован для сравнения. Список всех вариантов собственных функций см . в этом ответе .

Чтобы использовать первый массив для фильтрации второго массива (и вывода сохраненных данных из второго массива), вы должны написать $array2в качестве первого параметра и $array1как второй параметр.

array_diff()а также array_intersect()функции, которые используют (содержат uв имени своей функции) ожидают целое число в качестве возвращаемого значения. Это значение используется для предварительной сортировки данных перед фактическим выполнением оценок — это оптимизация производительности. Могут быть сценарии, когда, если вы только вернетесь 0или же 1(не трехстороннее сравнение), то результаты могут быть неожиданными. Чтобы гарантировать стабильный результат, всегда предоставляйте функцию сравнения, которая может возвращать отрицательное, положительное и нулевое целое число.

При сравнении целочисленных значений вычитание ( $a - $b) даст надежные возвращаемые значения. Для большей полезности при сравнении значений с плавающей запятой или нечисловых данных вы можете использовать оператор космического корабля, когда ваша версия PHP делает его доступным.

Коды: ( Демо)

  • PHP7.4+ (стрелочные функции)

            var_export(
        array_udiff($array2, $array1, fn($a, $b) => $a['ITEM'] <=> $b['ITEM'])
    );
    
  • PHP7+ (оператор космического корабля)

            var_export(
        array_udiff(
            $array2,
            $array1,
            function($a, $b) {
                return $a['ITEM'] <=> $b['ITEM'];
            }
        )
    );
    
  • PHP5.3+ (анонимные функции)

            var_export(
        array_udiff(
            $array2,
            $array1,
            function($a, $b) {
                return $a['ITEM'] === $b['ITEM']
                    ? 0
                    : ($a['ITEM'] > $b['ITEM'] ? 1 : -1);
            }
        )
    );
    

Вывод для всех версий выше:

      array (
  3 => 
  array (
    'ITEM' => 4,
  ),
)

При работе с массивами объектов используется тот же метод; только синтаксис для доступа к свойству отличается от доступа к элементу массива ( $a['ITEM']было бы $a->ITEM).


Для сценариев, когда элемент, изолированный от одного массива, не существует в другом массиве, вам нужно будет объединить оба $aа также $bdata в противоположный резервный столбец, поскольку данные из первого и второго массивов будут представлены в обоих аргументах обратного вызова.

Код: ( Демо)

      $array1 = array(
    array('ITEM' => 1),
    array('ITEM' => 2),
    array('ITEM' => 3),
);

$array2 = array(
    array('ITEMID' => 2),
    array('ITEMID' => 3),
    array('ITEMID' => 1),
    array('ITEMID' => 4),
);

// PHP7.4+ (arrow functions)
var_export(
    array_udiff(
        $array2,
        $array1,
        fn($a, $b) => ($a['ITEM'] ?? $a['ITEMID']) <=> ($b['ITEM'] ?? $b['ITEMID'])
    )
);

Другое решение, если (json_encode($array1) == json_encode($array2)) {...}

Сравнивает массив1 с одним или несколькими другими массивами и возвращает значения в массиве1, которых нет ни в одном из других массивов.

        //Enter your code here, enjoy!

$array1 = array("a" => "green", "red", "blue");
$array2 = array("b" => "green", "yellow", "red");
$result = array_diff($array1, $array2);

print_r($result);
Другие вопросы по тегам