0

Not quite sure how to word this correctly, but I am looking for some help to to move/shift array keys so that the top level array doesn't contain another array with only one item. Basically from this:

[0] => Array
    (
        [0] => Array
            (
                [_id] => 3
                [title] => Award winning wedding venue
                [subtitle] => Creating a website to reflect the prestige of the brand
            )

    )

[1] => Array
    (
        [0] => Array
            (
                [_id] => 5
                [title] => Bringing storytelling to life
                [subtitle] => Bringing storytelling to life
            )

    )

to be like this:

[0] => Array
    (
        [_id] => 3
        [title] => Award winning wedding venue
        [subtitle] => Creating a website to reflect the prestige of the brand
    )

[1] => Array
    (
        [_id] => 5
        [title] => Bringing storytelling to life
        [subtitle] => Bringing storytelling to life
    )

Almost just shifting the array key up one.

The original array is created using the following:

// Start with manual relation otherwise default to next/prev    
    foreach ($item['related'] as $id) {
      
      $related[] = perch_collection('Projects', [
        'filter' => [
          [
            'filter' => '_id',
            'match'  => 'eq',
            'value'  => $id,
          ],
            // Item is enabled
          [
            'filter' => 'status',
            'match' => 'eq',
            'value' => 'enabled',
          ],
        ],
        'skip-template' => true,
      ], true);
    }
Marc Sanders
  • 298
  • 1
  • 4
  • 13
  • 2
    Do you have any control over how the array is created in the first place. This is usually the most efficient way of sorting this sort of problem out. – Nigel Ren Jun 26 '20 at 13:08
  • I do partly, I will edit the question to show the code example. – Marc Sanders Jun 26 '20 at 13:12
  • 1
    Try changing the last part of the method call to `], true)[0];` with the extra `[0]` to say take the first element of the result. – Nigel Ren Jun 26 '20 at 13:17
  • Thanks @NigelRen, this also worked. Although I didn't expect it to. – Marc Sanders Jun 26 '20 at 13:34
  • Not going to close this one with https://stackoverflow.com/q/6193946/2943403 because Grumpy has given more suitable advice for this particular case. – mickmackusa Jun 26 '20 at 15:42

2 Answers2

1

The best way to fix this problem would be at the source. This looks like a Dataset received from a database, so instead of trying to manipulate the array after you received it, you could also try to generate it in the correct format. Most DALs have methods to manipulate the return type of the resultset.

However, if that is not possible and you always only have a single element nested, this loop should do the trick.

for($i = 0; $i <= count($array); $i++) {
    $shifted[$i] = $array[$i][0];
}
Realitätsverlust
  • 3,941
  • 2
  • 22
  • 46
  • isn't `count()` called on every single loop, making this method very expensive? Of course, to solve that, you could just declare the count of `$array` before the loop. It probably also doesn't really matter too much unless you are doing thousands of rows. – GrumpyCrouton Jun 26 '20 at 13:27
  • 1
    @GrumpyCrouton it is, I just wrote that thing real quick during lunch break. Also, count is very performant and even thousands of rows probably won't result in a noticeable performance degredation. But in general it's cleaner to declare the count before the loop. – Realitätsverlust Jun 26 '20 at 14:23
1

It would be best if you modify the creation of your array instead of changing it afterwards.

// Start with manual relation otherwise default to next/prev    
foreach ($item['related'] as $id) {
  
    $related[] = perch_collection('Projects', [
        'filter' => [
            [
                'filter' => '_id',
                'match'  => 'eq',
                'value'  => $id,
            ],
            // Item is enabled
            [
                'filter' => 'status',
                'match' => 'eq',
                'value' => 'enabled',
            ],
        ],
        'skip-template' => true,
  ], true)[0];
}

Note the [0] at the end of the perch_collection() function call. This is essentially the same as the second part of my answer, it just occurs earlier.


With that said, if you still want to change it after the original array is made, you could just use a simple foreach loop with a reference to the original array.

foreach($array as &$arr) {
    $arr = $arr[0];
}

Using & in front of $arr is a reference. This means the loop will alter the original array, so it prevents the overhead of a temporary array.


mickmackusa let me know about another solution using array_column(), which avoids the loop completely.

$array = array_column($array, 0);
GrumpyCrouton
  • 8,486
  • 7
  • 32
  • 71
  • `array_column()` can be used to mop up too. https://stackoverflow.com/a/45417345/2943403, but I agree that it is best to not create the mess in the first place. – mickmackusa Jun 26 '20 at 15:48
  • 1
    @mickmackusa That's a cool solution, I use `array_column()` a lot but never thought about the possibility of using it with a numbered index. – GrumpyCrouton Jun 26 '20 at 15:49
  • I don't mean to offend, but I eventually found a duplicate that provides all of the necessary guidance and hammered the question. – mickmackusa Jun 26 '20 at 15:52
  • @mickmackusa Nah that's just the way the site works! No offense taken. Thanks for finding a suitable dupe. – GrumpyCrouton Jun 26 '20 at 15:53
  • 1
    I looked at the earlier post that it was closed with and felt that it departed from the guidance that I wanted to extend to this question. It was deliberate. No, it is the non-standard thing to do. Ideally, all of the Stack Overflow duplicates should "collapse" down to the best&earliest questions. – mickmackusa Jun 26 '20 at 15:58