0

I have an array like this

array("split","cat", "split", "dog", "cow");

how can get a multi dimensional array at with split removed

like this

array( array( "cat"), array("dog", "cow") );

order should be preserved

I tried finding all the indexes where "split" happens then slice it but doesn't seems to work.

array("goat","split","cat", "split", "dog", "cow"); this is also possible
1
  • Shouldn't the result of first example be array( array(), array( "cat"), array("dog", "cow") ); ? Commented Aug 25, 2022 at 21:34

4 Answers 4

0

Basically we keep reading the array, aggregating to a "bucket" then when encountering a "split" we dump the bucket into the final array result. And we won't forget to push the final bucket when exiting the loop.

$arr = array("split", "cat", "split", "dog", "cow");
$bucket = [];
$result = [];
while (count($arr)) {
    $item = array_shift($arr);
    if ($item === "split") {
        $result[] = $bucket;
        $bucket = [];
    } else {
        $bucket[] = $item;
    }
}
$result[] = $bucket;
print_r($result);

Output:

Array
(
    [0] => Array
        (
        )

    [1] => Array
        (
            [0] => cat
        )

    [2] => Array
        (
            [0] => dog
            [1] => cow
        )

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

Comments

0

There are a number of ways to skin this cat.

To implement your first idea of finding the indices of the split tokens and slicing the array based upon those positions, you would do this:

$input = ["split", "cat", "split", "dog", "cow"];

// Get the indices of the split token
$splitIndices = array_keys(array_intersect($input, ['split']));

// Create an output buffer
$output = [];

// Initialize the last index var to zero
$lastIndex = 0;

// Iterate through the split indices
foreach($splitIndices as $currIndex)
{
    // If we have a splat in the first position, there is nothing to do
    if($currIndex == 0)
    {
        continue;
    }
    
    // Determine the number of elements to extract for this range
    $length = $currIndex-($lastIndex+1);
    
    // Slice out the range of elements
    $output[] = array_slice($input, $lastIndex+1, $length);
    
    // Update the last index
    $lastIndex = $currIndex;
}

// If the final element was not a split token, we need to add the remainder of the array
if(sizeof($input) > $lastIndex+1)
{
    $output[] = array_slice($input, $lastIndex+1);
}

print_r($output);

That's a bit of a faff, and error-prone. Let's try the classic approach of iterating through the array and adding the chunks to a buffer when we hit a token.

$input = ["split", "cat", "split", "dog", "cow"];
$output = [];

// Iterate through the array, send the current index into the loop along with the value.
foreach($input as $i=>$currValue)
{
    // If the current value is our delimiter...
    if($currValue == 'split')
    {
        // If we have items in the buffer, append it to the output
        if(!empty($currBuffer))
        {
            $output[] = $currBuffer;
        }
        
        // Clear the buffer and move to the next iteration
        $currBuffer = [];
        continue;
    }
    
    // Add the value to our buffer
    $currBuffer[] = $currValue;
    
    // If this is the last item, we need to set our buffer in the output array
    if($i == array_key_last($input))
    {
        $output[] = $currBuffer;
    }
}

print_r($output);

Hmmm. That's better, but having to keep track of the index is a bit smelly.

$input = ["split", "cat", "split", "dog", "cow"];

$output = [];
while(($currValue = array_shift($input)))
{
    if($currValue == 'split')
    {
        // If we have items in the buffer, append it to the output
        if(!empty($currBuffer))
        {
            $output[] = $currBuffer;
        }
        
        // Clear the buffer and move to the next iteration
        $currBuffer = [];
        continue;
    }
    
    // Add the value to our buffer
    $currBuffer[] = $currValue;
    
    // If this is the last item, we need to set our buffer in the output array
    if(empty($input))
    {
        $output[] = $currBuffer;
    }
}

print_r($output);

That's a bit better, no need to track the index, but it's still a lot of code to accomplish a simple task. We can do better.

$input = ["split", "cat", "split", "dog", "cow"];

$output = array_reduce($input, function($output, $item)
{
    if($item == 'split')
    {
        $output[] = [];
    }
    else
    {
        $output[array_key_last($output)][] = $item;
    }
    
    return $output;
});

print_r($output);

array_reduce - an elegant weapon, for a more civilized age.

Comments

0

If you'd like your exact expected output (starting from index 0 of your array and going out from there) you can do something like this:

$arr = ["split", "cat", "split", "dog", "cow"];
$rebuild = [];
$offset = 0;

foreach ($arr as $key => $value) {
    if ($value === 'split') {
        $rebuild = array_filter([...$rebuild, array_slice($arr, $offset, $key - $offset)]);
        $offset = ++$key;
    }
}

var_dump([...$rebuild, array_slice($arr, $offset, count($arr) - $offset)]);

Output:

array(2) {
  [0] => array(1) {
    [0] => string(3) "cat"
  },
  [1] => array(2) {
    [0] => string(3) "dog"
    [1] => string(3) "cow"
  }
}

See it working over at 3v4l.org


References:

Comments

0

The simplest way I can think of is to reduce the one array into an array of arrays with the split groups. For example:

<?php

$foo = ["split","cat", "split", "dog", "cow"];

$bar = array_reduce($foo, function($found, $baz) {
    if (empty($found) || $baz === 'split') {
        $found[] = [];
        
        if ($baz === 'split') {
            return $found;
        }
    }
    
    $found[count($found) - 1][] = $baz;
    
    return $found;
}, []);

print_r($bar);

https://3v4l.org/3I0Ne

All this does is process each item, creating a new subarray when empty or if the current value is split. Then it pushes the following items into that subarray, until another is found and a new subarray is appended for the next group. Then you get an array of (sub)arrays.

Array
(
    [0] => Array
        (
            [0] => cat
        )

    [1] => Array
        (
            [0] => dog
            [1] => cow
        )

)

Comments