PHP-循环通过多维数组和减少数组,如果关键发现。

时间:2022-11-16 21:30:42

I have an array that looks like this:

我有一个这样的数组:

array:3 [
  0 => array:5 [
    "id" => 18
    "product_id" => 37
    "total_price" => "643.00"
    "created_at" => "2017-05-02 13:22:35"
    "updated_at" => "2017-05-02 13:22:35"
  ]
  1 => array:5 [
    "id" => 19
    "product_id" => 36
    "total_price" => "532.00"
    "created_at" => "2017-05-02 13:23:47"
    "updated_at" => "2017-05-02 13:23:47"
  ]
  2 => array:5 [
    "id" => 20
    "product_id" => 36
    "total_price" => "532.00"
    "created_at" => "2017-05-03 13:20:47"
    "updated_at" => "2017-05-03 13:20:47"
  ]
]

In my case if the key "product_id" has the same value I want to reduce merge those arrays and add the total_price but I have to also save a new key to the new array: $quantity to store the number of array with the same key that existed before merging. So the final result should look like this:

在我的例子中,如果关键字“product_id”具有相同的值,我想减少合并这些数组并添加total_price,但是我还必须为新数组保存一个新键:$quantity,以使用合并前存在的相同键来存储数组的数量。所以最终的结果应该是这样的:

array:2 [
  0 => array:5 [
    "id" => 18
    "product_id" => 37
    "total_price" => "643.00"
    "quantity"   => 1
    "created_at" => "2017-05-02 13:22:35"
    "updated_at" => "2017-05-02 13:22:35"
  ]
  1 => array:5 [
    "id" => 19
    "product_id" => 36
    "total_price" => "1064.00"
    "quantity"   => 2
    "created_at" => "2017-05-02 13:23:47"
    "updated_at" => "2017-05-02 13:23:47"
  ]
]

Initially I tried with array_walk_recursive, but I got confused.

最初我尝试使用array_walk_recursive.com,但是我搞混了。

array_walk_recursive($products, function($value, $key) use (&$products_sold){
            array_push($products_sold, isset($products_sold[$key]) ?  $value + $products_sold[$key] : $value);
        });

I know this is useless but I failed to realize how to do this. Any explanation would be helpful. Thank you all for your time!

我知道这是没有用的,但我没有意识到怎么做。任何解释都是有用的。谢谢大家!

2 个解决方案

#1


2  

Try

试一试

$result = array_reduce($products, function ($result, $product) {
    foreach ($result as $index => $value) {
        if ($value['product_id'] == $product['product_id']) {
            $result[$index]['total_price'] += $product['total_price'];

            return $result;
        }
    }
    $result[] = $product;
    return $result;
}, []);

But I strongly recomment use BCMath functions instead of working with floats.

但我强烈建议使用BCMath函数,而不是使用浮点数。

So its better to write

所以最好写下来

$result[$index]['total_price'] = bcadd($result[$index]['total_price'], $product['total_price'], 2);

instead of

而不是

$result[$index]['total_price'] += $product['total_price'];

Update

更新

We can rewrite above version to nested foreach like so:

我们可以将上面的版本重写为嵌套foreach,如下所示:

$reducer = function ($result, $product) {
    foreach ($result as $index => $value) {
        if ($value['product_id'] == $product['product_id']) {
            $result[$index]['total_price'] += $product['total_price'];

            return $result;
        }
    }
    $result[] = $product;
    return $result;
};

$result = [];

foreach($products as $product) {
    $result = $reducer($result, $product);
}

so we can see it is just foreach loop which calls function which contains another foreach. We need another foreach because we need the way to determine if array contains product_id. We can index result with product_id so we can avoid secind foreach:

我们可以看到它只是foreach循环它调用包含另一个foreach的函数。我们需要另一个foreach,因为我们需要确定数组是否包含product_id。我们可以用product_id索引结果因此我们可以避免secind foreach:

$result = array_reduce($products, function ($result, $product) {
    $productId = $product['product_id'];
    if(isset($result[$productId])) {
        $result[$productId]['total_price'] += $product['total_price'];
        return $result;
    }
    $result[$productId] = $product;
    return $result;
}, []);

and then if you need indexes to be ordered from zero just call array_values($result)

如果需要从0开始排序索引只需调用array_values($result)

#2


2  

Got it done! I should say I didnt use total_price as string so I can do addition.

做到了!我应该说,我没有使用total_price作为字符串,所以我可以添加。

$stuff = array(
    array(
        "id" => 18,
        "product_id" => 37,
        "total_price" => 643.00,
        "created_at" => "2017-05-02 13:22:35",
        "updated_at" => "2017-05-02 13:22:35"),

    array(
        "id" => 19,
        "product_id" => 36,
        "total_price" => 532.00,
        "created_at" => "2017-05-02 13:23:47",
        "updated_at" => "2017-05-02 13:23:47"),

    array(
        "id" => 20,
        "product_id" => 36,
        "total_price" => 532.00,
        "created_at" => "2017-05-03 13:20:47",
        "updated_at" => "2017-05-03 13:20:47")
    );

for ($i=0; $i < count($stuff); $i++) { 
    $product_id = $stuff[$i]["product_id"];
    foreach ($stuff as $key => $value) {
        if($value["product_id"] === $product_id && $i !== $key) {
            $stuff[$i]["total_price"] += $value["total_price"];
            unset($stuff[$key]);
        }
    }
}

#1


2  

Try

试一试

$result = array_reduce($products, function ($result, $product) {
    foreach ($result as $index => $value) {
        if ($value['product_id'] == $product['product_id']) {
            $result[$index]['total_price'] += $product['total_price'];

            return $result;
        }
    }
    $result[] = $product;
    return $result;
}, []);

But I strongly recomment use BCMath functions instead of working with floats.

但我强烈建议使用BCMath函数,而不是使用浮点数。

So its better to write

所以最好写下来

$result[$index]['total_price'] = bcadd($result[$index]['total_price'], $product['total_price'], 2);

instead of

而不是

$result[$index]['total_price'] += $product['total_price'];

Update

更新

We can rewrite above version to nested foreach like so:

我们可以将上面的版本重写为嵌套foreach,如下所示:

$reducer = function ($result, $product) {
    foreach ($result as $index => $value) {
        if ($value['product_id'] == $product['product_id']) {
            $result[$index]['total_price'] += $product['total_price'];

            return $result;
        }
    }
    $result[] = $product;
    return $result;
};

$result = [];

foreach($products as $product) {
    $result = $reducer($result, $product);
}

so we can see it is just foreach loop which calls function which contains another foreach. We need another foreach because we need the way to determine if array contains product_id. We can index result with product_id so we can avoid secind foreach:

我们可以看到它只是foreach循环它调用包含另一个foreach的函数。我们需要另一个foreach,因为我们需要确定数组是否包含product_id。我们可以用product_id索引结果因此我们可以避免secind foreach:

$result = array_reduce($products, function ($result, $product) {
    $productId = $product['product_id'];
    if(isset($result[$productId])) {
        $result[$productId]['total_price'] += $product['total_price'];
        return $result;
    }
    $result[$productId] = $product;
    return $result;
}, []);

and then if you need indexes to be ordered from zero just call array_values($result)

如果需要从0开始排序索引只需调用array_values($result)

#2


2  

Got it done! I should say I didnt use total_price as string so I can do addition.

做到了!我应该说,我没有使用total_price作为字符串,所以我可以添加。

$stuff = array(
    array(
        "id" => 18,
        "product_id" => 37,
        "total_price" => 643.00,
        "created_at" => "2017-05-02 13:22:35",
        "updated_at" => "2017-05-02 13:22:35"),

    array(
        "id" => 19,
        "product_id" => 36,
        "total_price" => 532.00,
        "created_at" => "2017-05-02 13:23:47",
        "updated_at" => "2017-05-02 13:23:47"),

    array(
        "id" => 20,
        "product_id" => 36,
        "total_price" => 532.00,
        "created_at" => "2017-05-03 13:20:47",
        "updated_at" => "2017-05-03 13:20:47")
    );

for ($i=0; $i < count($stuff); $i++) { 
    $product_id = $stuff[$i]["product_id"];
    foreach ($stuff as $key => $value) {
        if($value["product_id"] === $product_id && $i !== $key) {
            $stuff[$i]["total_price"] += $value["total_price"];
            unset($stuff[$key]);
        }
    }
}