Compare array values with others values from the same array

余生长醉 提交于 2020-01-01 09:16:45

问题


What I’m trying to achieve is that, it will loop trough the array. Then it will look if the items in the array are the same on three points: product_id, the size value and the color value. I want to create a new array where the items are listed, the only thing I don’t want is the duplicated values. I want that the duplicated values if they are the same on those three points that the quantity will be count together. Like if I have 3 items same product id same size and same color and both of the three I ordered 3 items in my new array this is just standing 1 time and the quantity will be 9. So there will be no duplicated values in my new array.

Current loop

foreach($orders as $key => $order){
            foreach($order['orderProducts'] as $key => $value){
                echo '<pre>';
                print_r($value['attributes']);
                echo '</pre>';
            }
 }

results in the the following array

Array
(
    [id] => 2
    [product_id] => 4
    [order_id] => 2
    [name] => swag3
    [description] => haha
    [price] => 19.95
    [proceeds] => 10.00
    [quantity] => 2
    [attributes] => [{"id":1,"name":"Size","value":"XS","active":1},{"id":8,"name":"Color","value":"Wit","active":1}]
)
Array
(
    [id] => 3
    [product_id] => 3
    [order_id] => 3
    [name] => swag2
    [description] => lol
    [price] => 19.95
    [proceeds] => 10.00
    [quantity] => 2
    [attributes] => [{"id":2,"name":"Size","value":"S","active":1},{"id":7,"name":"Color","value":"Zwart","active":1}]
)
Array
(
    [id] => 4
    [product_id] => 3
    [order_id] => 4
    [name] => swag2
    [description] => lol
    [price] => 19.95
    [proceeds] => 10.00
    [quantity] => 1
    [attributes] => [{"id":2,"name":"Size","value":"S","active":1},{"id":7,"name":"Color","value":"Zwart","active":1}]
)

Sort of what I’m looking for..

Array
(
    [id] => 2
    [product_id] => 4
    [order_id] => 2
    [name] => swag3
    [description] => haha
    [price] => 19.95
    [proceeds] => 10.00
    [quantity] => 2
    [attributes] => [{"id":1,"name":"Size","value":"XS","active":1},{"id":8,"name":"Color","value":"Wit","active":1}]
)
Array
(
    [id] => 3
    [product_id] => 3
    [order_id] => 3
    [name] => swag2
    [description] => lol
    [price] => 19.95
    [proceeds] => 10.00
    [quantity] => 3
    [attributes] => [{"id":2,"name":"Size","value":"S","active":1},{"id":7,"name":"Color","value":"Zwart","active":1}]
)

Solution Note it's blade php as frontend.

Backend

$order // is the array with products
$items = [];
foreach($orders as $key => $order){
    foreach($order['orderProducts'] as $op){
        $i = [
        'product'=> Product::findOrFail($op->product_id)->toArray(),
        'attributes' =>$op->attributes,
        'quantity'=>$op->quantity
        ];
        $matchedResult = false;
        $count = count($items);
        for($a = 0; $a < $count; $a++){
            // Items with the same product_id in the $item array
            if($items[$a]['product']['id'] == $i['product']['id']){
                //check if the attributes are also the same
                if($items[$a]['attributes'] === $i['attributes']){
                    // The attributes ar ethe same so up the quantity
                    $items[$a]['quantity'] += $i['quantity'];
                    $matchedResult = true;
                    continue; // If its right there are no other matches
                }
            }
        }
        if($matchedResult === false){
            // only push item if there is not a match.
            $items[] = $i;
        }
    }
}

Frontend

<div class="table-responsive">
  <table class="table table-striped">
    <thead>
      <tr>
        <th>Product</th>
        <th>quantity</th>
      </tr>
    </thead>
    <tbody>
    @foreach($items as $item)
    <tr>
      <td>{{$item['product']['name']}}
      @if(count($item['attributes']) > 0) <small>
      @foreach($item['attributes'] as $att)
      {{$att['name']}} - {{$att['value']}}
      @endforeach
      </small>
      @endif</td>
      <td>{{$item['quantity']}}</td>
    </tr>
    @endforeach
    </tbody>
  </table>
</div>

回答1:


You can achieve your goal without using nested loops. You may use hash function of product_id, size and color parameters and use that value as a new array key like this:

$orders = // original array;
$newOrders = [];     // new array

foreach($orders as $order) {
    $pi = $order["product_id"];                // get product_id
    $attr = json_decode($order["attributes"]); // get attributes:
    $size = $attr[0]->value;                   // get size value
    $color = $attr[1]->Color;                  // get color

    $hash = sprintf("%s.%s.%s", $pi, $size, $color); // Calculate hash

    if ($newOrders[$hash]) {
        $newOrders[$hash].quantity++; // If hash is already present then just increase quantity
    } else {
        // Otherwise add new order
        $newOrders[$hash] = [
            "order" => $order,
            "quantity" => 1
        ];
    }
}



回答2:


I hope this can help you:

        $sortedArray = [];
        foreach ($order as $array) {
            $tag = getTag($array);
            push_to_array($sortedArray,$array,$tag);
        }



        function push_to_array(&$array1,$array2,$tag)
        {
            isset($array1[$tag]) ? $array1[$tag]['quantity'] += $array2['quantity'] : $array1[$tag] = $array2;
        }
        function getTag($array)
        {
            $attribs = json_decode($array['attributes'],true);
            foreach ($attribs as $value) {
                ($value['name'] =='Size' ) && $size = $value['value'];
                ($value['name'] =='Color') && $color= $value['value'];
            }
            return $array['product_id'].$size.$color;
        }



回答3:


Try this (untested but logic should be correct):

$orders = // original array;
$new;     // new array

foreach($orders as $order) {
    $pi = $order["product_id"];                // get product_id
    $attr = json_decode($order["attributes"]); // get attributes:
    $size = $attr[0]->value;                   // get size value
    $color = $attr[1]->Color;                  // get color
    $duplicate = false;
    foreach($newOrders as $newOrder() {        // loop through nested array
        $newPi = $newOrder["product_id"];
        $newAttr = json_decode($newOrder["attributes"]);
        $newSize = $newAttr[0]->value;
        $newValue = $newAttr[1]->Color;

        // check to see if same
        if(
            $pi == $newPi &&
            $size == $newSize &&
            $color == $newColor
        ) {
            $newOrders["quantity"]++;
            $duplicate = true;
            break;
        }
    }
    if(!$duplicate) {
        $new[] = $order;
    }
}

Edit: Sorry, I just reread your post and saw you don't want a full solution. Sorry. But I hope this can show you that nested loops are the way to go with this. As mentioned in the comments, there is no built in function for this in PHP (AFAIK).




回答4:


This is not a solution, but another approach to let you think by Object Oriented Programming
It will helps you a lot in you current and next problems

Now, you have a business case, that it must be resolved in your business layer
I can assist you if you want

<?php

class Attribute {
    private $_id;
    private $_name;
    private $_value;
    private $_active;

    // TODO implement getter and setter 
    // lTODO implement constructor
}

class Product {
    private $_id;
    private $_productId;
    // ... order_id, name, ...
    private $_attribute_a = array(); // it will be an array of attribute's object

    // TODO implement getter and setter 
    // TODO implement constructor

    private function getAttributeByName($name) {
        // loop through attribute array object and return the right attribute
        // foreach ($this->_attribute_a as $attr) {
        //      if ($attr->name === $name) return $attr;
        // }
    }

    public function equals($o) {
        if (!is_a($o, 'Product'))   return FALSE;
        if ($this == $o)            return TRUE ;

        if ($this->_productId === $o->_productId) {
            $attr1 = $this->getAttributeByName('Size');
            $attr2 = $this->getAttributeByName('Size');
            if ($attr1->getValue() !== $attr2->getValue()) return FALSE; 

            $attr1 = $this->getAttributeByName('Color');
            $attr2 = $this->getAttributeByName('Color');
            if ($attr1->getValue() !== $attr2->getValue()) return FALSE; 
            return TRUE;
        }
        return FALSE;
    }
}

Now, you can compare easily 2 Products Object, and later, updating equals() will not affect your code




回答5:


You have some grate answers from other users.

However i would like to post this for Googlers or other users in the planning stage and for your own knowledge.

With your example your using a shopping basket. You should never have duplicate items in the array you should be using a Quantity measure on the item and before adding to your array you check the array if the matching item is there increase the quantity.

as your current way your code is processing though the array after for no good reason if i was to add 20 of the same item your current system would have an array of 20 to loop though every time i opened the basket.

This other method will also provide you will support for people to add multiple quantities of items at once, also on your basket page edit the quantities




回答6:


Please note the assumptions below the code

function combineDuplicates($orders) {
$indexArray = array();
$uniqueArray = array();
foreach($orders as $value) {
    $productID = $value['product_id'];
    $attributes = $value['attributes'];
    foreach($attributes as $attribute) {
        switch($attribute['name']) {
            case 'Size' :   $size = $attribute['value'];
                            break;
            case 'Color':   $color = $attribute['value'];
                            break;
            default : break;
        }
    }
    if (!isset($indexArray[$productID][$size][$color])) {
        $indexArray[$productID][$size][$color]['count'] = 0;
        $uniqueArray[] = $value;
    }
    $indexArray[$productID][$size][$color]['count']++;
}
$orders = array();
foreach($uniqueArray as $key => $value) {
    $productID = $value['product_id'];
    $attributes = $value['attributes'];
    foreach($attributes as $attribute) {
        switch($attribute['name']) {
            case 'Size' :   $size = $attribute['value'];
                            break;
            case 'Color':   $color = $attribute['value'];
                            break;
            default : break;
        }
    }
    $uniqueArray[$key]['quantity'] = $indexArray[$productID][$size][$color]['count'];
}
return $uniqueArray;
}

Assumptions :

  • 'attributes' is converted to associative array
  • product_id, Color & Size values are non-empty in each element


来源:https://stackoverflow.com/questions/33574890/compare-array-values-with-others-values-from-the-same-array

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!