2016-08-10 3 views
2

Как сгруппировать массив по 'tax'and' concept 'и атрибуту SUM' val '?Групповые объекты массива по свойствам

Я ищу для создания единого объекта, когда налог и концепция одинаковы, также SUM val.

Я пробовал простую проверку и проверку внутри, но не работает.

спасибо.

echo json_encode($array); 

Массив печати

[ 
{ 
    "tax": "10", 
    "concept": "TUC", 
    "val": "10" 
}, 
{ 
    "tax": "10", 
    "concept": "TUC", 
    "val": "86" 
}, 
{ 
    "tax": "15", 
    "concept": "TUC", 
    "val": "8" 
}, 
{ 
    "tax": "11", 
    "concept": "IPS", 
    "val": "6" 
}, 
{ 
    "tax": "11", 
    "concept": "IPS", 
    "val": "45" 
} 
] 

Ожидаемый результат

[ 
{ 
    "tax": "10", 
    "concept": "TUC", 
    "val": "96" 
}, 
{ 
    "tax": "15", 
    "concept": "TUC", 
    "val": "8" 
}, 
{ 
    "tax": "11", 
    "concept": "IPS", 
    "val": "51" 
} 
] 
+3

* Я пробовал с простыми foreach и проверкой внутри, но не работает. * - покажите свой код – splash58

ответ

3

Вы можете использовать array_reduce() здесь. Вы будете использовать значение tax в качестве ключа, на котором вы группируетесь, и уменьшите массив до уникальных элементов tax, одновременно произведя сумму значений val. Единственное предостережение с этим подходом заключается в том, что преобразование его в JSON заставит PHP думать, что внешний элемент - это объект, а не массив (хотя это массив, это потому, что мы закончили использование индексации по умолчанию, отличного от стандартного). Но это легко смягчить с помощью вызова array_values().

$array = // your array from above 
$result = array_reduce($array, function($carry, $item) { 
    if(!isset($carry[$item->tax])) { 
     $carry[$item->tax] = $item; 
    } else { 
     $carry[$item->tax]->val += $item->val; 
    } 
    return $carry; 
}); 

$result = array_values($result); 

echo json_encode($result); 

Вы можете видеть из this demo, что она производит:

[{ 
    "tax": "10", 
    "concept": "TUC", 
    "val": 96 
}, { 
    "tax": "15", 
    "concept": "TUC", 
    "val": "8" 
}, { 
    "tax": "11", 
    "concept": "IPS", 
    "val": 51 
}] 
+0

Не работает для меня, плюс, вы рассматриваете значение 'tax' как ключ. OP хочет группировать, когда ** оба ** «налог» и «концепция» одинаковы, поэтому ключ должен быть комбинацией этих двух. –

+1

@VicenteOlivertRiera - Вот почему есть демонстрационная ссылка, чтобы попробовать и посмотреть, что она работает. Кроме того, данные OP не имеют каких-либо значений, в которых этот ключ был бы необходим (когда налог соответствует другому элементу, так же как и его концепция), но это простая модификация, которая может быть предоставлена ​​OP для реализации. – nickb

0

Первой группы объекты:

$groups = []; 
foreach($array as $object){ 
    $groups[$object->tax . "\0" . $object->concept] = $object; 
    // I use the NUL byte to delimit, assuming it is absent in $tax and $concept 
} 

Затем карта каждой группы в суммированном вверх объект.

$output = array_map(function(array $group){ 
    $object = new stdClass; 
    $object->tax = $group[0]->tax; 
    $object->concept = $group[0]->concept; 
    $object->val = array_reduce($group, function($carry, $item){ 
     return $carry + $item->val; 
    }, 0); 
    return $object; 
}, $groups); 
0

Добавить все «Вал» с до, где налоговые и концептуальные свойства двух объектов равны и установить свойство «ВАЛ» на этот номер для каждого из этих объектов.

В псевдокоде это будет что-то вроде ..

//Loop through all elements of array starting at 0 
    //InnerLoop through all elements of array starting at 0 
     //test if outer and inner object have equivalent tax and concept properties (and aren't the same location) 
      //if so then add inner loop object's val to outer loop object's val 

В конце этого просто удалить дубликаты в массив, это будет выглядеть примерно так ..

//Loop through all elements of array starting at the end and going to 0 
    //InnerLoop through all elements of array starting at 1 less than outer loop going to 0 
     //test if inner and outer loop object's have equal tax and concept properties 
      //if so then delete the object at the inner loops location 
0
<?php 
$arr_str = '[ 
    {"tax":"10", "concept":"TUC", "val":"10"}, 
    {"tax":"10", "concept":"TUC", "val":"86"}, 
    {"tax":"15", "concept":"TUC", "val":"8"}, 
    {"tax":"11", "concept":"IPS", "val":"6"}, 
    {"tax":"11", "concept":"IPS", "val":"45"} 
]'; 

$arr = json_decode($arr_str); 

$tmp_array = []; 

foreach ($arr as $e) { 
    // combine "tax" and "concept" so we can use both of them as key. Use "_" as delimiter. 
    $key = $e->tax . "_" . $e->concept; 
    // sum the "val" if the key exists, otherwise assign it 
    isset($tmp_array[$key]) ? $tmp_array[$key] += $e->val : $tmp_array[$key] = $e->val; 
} 

$grouped_array = []; 

foreach ($tmp_array as $k => $v) { 
    // ungroup the key so we can create an array like the original one 
    $tmp = explode("_", $k); 
    $grouped_array[] = (object)["tax" => $tmp[0], "concept" => $tmp[1], "val" => $v]; 
} 

echo json_encode($grouped_array); 
?> 
1
$array // Your array 
$result = []; 

array_walk($array, function($object) use (&$result) { 
    $notExist = true; 
    foreach ($result as $item) { 
     if ($item->tax == $object->tax && $item->concept == $object->concept) { 
      $item->val += $object->val; 
      $notExist = false; 
      break; 
     } 
    } 
    if ($notExist) { 
     array_push($result, $object); 
    } 
}); 

echo json_encode($result);