问题
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