0

As the title says I get array looking something like this:

array (size=376)
  0 => 
    array (size=3)
      'source' => int 0
      'target' => int 47
      'officers' => 
        array (size=1)
          0 => string 'PARKER, Thomas, Sir' (length=19)
  1 => 
    array (size=3)
      'source' => int 0
      'target' => int 104
      'officers' => 
        array (size=1)
          0 => string 'STEVENS, Anne' (length=13)
  2 => 
    array (size=3)
      'source' => int 0
      'target' => int 187
      'officers' => 
        array (size=1)
          0 => string 'PARKER, Thomas, Sir' (length=19)
  3 => 
    array (size=3)
      'source' => int 0
      'target' => int 229
      'officers' => 
        array (size=1)
          0 => string 'GROTE, Byron' (length=12)
  4 => 
    array (size=3)
      'source' => int 0
      'target' => int 244
      'officers' => 
        array (size=1)
          0 => string 'GROTE, Byron' (length=12)
  5 => 
    array (size=3)
      'source' => int 1
      'target' => int 60
      'officers' => 
        array (size=1)
          0 => string 'BASON, John' (length=11)
  6 => 
    array (size=3)
      'source' => int 1
      'target' => int 92
      'officers' => 
        array (size=1)
          0 => string 'HAUSER, Wolfhart, Dr' (length=20)

If source and target are the same I want to create 1 value in this array for example

Insteed of this:

    5 => 
        array (size=3)
          'source' => int 1
          'target' => int 92
          'officers' => 
            array (size=1)
              0 => string 'BASON, John' (length=11)
      6 => 
        array (size=3)
          'source' => int 1
          'target' => int 92
          'officers' => 
            array (size=1)
              0 => string 'HAUSER, Wolfhart, Dr' (length=20)

I would want to get

5 => 
            array (size=3)
              'source' => int 1
              'target' => int 92
              'officers' => 
                array (size=1)
                  0 => string 'BASON, John' (length=11)
                  1 => string 'HAUSER, Wolfhart, Dr' (length=20)

My idea to achieve this:

for ($i = 0; $i < count($edges); $i++) {
    for ($j = $i + 1; $j < count($edges); $j++) {
        if($edges[$i]['source']==$edges[$j]['source']&&$edges[$i]['target']==$edges[$j]['target']){
            foreach( $edges[$j]['officers'] as $officer){
                array_push($edges[$i]['officers'], $officer);
            }
            array_splice($edges, $j,1);
        }

    }
}

It seems to be merging but only 2 values and it isn't deleting old values so:

I got something like :

 66 => 
    array (size=3)
      'source' => int 24
      'target' => int 103
      'officers' => 
        array (size=2)
          0 => string 'GILAURI, Irakli' (length=15)
          1 => string 'JANIN, Neil' (length=11)
  67 => 
    array (size=3)
      'source' => int 24
      'target' => int 103
      'officers' => 
        array (size=1)
          0 => string 'MORRISON, David' (length=15)

So it merget Gilauri and Janin but didn't add Morrison, David to officers array and also Gilauri, Irakli and Janin, Neil have separate row in this array which shouldn't be added.

2 Answers 2

2

Note that array_splice rekeys the array each time it is executed. From the documentation:

Note that numeric keys in input are not preserved.

I.e. array_splice($array, 1, 1) on $array = [0 => 1, 1 => 2, 2 => 3] will result in [0 => 1, 1 => 3].

Thus when you are iterating with a for loop, your index will point one entry further than before for each removed array element.

To remove by index without rekeying, use unset($edges[$j]) instead of the array_splice().

Alternatively use a foreach loop (by reference to operate on the actual loop and not on a copy):

foreach ($edges as $i => &$edge) {
    for ($j = $i + 1; $j < count($edges); $j++) {
        if ($edge['source'] == $edges[$j]['source'] && $edge['target'] == $edges[$j]['target']) {
            foreach ($edges[$j]['officers'] as $officer) {
                array_push($edge['officers'], $officer);
            }
            array_splice($edges, $j, 1);
        }
    }
}

But I recommend the unset() alternative as it is much faster (array_splice always recreates the array completely).

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

2 Comments

This really is a very good explanation of the problem with the OP's code.
@bwoebi thank you, works like a charm. I am glad I was at least somehow close to getting it working.
2

This is similar to other problems where you can solve this by using a key from the sub-arrays as a key in your merged result. It's just a little different because you need to use more than one key to determine which records should be merged.

I would suggest doing it by just concatenating the two keys.

foreach ($your_array as $item) {
    $k = "$item[source].$item[target]";
    if (isset($merged[$k])) {
        $merged[$k]['officers'] = array_merge($merged[$key]['officers'], $item['officers']);
    } else {
        $merged[$k] = $item;
    }
}

And if you don't like the composite keys, you can do array_values($merged) afterward to get back to plain numeric keys.

3 Comments

While that's not explaining what he did wrongly (see my answer), this is good advice; +1.
@bwoebi Thanks! I like to use this approach for this type of problem as it only takes one fairly simple pass through the input array.
@Don'tPanic thank you for help this solution works great as well!

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.