Viewed   87 times

I got a multidimensional array like this:

Totalarray
(
[0] => Array
    (
        [city] => NewYork
        [cash] => 1000
    )

[1] => Array
    (
        [city] => Philadelphia
        [cash] => 2300
    )

[2] => Array
    (
        [city] => NewYork
        [cash] => 2000
    )
)

and I'd like to sum the value [cash] of the sub-arrays who got the same value[city] and obtain an array like this:

Totalarray
(
[0] => Array
    (
        [city] => NewYork
        [cash] => 3000
    )

[1] => Array
    (
        [city] => Philadelphia
        [cash] => 2300
    )
)

How can I do it?

 Answers

2

Try below code:

<?php

$arr = array(
        array('city' => 'NewYork', 'cash' => '1000'),
        array('city' => 'Philadelphia', 'cash' => '2300'),
        array('city' => 'NewYork', 'cash' => '2000'),
    );

$newarray = array();
foreach($arr as $ar)
{
    foreach($ar as $k => $v)
    {
        if(array_key_exists($v, $newarray))
            $newarray[$v]['cash'] = $newarray[$v]['cash'] + $ar['cash'];
        else if($k == 'city')
            $newarray[$v] = $ar;
    }
}

print_r($newarray);


Output:

Array
(
    [NewYork] => Array
        (
            [city] => NewYork
            [cash] => 3000
        )

    [Philadelphia] => Array
        (
            [city] => Philadelphia
            [cash] => 2300
        )

)


Demo:
http://3v4l.org/D8PME

Saturday, August 6, 2022
4

You need to iterate over your results, adding a new entry to the output when you encounter a new team, or updating the points value when you find the same team again. This is most easily done by initially indexing the output by the team name, and then using array_values to re-index the array numerically:

$teams = array();
foreach ($results as $result) {
    $team = $result['team'];
    if (!isset($teams[$team])) {
        $teams[$team] = array('team' => $team, 'points' => $result['punti']);
    }
    else {
        $teams[$team]['points'] += $result['punti'];
    }
}
$teams = array_values($teams);
print_r($teams);

Output (for your sample data):

Array
(
    [0] => Array
        (
            [team] => Red Bull Racing
            [points] => 418
        )
    [1] => Array
        (
            [team] => Scuderia Ferrari
            [points] => 353
        )
    [2] => Array
        (
            [team] => Mercedes-AMG
            [points] => 516
        )
    [3] => Array
        (
            [team] => Racing Point F1
            [points] => 147
        )
    [4] => Array
        (
            [team] => Haas F1
            [points] => 127
        )
)

Demo on 3v4l.org

Friday, August 12, 2022
 
4

If you absolutely have to do this in PHP, then something like:

$data = array(
    array(
        'shelf' => 'Left',
        'weight' => '10.000',
        'piece' => 1,
    ),
    array(
        'shelf' => 'Right',
        'weight' => '04.000',
        'piece' => 12,
    ),
    array(
        'shelf' => 'Right',
        'weight' => '04.000',
        'piece' => 4,
    ),
    array(
        'shelf' => 'Right',
        'weight' => '07.000',
        'piece' => 8,
    ),
);


$newData = array();
$result = array_reduce(
    $data,
    function($newData, $value) {
        $key = $value['shelf'].$value['weight'];
        if (!isset($newData[$key])) {
            $newData[$key] = $value;
        } else {
            $newData[$key]['piece'] += $value['piece'];
        }
        return $newData;
    },
    $newData
);
var_dump($result);

will work, but I really do believe that you're creating major performance problems for yourself with your whole approach to this problem

Friday, August 5, 2022
 
4

Simply you can write a function like this with recursion

function arrSum(arr) {
  var sum = 0;
  // iterate array using forEach, better to use for loop since it have higher performance
  arr.forEach(function(v) {
    // checking array element is an array
    if (typeof v == 'object')
      // if array then getting sum it's element (recursion)
      sum += arrSum(v);
    else
      // else adding the value with sum
      sum += v
  })
  // returning the result
  return sum;
}

console.log(arrSum([2, 5, [4, 6], 5]) === 22);

Using for loop

function arrSum(arr) {
  var sum = 0;
  for (var i = 0; i < arr.length; i++) {
    if (typeof arr[i] == 'object')
      sum += arrSum(arr[i]);
    else
      sum += arr[i];
  }
  return sum;
}

console.log(arrSum([2, 5, [4, 6], 5]) === 22);
Tuesday, September 13, 2022
 
2

You can write a generic groupAdjacent function. It has two parameters -

  1. t - the input array
  2. equal - a function to test if elements are considered adjacent
function groupAdjacent(t, equal)
{ function* run (r, q, i)
  { if (i >= t.length)
      return yield [...r, q]
    if (equal(q, t[i]))
      return yield* run([...r, q], t[i], i + 1)
    yield [...r, q]
    yield* run([], t[i], i + 1)
  }
  return t.length
    ? Array.from(run([], t[0], 1))
    : [] 
}

Next we define two functions specific to your particular teams data -

  1. teamAdjacent - determines what makes a team adjacency
  2. teamSort - compares two teams for sorting
const teamAdjacent = (a, b) =>
  a[1] == b[1] && a[2] == b[2] // w/l is equal

const teamSort = (a, b) =>
  a[3] - b[3]                  // sort by sortKey, ascending

Finally we tie everything together. groupAdjacent creates an array of groups, then we .sort each group, and lastly call .flat to return an un-grouped result -

const result =
  groupAdjacent(teams, teamAdjacent)
    .map(_ => _.sort(teamSort))
    .flat()

console.log(result)
['Team A', 25, 2, 88]
['Team D', 20, 7, 54]
['Team E', 20, 7, 65]
['Team C', 20, 7, 76]
['Team B', 20, 7, 84]
['Team F', 20, 6, 34]
['Team G', 19, 8, 67]
['Team H', 20, 7, 11]
['Team N', 3, 24, 33]

Expand the snippet to verify the results in your own browser -

function groupAdjacent(t, equal)
{ function* run (r, q, i)
  { if (i >= t.length)
      return yield [...r, q]
    if (equal(q, t[i]))
      return yield* run([...r, q], t[i], i + 1)
    yield [...r, q]
    yield* run([], t[i], i + 1)
  }
  return t.length
    ? Array.from(run([], t[0], 1))
    : [] 
}

const teamAdjacent = (a, b) =>
  a[1] == b[1] && a[2] == b[2] // w/l is equal

const teamSort = (a, b) =>
  a[3] - b[3]                  // sort by sortKey, ascending

const teams =
  [ ['Team A', 25, 2, 88]
  , ['Team B', 20, 7, 84]
  , ['Team C', 20, 7, 76]
  , ['Team D', 20, 7, 54]
  , ['Team E', 20, 7, 65]
  , ['Team F', 20, 6, 34]
  , ['Team G', 19, 8, 67]
  , ['Team H', 20, 7, 11]
  , ['Team N', 3, 24, 33]
  ]

const result =
  groupAdjacent(teams, teamAdjacent)
    .map(_ => _.sort(teamSort))
    .flat()

console.log(result)

You can write groupAdjacent without recursion too, if you wish -

function* groupAdjacent(t, equal)
{ if (t.length === 0) return
  let g = [t[0]]
  for (const _ of t.slice(1))
    if (equal(_, g[0]))
      g.push(_)
    else
      (yield g, g = [_])
  yield g
}

The only difference with this version is that you must wrap the groupAdjacent call in Array.from -

const result =
  Array.from(groupAdjacent(teams, teamAdjacent))
    .map(_ => _.sort(teamSort))
    .flat()
// => (same output)

related reading

  • Javascript: shuffling groups of objects in an array
  • How can I sort an indirect array with javascript?
  • How should i sort a list inside an object in functional programming with different logic based on different condition?

equivalence

Scott points out the use of .map(fn).flat() is identical to .flatMap(fn)1. I should've noticed this because I don't think I've ever used .flat and this is yet another scenario where it's not necessary -

const result =
  groupAdjacent(teams, teamAdjacent)
    .map(_ => _.sort(teamSort))
    .flat()

Is equivalent to -

const result =
  groupAdjacent(teams, teamAdjacent)
    .flatMap(_ => _.sort(teamSort))

1. Only equivalent when flattening a depth of 1, ie .flat() and .flat(1)

Thursday, November 17, 2022
 
alixb
 
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 :