0

I'm trying to print out shopping cart orders, however, instead of displaying all products from that order I want to group the orders by the order ID so that I can display the sum of the order and link to a detail page.

Instead of this

---------------------------------------
date        order number        total
---------------------------------------
today        1234WEDK             600
---------------------------------------
today        1234WEDK             500
---------------------------------------

I'd like to display this

---------------------------------------
date        order number        total
---------------------------------------
today        1234WEDK            1100
---------------------------------------

Here's a sample array

array:2 [▼
  0 => array:9 [▼
    "id" => 57
    "order_id" => 51
    "order_hash" => "1234WEDK"
    "price" => 600
  ]
  1 => array:9 [▼
    "id" => 58
    "order_id" => 51
    "order_hash" => "1234WEDK"
    "price" => 500
  ]
]
0

2 Answers 2

4
$data = [
  [
    "id" => 57,
    "order_id" => 51,
    "order_hash" => "1234WEDK",
    "price" => 600
  ],
  [
    "id" => 58,
    "order_id" => 51,
    "order_hash" => "1234WEDK",
    "price" => 500
  ],
  [
    "id" => 59,
    "order_id" => 1111,
    "order_hash" => "1234ABCD",
    "price" => 200
  ]
];

$result = array_reduce($data, function($acc, $x) {
  if (!array_key_exists($x['order_hash'], $acc)) {
    $acc[$x['order_hash']] = 0;
  }
  $acc[$x['order_hash']] += $x['price'];
  return $acc;
}, []);

echo json_encode($result, JSON_PRETTY_PRINT), PHP_EOL;

Output

{
    "1234WEDK": 1100,
    "1234ABCD": 200
}

That solution is mostly crap tho because the function is totally tangled up with multiple intentions and responsibilities. It's looking up object properties, grouping, and summing values all in one. Blech.

Functional Programming in PHP can be pretty verbose, but that doesn't mean it should be entirely dismissed.

What if I told you … the entire solution could be reduced to this ?

// your reusable computation
$sumOrdersByHash = comp (map (function($xs) {
  return [
    'hash' => prop ('order_hash') (head ($xs)),
    'sum'  => sum (map (prop('price')) ($xs))
  ];
})) (group_by (prop ('order_hash')));

// run computation
$result = $sumOrdersByHash($data);

All you need are these reusable prerequisites. Bwahahahaha …

function id ($x) { return $x; }
function head ($xs) { return $xs[0]; }
function tail ($xs) { return array_slice($xs, 1); }

function foldl (callable $f) {
  return function ($acc) use ($f) {
    return function ($xs) use ($f, $acc) {
      if (empty($xs))
        return $acc;
      else
        return foldl ($f) (call_user_func($f, $acc, head($xs))) (tail ($xs));
    };
  };
}

function map (callable $f) {
  return foldl (function ($acc, $x) use ($f) {
    return array_merge($acc, [call_user_func($f, $x)]);
  }) ([]);
}

function sum ($xs) {
  return foldl (function ($x, $y) { return $x + $y; }) (0) ($xs);
}

function prop ($k) {
  return function ($arr) use ($k) {
    return $arr[$k];
  };
};

function group_by (callable $f) {
  return foldl (function ($acc, $x) use ($f) {
    $key = call_user_func($f, $x);
    if (array_key_exists($key, $acc))
      array_push($acc[$key], $x);
    else
      $acc[$key] = [$x];
    return $acc;
  }) ([]);
}

function comp (callable $f) {
  return function (callable $g) use ($f) {
    return function ($x) use ($f, $g) {
      return call_user_func($f, call_user_func($g, $x));
    };
  };
}

Put it all together and here's what you get

$result = $sumOrdersByHash($data);
echo json_encode($result, JSON_PRETTY_PRINT), PHP_EOL;

// =>    
[
    {
        "hash": "1234WEDK",
        "sum": 1100
    },
    {
        "hash": "1234ABCD",
        "sum": 200
    }
]
Sign up to request clarification or add additional context in comments.

6 Comments

Why so difficult? Functions like grouping and summing are much easier and faster using the queries themselves.
@JanWillem I did not make the assumption the user could work with the data from SQL. I worked with the data provided in the question.
@naomik I apologize for not specifying in my original question that I was pulling records. I stated that my mind was fried, and it really was. Thank you for your answer and the great explanation. :)
@timgavin no problem. I would be sad to learn you ended up with anything other than an optimal solution ^_^
Allright, my bad! @naomik also keep in mind, that using Laravel gives you the possibility to use Laravel Collections, which can be used for various array-related mutations.
|
3

Assuming you are getting your data from a database, you should make it to do all the calculations for you

SELECT order_hash, date, sum(price) as total FROM cart GROUP BY order_hash

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.