1

I have a an array like so:

$fruit = array('Apple', 'Orange', 'Banana');

I would like to combine the array with a separator similar to implode but without converting the result to a string.

So instead of

implode('.', $fruit); // 'Apple.Orange.Banana'

the result should be:

array('Apple', '.', 'Orange', '.', 'Banana');

This could probably be achieved with loops, however, I am looking for the best possible solution. Maybe there is a native function that can accomplish that which I do not know of? Thanks in advance!

mickmackusa
  • 43,625
  • 12
  • 83
  • 136
Ood
  • 1,445
  • 4
  • 23
  • 43
  • I'd probably call this "interleaving" or "alternating" the values, but the description is clear. I don't have an answer, though. – IMSoP Sep 29 '22 at 16:29

3 Answers3

3

You can implode based on |.|(period character surrounded by pipes) and then explode on the | pipe character.

<?php

$fruits = array('Apple', 'Orange', 'Banana');

$d = explode("|", implode('|.|', $fruits));

print_r($d);

Online Demo

Update:

As @RiggsFolly mentioned in the comments, you can use a very unlikely character like chr(1) as a delimiter.

<?php
$fruits = array('Apple', 'Orange', 'Banana');
$sep = chr(1);
$d = explode($sep, implode($sep.'.'.$sep, $fruits));

print_r($d);

Online Demo

nice_dev
  • 17,053
  • 2
  • 21
  • 35
  • 2
    I thought about that. The problem is that if a string in the array contains the delimiter (e.g. 'Or|ange') this would not work. – Ood Sep 29 '22 at 16:45
  • 1
    @Ood You can change the delimiter. `|` is just an option. Also, adding new constraints when an answer is given is not really appreciable. – nice_dev Sep 29 '22 at 16:46
  • 2
    Create a Really Really unlikely char as a seperator like `$sep = chr(1);` – RiggsFolly Sep 29 '22 at 16:49
  • Sorry, my bad. I tried to make the question as easy to understand as possible, but of course this should work on any array of strings. – Ood Sep 29 '22 at 16:50
  • 1
    https://onecompiler.com/php/3yhg22f42 No loop in site, totally ripped off from @nice_dev answer of course – RiggsFolly Sep 29 '22 at 16:50
  • @RiggsFolly Heeding your advice. – nice_dev Sep 29 '22 at 16:52
  • 1
    @Ood Fair enough, but the conditions need to mentioned for us to consider it. Never mind. – nice_dev Sep 29 '22 at 16:55
  • @nic I have hammered this duplicate page. You may like to add your approach as an answer on the dupe target. Although, I don't personally like this technique because it requires the developer to be 100% certain that the array values never contain the nominated separator. – mickmackusa Oct 08 '22 at 22:16
  • @mickmackusa Since OP didn't mention about the domain of characters, I went with the benefit of doubt. – nice_dev Oct 09 '22 at 07:28
  • 1
    @nice It is a working answer -- no shame in that. – mickmackusa Oct 09 '22 at 07:44
2

Use array_splice() with a reversed for loop

Remember to remove 1 from count($fruit) so we won't add another . at the end of the array

<?php

$fruit = [ 'Apple', 'Orange', 'Banana' ];
for ($i = count($fruit) - 1; $i > 0; $i--) {
    array_splice($fruit, $i, 0, '.');
}

var_dump($fruit);
array(6) {
  [0]=>
  string(5) "Apple"
  [1]=>
  string(1) "."
  [2]=>
  string(6) "Orange"
  [3]=>
  string(1) "."
  [4]=>
  string(6) "Banana"
}
0stone0
  • 34,288
  • 4
  • 39
  • 64
  • 1
    @ood thought you wanted to avoid loops :) – RiggsFolly Sep 29 '22 at 16:40
  • You could avoid loops by making a 2d array and flatten it afterwards, but IMHO this seems the most straight forward way. – 0stone0 Sep 29 '22 at 16:41
  • @RiggsFolly You are right. However, I guess there is no native function/one-liner that does this, so if loops are the best solution that is fine with me. – Ood Sep 29 '22 at 16:43
  • Earlier posted and more dynamic version of this answer can be found at [Push static value into another array at every nth position](https://stackoverflow.com/a/73576397/2943403) – mickmackusa Oct 08 '22 at 22:18
1

Alternative

Leaning on the array_* functions, you could consider the following:

function interleave(string $sep, array $arr): array {
  return array_slice(array_merge(...array_map(fn($elem) => [$sep, $elem], $arr)), 1); 
}

Due to the use of inbuilt functions and no explicit looping, it exceeds the speed of the looping array_splice implementation around the 10 element mark, so the trade-off between terse implementation and performance may be worth it in your case.

Explanation

When called like so:

interleave('.', ['Apple', 'Orange', 'Banana']);

does the following (from the inside out):

Map

Map each element to a pair ['.', $elem]:

$mapped = array_map(fn($elem) => ['.', $elem], ['Apple', 'Orange', 'Banana']);

resulting in:

Array
(
    [0] => Array
        (
            [0] => .
            [1] => Apple
        )

    [1] => Array
        (
            [0] => .
            [1] => Orange
        )

    [2] => Array
        (
            [0] => .
            [1] => Banana
        )

)

Merge

Flatten the array using array_merge taking advantage of the fact that, from the documentation:

If [...] the arrays contain numeric keys, the later value will not overwrite the original value, but will be appended.

$merged = array_merge(...$mapped);

resulting in:

Array
(
    [0] => .
    [1] => Apple
    [2] => .
    [3] => Orange
    [4] => .
    [5] => Banana
)

Slice

Slice off the first extra separator:

$sliced = array_slice($merged, 1);

resulting in:

Array
(
    [0] => Apple
    [1] => .
    [2] => Orange
    [3] => .
    [4] => Banana
)
msbit
  • 4,152
  • 2
  • 9
  • 22