0

I have $row which outputs the below. Array 0 - 4 do not change per user but the last items in each array need to be added together.

array (
  0 => '2',
  1 => 'Joe',
  2 => 'Bloggs',
  3 => '[email protected]',
  4 => '1,2',
  5 => 1,
  6 => 0,
  7 => 1,
)array (
  0 => '2',
  1 => 'Joe',
  2 => 'Bloggs',
  3 => '[email protected]',
  4 => '1,2',
  5 => 0,
  6 => 1,
  7 => 1,
)array (
  0 => '1',
  1 => 'Jane',
  2 => 'Doe',
  3 => '[email protected]',
  4 => '1,4',
  5 => 1,
  6 => 0,
  7 => 1,
)array (
  0 => '1',
  1 => 'Jane',
  2 => 'Doe',
  3 => '[email protected]',
  4 => '1,4',
  5 => 0,
  6 => 0,
  7 => 0,
)

I need to combine them so they are like this:

Array
(
    [0] => 2
    [1] => Joe
    [2] => Bloggs
    [3] => [email protected]
    [4] => 1,2
    [5] => 1
    [6] => 1
    [7] => 2
)
Array
(
    [0] => 1
    [1] => Jane
    [2] => Doe
    [3] => [email protected]
    [4] => 1,4
    [5] => 1
    [6] => 0
    [7] => 1
)

My code so far is:

$combined = array();
foreach ($row as $item) {
    if (!array_key_exists($item[0], $combined)) {
        $combined[$item[0]] = $item;
    } else {
        
        array_push($combined, $item);
    }   
}

But this is not doing what I expect.

8
  • Does this answer your question? PHP get the last 3 elements of an array Commented Nov 11, 2020 at 13:41
  • @BurhanKashour That is not what the OP is asking. Commented Nov 11, 2020 at 13:46
  • @Fazberry Your solution doesn't even try to sum up the values, you just keep replacing the item with the latest one. Also, when you do array_push, the element is inserted at the next available index. Your check is based on the index being the same as the user's id. If you want to go that way, then scrap the push and insert manually at the desired index (basically, your if branch contents should be in the else branch, and the if branch should do the addition). Commented Nov 11, 2020 at 13:51
  • @FazBerry can you paste your array here instead of that printed so we can easily plug it Commented Nov 11, 2020 at 14:08
  • @jerson not quite sure what you mean. Commented Nov 11, 2020 at 14:10

3 Answers 3

1

You were very close. You simply needed to add the values.

/**
 * @param array $combined       the combined array
 * @param array $item           a single row of data (8-element array)
 *
 * @returns array               the updated combined array
 */
function combineArray(array $combined, array $item) {
    // This is how we know whether the element exists or not
    $key = $item[0];
    if (!array_key_exists($key, $combined)) {
        // This is a NEW item, so just add it to the combined array.
        $combined[$key] = $item;
    } else {
        // This already exists. Modify the required columns.
        $combined[$key][5] += $item[5];
        $combined[$key][6] += $item[6];
        $combined[$key][7] += $item[7];
        /*
           You could also do this automatically from the type of variable, instead of specifying 5, 6 and 7:
           foreach ($item as $i => $value) {
               if (in_array(gettype($value), array('integer', 'float'))) {
                   $combined[$key][$i] += $value;
               }
           }
        */
    }   

    return $combined;
}

$combined = array();

foreach ($row as $item) {
    $combined = combineArray($combined, $item);
}
// Now convert to "true" array. This is VERY IMPORTANT if you want to output
// it to, say, JSON, where [ 0 => 'a', 1 => 'b' ] and [ 0 => 'a', 2 => 'b' ]
// are two different KINDS of object (the first an array, the second a dict)

$combined = array_values($combined);

or also (to show the call with a single row):

$item = array (
  0 => '2',
  1 => 'Joe',
  2 => 'Bloggs',
  3 => '[email protected]',
  4 => '1,2',
  5 => 1,
  6 => 0,
  7 => 1,
);
$combined = combineArray($combined, $item);

The loop version works as expected with the following data:

$row = array(
array (
  0 => '2',
  1 => 'Joe',
  2 => 'Bloggs',
  3 => '[email protected]',
  4 => '1,2',
  5 => 1,
  6 => 0,
  7 => 1,
),array (
  0 => '2',
  1 => 'Joe',
  2 => 'Bloggs',
  3 => '[email protected]',
  4 => '1,2',
  5 => 0,
  6 => 1,
  7 => 1,
),array (
  0 => '1',
  1 => 'Jane',
  2 => 'Doe',
  3 => '[email protected]',
  4 => '1,4',
  5 => 1,
  6 => 0,
  7 => 1,
),array (
  0 => '1',
  1 => 'Jane',
  2 => 'Doe',
  3 => '[email protected]',
  4 => '1,4',
  5 => 0,
  6 => 0,
  7 => 0,
));

and outputs:

Array
(
    [0] => Array
        (
            [0] => 2
            [1] => Joe
            [2] => Bloggs
            [3] => [email protected]
            [4] => 1,2
            [5] => 1
            [6] => 1
            [7] => 2
        )

    [1] => Array
        (
            [0] => 1
            [1] => Jane
            [2] => Doe
            [3] => [email protected]
            [4] => 1,4
            [5] => 1
            [6] => 0
            [7] => 1
        )

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

2 Comments

Hi thanks for your input. This didn't work for me. I got a fatal error: Error: Cannot use assign-op operators with string offsets in. I guess it's trying to add a string
@Fazberry my code works correctly with the data you supplied (I had tested it). If different data yields different results, you should post the data that you're actually using. Could it be that you're using $row to indicate a single component array instead of $item?
0

This works for me.

$res = array();

foreach($array as $vals){
    if(($index = array_search($vals[0], array_column( $res, 0))) !== false) {
        $res[$index][5] += $vals[5];
        $res[$index][6] += $vals[6];
        $res[$index][7] += $vals[7];
    } else {
        $res[] = $vals;
    }
}

print_r($res);

Output with:

Array
(
    [0] => Array
        (
            [0] => 2
            [1] => Joe
            [2] => Bloggs
            [3] => [email protected]
            [4] => 1,2
            [5] => 1
            [6] => 1
            [7] => 2
        )

    [1] => Array
        (
            [0] => 1
            [1] => Jane
            [2] => Doe
            [3] => [email protected]
            [4] => 1,4
            [5] => 1
            [6] => 0
            [7] => 1
        )

)

Comments

0

How about that?

$rows = array(
        array (
            0 => '2',
            1 => 'Joe',
            2 => 'Bloggs',
            3 => '[email protected]',
            4 => '1,2',
            5 => 1,
            6 => 0,
            7 => 1,
        ),
        array (
            0 => '2',
            1 => 'Joe',
            2 => 'Bloggs',
            3 => '[email protected]',
            4 => '1,2',
            5 => 0,
            6 => 1,
            7 => 1,
        ),
        array (
            0 => '1',
            1 => 'Jane',
            2 => 'Doe',
            3 => '[email protected]',
            4 => '1,4',
            5 => 1,
            6 => 0,
            7 => 1,
        ),
        array (
            0 => '1',
            1 => 'Jane',
            2 => 'Doe',
            3 => '[email protected]',
            4 => '1,4',
            5 => 0,
            6 => 0,
            7 => 0,
        ));

foreach ($rows as $row) {

    if (isset($t[$row[3]])) {

        $t[$row[3]][5] += $row[5];
        $t[$row[3]][6] += $row[6];
        $t[$row[3]][7] += $row[7];
    } else 
        $t[$row[3]] = $row;
}

foreach ($t as $r) $combined[] = $r;

print_r($combined);

3 Comments

the problem is that the email or column 3 will be the key
ok then fill it in another array `foreach ($combined as $r) $without[] = $r;
I've edit now my answer. If it does what you want. Please consider accepting. Thank you

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.