2

Inside a laravel blade template, I am trying to reduce an array like this:

$longList = [['box' => 1, 'kg' => 2], ['box' => 2, 'kg' => 2], ['box' => 3, 'kg' => 3]];

into something like this: $reducedList = [['count' => 2, 'kg' => 2], ['count' => 1, 'kg' => 3]];

This is what I have so far:

@php
          $variableWeights = isset($sale->variable_weight_json) ? collect(json_decode($sale->variable_weight_json, true)) : null;
          $groups = array();

          if (isset($variableWeights)) {
            $groups = $variableWeights->reduce(function($carry, $item) {
              $index = array_search($item['kg'], array_column($carry, 'weight'));
              if (isset($index)) {
                $existing = $carry[$index];
                array_splice($carry, $index, 1, [
                  'count' => $existing['count'] + 1,
                  'weight' => $item['kg']
                ]);
              } else {
                array_push($carry, [
                  'count' => 1,
                  'weight' => $item['kg'],
                ]);
              }
              return $carry;
            }, array());
          }
        @endphp

But it is giving me the error Undefined offset: 0

I am new to php. How should the code be corrected or is there a better approach to achieve the desired result?

5 Answers 5

2

Why dont you reduce it to something simpler like this

$reducedList = [2 => 2, 3 => 1]

where the weight is the index and the value is the count.

$reducedList = [];
foreach ($longList as $box) {
    if (isset($reducedList[$box['kg']]) {
        $reducedList[$box['kg']]++;
    } else {
        $reducedList[$box['kg']] = 1;
    }
}

This way you avoid complexity but you still get the same amount of information.

Sign up to request clarification or add additional context in comments.

Comments

1

I guess you can achieve it with code like:

$longList = [['box' => 1, 'kg' => 2], ['box' => 2, 'kg' => 2], ['box' => 3, 'kg' => 3]];

$reducedList = array_values(array_reduce(
    $longList,
    function($carry, $item) {
        if (isset($carry[$item['kg']])) {
            ++$carry[$item['kg']]['count'];
        } else {
            $carry[$item['kg']] = ['count' => 1, 'kg' => $item['kg']];
        }

        return $carry;
    },
    []
));

print_r($reducedList);

Here is a working example.

Comments

1

don't use isset() function. it checks only variable existing. use empty() or other condition, it will check variable existing and value. try this.

@php
          $variableWeights = isset($sale->variable_weight_json) ? collect(json_decode($sale->variable_weight_json, true)) : null;
          $groups = array();

          if ($variableWeights->isNotEmpty()) {
            $groups = $variableWeights->reduce(function($carry, $item) {
              $index = array_search($item['kg'], array_column($carry, 'weight'));
              if ($index != false ) {
                $existing = $carry[$index]?: false;
                if ($existing) {
                   array_splice($carry, $index, 1, [
                     'count' => $existing['count'] + 1,
                     'weight' => $item['kg']
                   ]);
                }
              } else {
                array_push($carry, [
                  'count' => 1,
                  'weight' => $item['kg'],
                ]);
              }
              return $carry;
            }, array());
          }
        @endphp

1 Comment

$index can have the value 0 and be valid. isset() or empty wont change much.
1

You can use the sexy countBy() method (combined with the famous map() one) of the Collection class.

Try this:

$longList = [['box' => 1, 'kg' => 2], ['box' => 2, 'kg' => 2], ['box' => 3, 'kg' => 3]];

$shortList = collect($longList)
    ->countBy('kg')
    ->map(function ($count, $kg) {
        return [
            'kg' => $kg, 
            'count' => $count,
        ];
    });

With that, you'll get this:

dd($shortList);
=> Illuminate\Support\Collection {#3380
     all: [
       2 => [
         "kg" => 2,
         "count" => 2,
       ],
       3 => [
         "kg" => 3,
         "count" => 1,
       ],
     ],
   }

Here you have a working demo.

Comments

0

isset checks if variable is set (i.e it exists and not NULL). As I (and core developers) can hardly imagine in which cases array_search can return NULL, there's a manual which says:

Returns the key for needle if it is found in the array, FALSE otherwise.

So, you need to check if $index is not false:

$index = array_search($item['kg'], array_column($carry, 'weight'));
// Note that I use `!==` because using `!=` will convert 
// `0` index to false, which is not correct in your case
if (false !== $index) {

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.