Group identical items in PHP array & count

2020-05-08 17:56发布

问题:

I'm trying to create an array that groups together similar/identical items and creates a count/ tally of the number of times that item occurs.

I've managed to get an array to output that looks something like this:

Code            Item
WX4RCDWK3VJ7M   Caesar Salad
WX4RCDWK3VJ7M   Caesar Salad
YTZ8346445MFT   Wolfblass Cab Sauvignon
XGZ4NDEDKTCGY   Rib Eye 16 oz
A50NPRW74C5K6   Filet 8 oz
A50NPRW74C5K6   Filet 8 oz
A50NPRW74C5K6   Filet 8 oz

I'd like the output to look something like this:

Code            Item                      Count
WX4RCDWK3VJ7M   Caesar Salad              2
YTZ8346445MFT   Wolfblass Cab Sauvignon   1 
XGZ4NDEDKTCGY   Rib Eye 16 oz             1
A50NPRW74C5K6   Filet 8 oz                3

Currently I've managed to get to this point correctly, based on an original extensive multidimensional array ( $orders[]['lineItems']['elements'][]):

foreach ($orders as $order){
  foreach ($order['lineItems']['elements'] as $item){
       $product['code'] = $item['item']['code'];
       $product['name'] = $item['name'];
       $products[] = $product;
  }
}
print_r ($products);

I've tried using array_count_values, but get an error in my terminal saying "Can only count STRING and INTEGER values!".

I've tried looping the product['code'] in as a key for my output array ($products) and increment a product['count'] item.

This seems like it should be very basic, but I'm missing something.

EDIT: The original array that I'm looping through looks something like this (I have taken out most irrelevant pieces) - this is a single "order", there are many of these.

"orders" : {
    "elements": [1]
        0: {
            "currency" : "EUR"
            "lineItems": {
                "elements": [2]
                    0:  {
                        "item": {
                                "code": "ASDFXCVDGRRGTG"
                            }-
                        "name": "Caesar Salad"
                        "price": 400
                    },
                    1:  {
                        "item": {
                                "code": "QWEWERRTERTT"
                            }-
                        "name": "Crafty Beer"
                        "price": 100
                    }
            }
            "createdTime": 1453386417000      
    }
}

EDIT2 - changed 'id' to 'code' to avoid confusion between numeric and non-numeric arrays

回答1:

The outer part of your loop looks like it should work for this. You just need to make a couple of changes to how it is building the grouped array.

foreach ($orders as $order) {
    foreach ($order['lineItems']['elements'] as $item) {
        // use the item id as a key in the array you are building
        $id = $item['item']['id'];

        if (isset($products[$id])) {
            // if the item has already been added, increment the count
            $products[$id]['Count']++;
        } else {
            // otherwise, add the item with an initial count of 1
            $products[$id]['ID'] = $id;
            $products[$id]['Item'] = $item['name'];
            $products[$id]['Count'] = 1;
        }
    }
}

The resulting $products array will have item IDs as keys. If you want it to have numeric keys instead, you can then do:

$products = array_values($products);


回答2:

You want counts by id. Use a separate array, keyed by id to do this.

$itemCounts = array();
foreach($products as $product)
{
    if (!isset($itemCounts[$product['code']]))
    {
        $itemCounts[$product['code']] = 0;
    }
    $itemCounts[$product['code']]++;
}
print_r($itemCounts);

If you want, you can get everything in a single array, still keyed by ID:

$itemCounts = array();
foreach($products as $product)
{
    if (!isset($itemCounts[$product['code']]))
    {
        $itemCounts[$product['code']] = array(
            'name' => $product['name'],
            'count' => 0
        );
    }
    $itemCounts[$product['code']]['count']++;
}
print_r($itemCounts);

You can optimize this by not creating $products at all. Replace $products in my code above with the corresponding item from the original $orders array.

EDIT

The code snippets above give you the correct array structure to handle this type of data. To produce your exact desired output from the second code snippet above, you'd want to do something like this:

foreach($itemCounts as $code => $item)
{
    print $code . " " . $item['name'] . " " . $item['count'] . "\n";
}