# Php Arrays Sum Group By

Viewed   158 times

Possible Duplicate:
php group by SUM using multi dimensional array

I'm working on creating shopping-cart for a wholesale company. And i'll create also invoice later. It's same logic.

Firstly, i multiply paket (package) * paket adeti (package quantity) * fiyat? (price) And i wrote it at the end of list. Now i have to calculate vat. The main problem is we don't know vat ratios exactly before.

May be there exist 3 different vat ratios. (it depends on the products which customer selects) May be one.

I made an array of vats

``````\$vats[] = array(\$row['vat'], \$row['wholesaleprice'] - \$wholesaleprice);
``````

Result is like that

``````Array (
 => Array (  => 18  => 1,07 )
 => Array (  =>  8  => 0,44 )
 => Array (  =>  8  => 0,67 )
 => Array (  => 18  => 0,55 )
 => Array (  => 18  => 0,19 )
 => Array (  =>  8  => 0,48 )
 => Array (  => 18  => 2,59 )
 => Array (  =>  8  => 0,15 )
 => Array (  => 18  => 12,97 )
)
``````

I have to sum vat group by ratios...

And i want to display like

VAT (%18) 136,26 TL VAT (%8) 16,90 TL VAT (%1) 9,28 TL

How can i do that in shortcut. I've check array functions. But i couldn't find anything useful.

Shopping Cart: http://i.stack.imgur.com/DDsCq.png

2

Try something like this:

``````<?php

\$data = Array (
Array ( 0 => '18', 1 => '1,07' ),
Array ( 0 => '8', 1 => '0,44' ),
Array ( 0 => '8', 1 => '0,67' ),
Array ( 0 => '18', 1 => '0,55' ),
Array ( 0 => '18', 1 => '0,19' ),
Array ( 0 => '8', 1 => '0,48' ),
Array ( 0 => '18', 1 => '2,59' ),
Array ( 0 => '8', 1 => '0,15' ),
Array ( 0 => '18', 1 => '12,97' )
);

// predefine array
\$data_summ = array();
foreach ( \$data as \$value ) {
\$data_summ[ \$value ] = 0;
}

foreach ( \$data as \$list ) {
\$number = str_replace( ",", ".", \$list ) * 1;
\$data_summ[ \$list ] += (float)\$number;
}

?>
``````

Output of `\$data_summ`:

``````Array
(
 => 1.74
 => 17.37
)
``````

If I understand you correctly.

Wednesday, December 7, 2022
5

This is the solution I've come up with based off of the understanding that your intended array structure was as so;

``````\$dis = array(
array(
'Dis_id'  => 'Dl-Dis1',
'Dis_per' => 7.500,
'Dis_val' => 192.75
),
...
);
``````

It determines the solution by creating a multidimensional array where the first dimension is the `Dis_id`, and the second dimension is the `Dis_per`, and the value becomes the sum of the `Dis_val`;

``````\$sums = array();

foreach (\$dis as \$entry) {
if (!isset(\$sums[\$entry['Dis_id']])) {
\$sums[\$entry['Dis_id']] = array();
}
if (!isset(\$sums[\$entry['Dis_id']]["{\$entry['Dis_per']}"])) {
\$sums[\$entry['Dis_id']]["{\$entry['Dis_per']}"] = 0;
}
\$sums[\$entry['Dis_id']]["{\$entry['Dis_per']}"] += \$entry['Dis_val'];
}
``````

See this working example; https://eval.in/158661

Wednesday, October 19, 2022
2

I need compare values of the products by each key. To highlight rows in the compare table where price, quantity, availability, or manufacturer is different.

If you want to highlight all products unless all of them have exactly the same price, quantity, availability, or manufacturer.

function:

``````function productsIdentical(array &\$products) : bool
{
if (count(\$products) < 2) {
throw new InvalidArgumentException("You should pass at least 2 products to compare");
}

\$compare = '';
foreach (\$products as \$product) {
ksort(\$product); //to make comparison of key order insensitive
\$sha = sha1(json_encode(\$product));
if (empty(\$compare)) {
\$compare = \$sha;
} elseif (\$sha !== \$compare) {
return false;
}
}
return true;
}
``````

returns `true` only if all products' fields have exactly the same keys and value, otherwise it returns `false`

so you use it this way:

``````\$identicalFlag = productsIdentical(\$all_products);
if (\$identicalFlag === false) {
echo "Products are not identical:" . PHP_EOL;

\$nonIdenticalProductsArr = array_keys(\$all_products);
echo "Non identical products are:" . PHP_EOL;
print_r(\$nonIdenticalProductsArr);

} else {
echo "Products are identical" . PHP_EOL;
}
``````

Output:

for identical products:

``````Products are identical
``````

for non identical:

``````Products are not identical:
Non identical products are:
Array
(
 => product_1
 => product_2
 => product_3
)
``````

Or if you want to detect every product field that is not the same across all products in the array use this function:

``````function getFieldsNonIdentical(array &\$products) : array
{
if (count(\$products) < 2) {
throw new InvalidArgumentException("You should pass at least 2 products to compare");
}

\$compareArr = [];
\$keyDifferentArr = [];
foreach (\$products as \$product) {
foreach(\$product as \$key => \$val) {
if (!key_exists(\$key, \$compareArr)) {
\$compareArr[\$key] = \$val;
} elseif (\$compareArr[\$key] !== \$val) {
\$keyDifferentArr[\$key] = true;
}
}
}
return array_keys(\$keyDifferentArr);
}
``````

this way:

``````\$fieldsNonIdentical = getFieldsNonIdentical(\$all_products);

if (!empty(\$fieldsNonIdentical)) {
echo "Fields that are non identical:" . PHP_EOL;

print_r(\$fieldsNonIdentical);

\$nonIdenticalStyle = 'style="background-color: lightblue;"';
\$styleArr = [];
foreach (\$fieldsNonIdentical as \$key => \$value) {
\$styleArr[\$value] = \$nonIdenticalStyle;
}

echo "Non Identical fields styling is:" . PHP_EOL;
print_r(\$styleArr);
} else {
}
``````

Output

for identical:

``````All fields in all products are the same.
``````

for non identical:

``````Fields that are non identical:
Array
(
 => price
 => manufacturer
)
Non Identical fields styling is:
Array
(
[price] => style="background-color: lightblue;"
[manufacturer] => style="background-color: lightblue;"
)
``````
Wednesday, December 7, 2022
3
``````function searchForId(\$id, \$array) {
foreach (\$array as \$key => \$val) {
if (\$val['uid'] === \$id) {
return \$key;
}
}
return null;
}
``````

This will work. You should call it like this:

``````\$id = searchForId('100', \$userdb);
``````

It is important to know that if you are using `===` operator compared types have to be exactly same, in this example you have to search `string` or just use `==` instead `===`.

Based on angoru answer. In later versions of PHP (`>= 5.5.0`) you can use one-liner.

``````\$key = array_search('100', array_column(\$userdb, 'uid'));
``````

Here is documentation: http://php.net/manual/en/function.array-column.php.

Thursday, December 8, 2022
3

### `UNION ALL`

You could "counter-pivot" with `UNION ALL` first:

``````SELECT name, array_agg(c) AS c_arr
FROM  (
SELECT name, id, 1 AS rnk, col1 AS c FROM tbl
UNION ALL
SELECT name, id, 2, col2 FROM tbl
ORDER  BY name, id, rnk
) sub
GROUP  BY 1;
``````

Adapted to produce the order of values you later requested. The manual:

The aggregate functions `array_agg`, `json_agg`, `string_agg`, and `xmlagg`, as well as similar user-defined aggregate functions, produce meaningfully different result values depending on the order of the input values. This ordering is unspecified by default, but can be controlled by writing an `ORDER BY` clause within the aggregate call, as shown in Section 4.2.7. Alternatively, supplying the input values from a sorted subquery will usually work.

Bold emphasis mine.

### `LATERAL` subquery with `VALUES` expression

`LATERAL` requires Postgres 9.3 or later.

``````SELECT t.name, array_agg(c) AS c_arr
FROM  (SELECT * FROM tbl ORDER BY name, id) t
CROSS  JOIN LATERAL (VALUES (t.col1), (t.col2)) v(c)
GROUP  BY 1;
``````

Same result. Only needs a single pass over the table.

### Custom aggregate function

Or you could create a custom aggregate function like discussed in these related answers:

• Selecting data into a Postgres array
• Is there something like a zip() function in PostgreSQL that combines two arrays?
``````CREATE AGGREGATE array_agg_mult (anyarray)  (
SFUNC     = array_cat
, STYPE     = anyarray
, INITCOND  = '{}'
);
``````

Then you can:

``````SELECT name, array_agg_mult(ARRAY[col1, col2] ORDER BY id) AS c_arr
FROM   tbl
GROUP  BY 1
ORDER  BY 1;
``````

Or, typically faster, while not standard SQL:

``````SELECT name, array_agg_mult(ARRAY[col1, col2]) AS c_arr
FROM  (SELECT * FROM tbl ORDER BY name, id) t
GROUP  BY 1;
``````

The added `ORDER BY id` (which can be appended to such aggregate functions) guarantees your desired result:

``````a | {1,2,3,4}
b | {5,6,7,8}
``````

Or you might be interested in this alternative:

``````SELECT name, array_agg_mult(ARRAY[ARRAY[col1, col2]] ORDER BY id) AS c_arr
FROM   tbl
GROUP  BY 1
ORDER  BY 1;
``````

Which produces 2-dimensional arrays:

``````a | {{1,2},{3,4}}
b | {{5,6},{7,8}}
``````

The last one can be replaced (and should be, as it's faster!) with the built-in `array_agg()` in Postgres 9.5 or later - with its added capability of aggregating arrays:

``````SELECT name, array_agg(ARRAY[col1, col2] ORDER BY id) AS c_arr
FROM   tbl
GROUP  BY 1
ORDER  BY 1;
``````

Same result. The manual:

input arrays concatenated into array of one higher dimension (inputs must all have same dimensionality, and cannot be empty or null)

So not exactly the same as our custom aggregate function `array_agg_mult()`;

Saturday, November 12, 2022