过滤 php 数组并仅保留重复数据中最旧的数据

问题描述 投票:0回答:2

我在 PHP 中有一个数组,可以有 多个相同的标签,但每个标签的 创建日期 不同。我尝试过滤我的数组并当数组中存在重复标签时仅保留旧创建的数据。

数组看起来像这样:

$data = [
     [0] => Array
        (
            [label] => "Same label"
            [created] => "15/01/2022" //recent data
        )
     [1] => Array
        (
            [label] => "Same label"
            [created] => "11/01/2022" //oldest data to unset
        )
     [2] => Array
        (
            [label] => "Label alone"
            [created] => "18/01/2022"
        )
]

并且必须是这样的:

$data = [
     [0] => Array
        (
            [label] => "Same label"
            [created] => "11/01/2022"
        )
     [1] => Array
        (
            [label] => "Label alone"
            [created] => "18/01/2022"
        )
]

实际上,我尝试过使用

array_search()
,但是如果数据很多,则过程很长我可以删除重复数据,但我不知道如何仅在数组中的重复标签上按创建日期进行过滤...

$data = [];
foreach ($prs as $pr) {
  $exist = array_search($pr->getLabel, array_column($data, 'label'), TRUE);

  if (!$exist){
    $data[] = [
          'label' => $pr->getLabel(),
          'created' => $pr->getCreationDate(),
    ];
  }
}

我看到还有

array_filter()
功能,
array_key_exists()
等不错的功能

你能帮我吗?

我会随着进度添加更多信息,但我无法显示所有页面或进程(仅作为示例,因为它们是机密数据)。

非常感谢您的帮助。

php arrays filter associative-array
2个回答
1
投票

一种方法可能是按标签和日期进行双重排序。然后排序后,您可以循环集合并比较当前和下一个标签。

如果下一个标签与集合中的当前标签或最后一个标签不同,则将该项目添加到

$result
数组中。

该示例使用 spaceship 运算符

<=>
进行 usort 函数中的比较,自 php 7 起可用

$data = [
    ["label" => "test1","created" => "31/12/2022"],
    ["label" => "Same label", "created" => "13/01/2022"],
    ["label" => "Same label", "created" => "15/01/2022"],
    ["label" => "Same label", "created" => "11/01/2022"],
    ["label" => "Label alone","created" => "18/01/2022"],
    ["label" => "test1","created" => "30/12/2022"],
];

usort($data, function($a, $b) {
    if ($a["label"] === $b["label"]) {
        return DateTime::createFromFormat("d/m/Y", $a["created"]) <=> DateTime::createFromFormat("d/m/Y", $b["created"]);
    }
    return $a["label"] <=> $b["label"];
});

$result = [];
$last = count($data) - 1;

for ($i = 0; $i < count($data); $i++) {
    if ((isset($data[$i + 1]) && $data[$i + 1]["label"] !== $data[$i]["label"]) || $i === $last) {
        $result[] = $data[$i];
    }
}

print_r($result);

输出

Array
(
    [0] => Array
        (
            [label] => Label alone
            [created] => 18/01/2022
        )

    [1] => Array
        (
            [label] => Same label
            [created] => 15/01/2022
        )

    [2] => Array
        (
            [label] => test1
            [created] => 31/12/2022
        )

)

查看 PHP 演示


0
投票

由于您的日期列值使用“big-endian”格式,因此您需要在排序之前解析这些字符串。通过在隔离解析值后进行排序来最小化总解析调用。

数组按 ASC 顺序按日期排序后,您可以通过调用

array_column()
并使用
label
值分配临时第一级键,要求 PHP 用后面遇到的重复项覆盖前一个遇到的重复项。

因为 PHP 不允许在任何级别出现重复的键,并且使用它们作为键时您的

label
值不会被破坏,所以这种技术是可靠的。请注意,如果您的临时键是浮点数或可能是强制碰撞整数的类型的混合,则这种方法并不安全。

代码:(演示

array_multisort(
    array_map(fn($row) => date_create_from_format('d/m/Y', $row['created']), $data),
    $data
);
var_export(array_values(array_column($data, null, 'label')));

此页面类似于:根据一个值从数组中删除重复的对象,在 PHP 中保留其他值的最低值?

© www.soinside.com 2019 - 2024. All rights reserved.