如何在 php 数组中找到并删除几乎重复的行,其中一个键值不同?

How find and delete almost duplicate rows in php array, which differ in one key value?

我有以下数组(数组很大):

Array ( 
   [0] => Array ( 
              [id] => 1 
              [timestamp] => 1503050400
              [name] =>  Event A
              [value] =>  )
   [1] => Array ( 
              [id] => 2 
              [timestamp] => 1503446400
              [name] => Event B 
              [value] =>  )
   [2] => Array ( 
              [id] => 2 
              [timestamp] => 1503446400
              [name] => Event B 
              [value] => 71 )
   [3] => Array ( 
              [id] => 3 
              [timestamp] => 1503720000
              [name] => Event C
              [value] => 12 )
   [4] => Array ( 
              [id] => 3 
              [timestamp] => 1503720000
              [name] => Event C 
              [value] =>  )

              ...
)

如您所见,一些数组键(行)具有相同的 ID、时间戳和名称,但具有不同的值。 我想找到并取消设置 ($array[$key]) 满足以下条件的行:

如果数组中有相同名称、ID 和时间戳的键,删除这些键,但只保留 Value != null

看起来像这样:

foreach ($array as $key => $row) {
  if ( ... ) {
    unset($array[$key]);
  }
else {}

}
print_r($array);

输出应该是:

Array ( 
   [0] => Array ( 
              [id] => 1 
              [timestamp] => 1503050400
              [name] =>  Event A
              [value] =>  )
   [2] => Array ( 
              [id] => 2 
              [timestamp] => 1503446400
              [name] => Event B 
              [value] => 71 )
   [3] => Array ( 
              [id] => 3 
              [timestamp] => 1503720000
              [name] => Event C
              [value] => 12 )

              ...
)
foreach ($array as $key => $row) {
  if ($row[value]) {
    unset($array[$key]);
  }
else {
  $row[result] = $row[value];
  unset($row[value]);
  }
}
print_r($array);

您可以使用 array_reduce()array_filter():

<?php

$data = array(
    array(
        'id' => 1,
        'timestamp' => 1503050400,
        'name' => 'Event A',
        'value' => null,
    ),
    array(
        'id' => 2,
        'timestamp' => 1503446400,
        'name' => 'Event B',
        'value' => null,
    ),
    array(
        'id' => 2,
        'timestamp' => 1503446400,
        'name' => 'Event B',
        'value' => 71,
    ),
    array(
        'id' => 3,
        'timestamp' => 1503720000,
        'name' => 'Event C',
        'value' => 12,
    ),
    array(
        'id' => 3,
        'timestamp' => 1503720000,
        'name' => 'Event C',
        'value' => null,
    ),
);

/**
 * Reduce the array of items to an array of buckets, where
 * each bucket contains elements with the same
 *
 * - id
 * - timestamp
 * - name
 *
 * so that we can than take a look at the contents of the
 * individual buckets.
 */
$buckets = array_reduce(
    $data,
    function (array $carry, array $item) {
        /**
         * create an index from
         *
         * - id
         * - timestamp
         * - name
         */
        $index = serialize(array(
            'id' => $item['id'],
            'timestamp' => $item['timestamp'],
            'name' => $item['name'],
        ));

        /**
         * initialize empty bucket if we don't have one yet for this index
         */
        if (!array_key_exists($index, $carry)) {
            $carry[$index] = array();
        }

        /**
         * add item to bucket
         */
        $carry[$index][] = $item;

        return $carry;
    },
    array()
);

/**
 * Reduce the content of the buckets to elements that match the requirements.
 */
$filtered = array_reduce(
    $buckets,
    function (array $carry, array $items) {
        /**
         * if we have only one item in the bucket, let's take it
         */
        if (1 === count($items)) {
            $carry[] = array_shift($items);

            return $carry;
        }

        /**
         * find all items where the value is not null
         */
        $withoutNullValue = array_filter($items, function (array $item) {
            return array_key_exists('value', $item) && null !== $item['value'];
        });

        /**
         * if we have any items where the value is not null, take all of them
         */
        if (0 < count($withoutNullValue)) {
            $carry = array_merge(
                $carry,
                $withoutNullValue
            );

            return $carry;
        }

        /**
         * if all of the items have a value of null, let's just take the first
         */
        $carry[] = array_shift($items);

        return $carry;
    },
    array()
);

var_dump($filtered);

参考:

有关示例,请参阅: