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 ( 
[0] => Array ( [0] => 18 [1] => 1,07 ) 
[1] => Array ( [0] =>  8 [1] => 0,44 ) 
[2] => Array ( [0] =>  8 [1] => 0,67 ) 
[3] => Array ( [0] => 18 [1] => 0,55 ) 
[4] => Array ( [0] => 18 [1] => 0,19 ) 
[5] => Array ( [0] =>  8 [1] => 0,48 ) 
[6] => Array ( [0] => 18 [1] => 2,59 ) 
[7] => Array ( [0] =>  8 [1] => 0,15 ) 
[8] => Array ( [0] => 18 [1] => 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

 Answers

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] ] = 0;
}

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

?>

Output of $data_summ:

Array
(
    [8] => 1.74
    [18] => 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);

    //do your styling  on $nonIdenticalProducts

} 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
(
    [0] => product_1
    [1] => product_2
    [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);

    //do your styling

    $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 {
    echo "All fields in all products are the same." . PHP_EOL;
}

Output

for identical:

All fields in all products are the same.

for non identical:

Fields that are non identical:
Array
(
    [0] => price
    [1] => manufacturer
)
Non Identical fields styling is:
Array
(
    [price] => style="background-color: lightblue;"
    [manufacturer] => style="background-color: lightblue;"
)
Wednesday, December 7, 2022
 
sparr
 
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
 
Only authorized users can answer the search term. Please sign in first, or register a free account.
Not the answer you're looking for? Browse other questions tagged :