0

How would one convert the following array:

[
  "prefix1 foo",
  "prefix2 bar",
  "prefix1 aaa",
  "prefix2 bbb",
  "prefix3 ccc",
  "prefix1 111",
  "prefix2 222"
]

into the following data structure:

[
  [
    "prefix1" => "foo",
    "prefix2" => "bar"
  ],
  [
    "prefix1" => "aaa",
    "prefix2" => "bbb",
    "prefix3" => "ccc"
  ],
  [
    "prefix1" => "111",
    "prefix2" => "222"
  ],
]

array_chunk would be perfect if not for the fact that the chunks are of variable sizes. The prefixes are known ahead of time and each "chunk" would have a length of either two or three.

2
  • Loop through and explode(), then build a new array with the pieces Commented Nov 3, 2018 at 1:02
  • In the future please include your best failed coding attempt. Commented Nov 3, 2018 at 3:25

4 Answers 4

1

You could do it like this (given $input):

$result = [];
$prev = $input[0];
foreach($input as $line) {
    list($key, $value) = explode(" ", $line);
    if ($key < $prev) $result[] = [];
    $result[count($result)-1][$key] = $value;
    $prev = $key;
}

It assumes that the keys, which should end up in the same subarray, are alphabetically ordered in the input, so that a break into a next subarray happens when this order is not maintained.

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

Comments

1

This solution allows prefixes to be arbitrarily ordered by storing them in an array in the order in which they are expected to be encountered in the input data (assumed to be in $input):

$prefixes = ['prefix1', 'prefix2', 'prefix3'];
$output = array();
$lastidx = count($prefixes);
foreach ($input as $item) {
    list($prefix, $value) = explode(' ', $item);
    $index = array_search($prefix, $prefixes);
    if ($index < $lastidx) $output[] = array();
    $output[count($output)-1][$prefix] = $value;
    $lastidx = $index;
}
print_r($output);

For your sample input output is:

Array ( 
    [0] => Array ( 
        [prefix1] => foo
        [prefix2] => bar 
    )
    [1] => Array (
        [prefix1] => aaa
        [prefix2] => bbb
        [prefix3] => ccc
    )
    [2] => Array (
        [prefix1] => 111
        [prefix2] => 222
    ) 
)

Demo on 3v4l.org

Comments

1

isset() is faster than array_search()

Code: (Demo)

$array = [
  "prefix1 foo",
  "prefix2 bar",
  "prefix1 aaa",
  "prefix2 bbb",
  "prefix3 ccc",
  "prefix1 111",
  "prefix2 222"
];

foreach ($array as $v) {
    [$prefix, $value] = explode(' ', $v, 2);  // explode and perform "array destructuring"
    if (isset($batch[$prefix])) {     // check if starting new batch
        $result[] = $batch;           // store old batch
        $batch = [$prefix => $value]; // start new batch
    } else{
        $batch[$prefix] = $value;     // store to current batch
    }
}
$result[] = $batch;                   // store final batch
var_export($result);

or

foreach ($array as $v) {
    [$prefix, $value] = explode(' ', $v, 2);
    if (isset($batch[$prefix])) {
        $result[] = $batch;
        unset($batch);
    }
    $batch[$prefix] = $value;
}
$result[] = $batch;

Output:

array (
  0 => 
  array (
    'prefix1' => 'foo',
    'prefix2' => 'bar',
  ),
  1 => 
  array (
    'prefix1' => 'aaa',
    'prefix2' => 'bbb',
    'prefix3' => 'ccc',
  ),
  2 => 
  array (
    'prefix1' => '111',
    'prefix2' => '222',
  ),
)

Comments

1

You can do it a little easier

$res = [];
foreach ($array as $v) {
    list($prefix, $value) = explode(' ', $v, 2);
    $res[$prefix][] = [$prefix => $value];
}
print_r($res);
// if you want numeric index
$res = array_values($res);
print_r($res);

demo

Comments

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.