如何在 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);
参考:
- http://php.net/manual/en/function.array-reduce.php
- http://php.net/manual/en/function.array-filter.php
有关示例,请参阅:
我有以下数组(数组很大):
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);
参考:
- http://php.net/manual/en/function.array-reduce.php
- http://php.net/manual/en/function.array-filter.php
有关示例,请参阅: