【问题标题】:Remove duplicate objects from array based on one value, keep lowest of other value in PHP?基于一个值从数组中删除重复对象,保持PHP中其他值的最低值?
【发布时间】:2017-02-16 18:19:17
【问题描述】:

现在我在 PHP 中有一个对象数组,其中一些对象的“id”值重复。我正在尝试删除重复项,但我想保留“数量”值最低的那个。

我知道您通常如何从数组中删除重复的整个对象,但不仅是如果一个值是重复的,以及如何保留另一个值的较低值。

例子:

[
    {
        id: 1,
        qty: 200
    },
    {
        id: 1,
        qty: 190
    },
    {
        id: 2,
        qty: 10
    },
    {
        id: 2,
        qty: 12
    },
    {
        id: 2,
        qty: 10
    },
    {
        id: 3,
        qty: 5
    },
    {
        id: 4,
        qty: 5
    },
    {
        id: 4,
        qty: 2
    },
]

我最终想要的是..

[
    {
        id: 4,
        qty: 2
    },
    {
        id: 3,
        qty: 5
    },
    {
        id: 2,
        qty: 10
    },
    {
        id: 1,
        qty: 190
    }
]

这可能吗?

【问题讨论】:

    标签: php arrays


    【解决方案1】:

    这看起来几乎像 JSON,所以假设你 $array = json_decode($json, true) 到一个关联数组:

    array_multisort(array_column($array, 'qty'), SORT_DESC, $array);
    $result = array_column($array, null, 'id');
    
    • 提取qty 的数组并对其进行降序排序,然后对原始数组进行排序
    • 从中提取一个以id为键的数组

    使用array_column() 提取将导致最后一个id 键覆盖以前的键。最后一个将是自降序排序以来qty 最低的那个。

    如果您需要将其恢复为 JSON 对象,则只需重新索引:

    $json = json_encode(array_values($result));
    

    【讨论】:

    • 非常好。这几乎完全符合我的目标。现在浏览所有这些功能的文档。如果我想在最后再次对它进行排序,以便数组按照从最高到最低 id 的顺序排列,那会是什么?我刚刚尝试了array_multisort($array, SORT_ASC);SORT_DESC,但我仍然按照 1、2、3、4 的顺序购买它们,但想要 4、3、2、1 的顺序。
    • 你的意思是从最高到最低id
    • @AbraCadaver 是的。我只是尝试了所有我能想到的排序方法,但出于某种原因,我仍然将它们从最低到最高 id
    • 如果是这样,那么只需按反向键排序:krsort($result);,因为键现在是 id
    • @AbraCadaver 这仍然给了我一个包含 4 个对象的对象,由于某种原因,它按 1、2、3、4 排序。
    【解决方案2】:

    AbraCadaver 想出了这么好的答案,但我努力想出了我的答案,所以我想分享它以防它对某人有用。如果有的话,它可能对扩展的或更复杂的数组有用。我走的是创建嵌套循环的路线。代码如下:

        $newArray = [];
    
        for ($i = 0; $i < count($myArray); $i++)
        {
            $id_column = array_column($newArray, 'id');
            $qty_column = array_column($newArray, 'qty');
            if (!in_array($myArray[$i]['id'],$id_column)) {
                array_push($newArray, $myArray[$i]);
            }
            else {
                $id_pos = array_search($myArray[$i]['id'],$id_column);
                if ($myArray[$i]['qty'] < $qty_column[$id_pos])
                {
                    array_splice($newArray,$id_pos,1,$myArray[$i]);
                }
            }
        }
    

    基本上我创建了一个新的空数组。我循环遍历原始数组的每个元素以查看它是否在新数组中。如果没有,我添加它,如果它已经在新的数组中,那么我检查新的数组,看看那个id的数量是否更高,如果是,我在当前行拼接。

    【讨论】:

    • 非常好!绝对保存以备后用。
    【解决方案3】:

    这是可能的答案之一,假设 $your_input 包含您的数据作为字符串...

    方法一

    <?php
    $your_input=preg_replace('#\s*\{\s*id\s*:\s*([^,]+?),\s*qty\s*:\s*([^,\}]+?)\s*\}\s*(,)?#','{"id":"$1","qty":"$2"}$3',$your_input);
    $your_input=json_decode($your_input,true);
    $result=[];
    foreach($your_input as $a) 
    if (!array_key_exists($a['id'],$result) or $a['qty']<$result[$a['id']]['qty'])
    {
    $result[$a['id']]['id']=$a['id'];
    $result[$a['id']]['qty']=$a['qty'];
    }
    $result=json_encode(array_values($result),JSON_PRETTY_PRINT);
    echo '<pre>';
    print_r($result);
    

    方法二

    <?php
    $your_input=str_replace(['        ',':'],['"','":'],$your_input);
    $your_input=json_decode($your_input,true);
    usort($your_input,function($a,$b){return $a['qty']==$b['qty']?0:($a['qty']>$b['qty']?-1:1);});
    foreach($your_input as $b) $result[$b['id']]=['id'=>$b['id'],'qty'=>$b['qty']];
    $result=json_encode(array_values($result),JSON_PRETTY_PRINT);
    echo '<pre>';
    print_r($result);
    

    在方法 1 或方法 2 之后,$result 变量应包含以下数据字符串...

    [
        {
            "id": 1,
            "qty": 190
        },
        {
            "id": 2,
            "qty": 10
        }
    ]
    

    【讨论】:

      【解决方案4】:

      没有必要涉及排序算法——这只会对脚本性能产生负面影响。

      如果行的 id 尚未出现在输出数组中,则使用临时的第一级键将其推入输出数组。如果行的 id 已经在输出数组中,但数量较少,则覆盖输出数组中的行。

      这个任务永远不需要超过一个循环。如果要删除临时的一级键,则循环后调用array_values()

      代码:(Demo)

      $data = [
          ['id' => 1, 'qty' => 200],
          ['id' => 1, 'qty' => 190],
          ['id' => 2, 'qty' => 10],
          ['id' => 2, 'qty' => 12],
          ['id' => 2, 'qty' => 10],
          ['id' => 3, 'qty' => 5],
          ['id' => 4, 'qty' => 5],
          ['id' => 4, 'qty' => 2],
      ];
      
      $result = [];
      foreach ($data as $row) {
          if (!isset($result[$row['id']]) || $row['qty'] < $result[$row['id']]['qty']) {
              $result[$row['id']] = $row;
          }
      }
      var_export(array_values($result));
      

      输出:

      array (
        0 => 
        array (
          'id' => 1,
          'qty' => 190,
        ),
        1 => 
        array (
          'id' => 2,
          'qty' => 10,
        ),
        2 => 
        array (
          'id' => 3,
          'qty' => 5,
        ),
        3 => 
        array (
          'id' => 4,
          'qty' => 2,
        ),
      )
      

      【讨论】:

        猜你喜欢
        • 2020-12-07
        • 2021-03-03
        • 1970-01-01
        • 2016-11-07
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-04-02
        相关资源
        最近更新 更多