1

i have a string like

$str = "1-a,2-b,3-c";

i want to convert it into a single array like this

$array = [
             1 => "a", 
             2 => "b", 
             3 => "c"
];

what i do is

$str = "1-a,2-b,3-c";
$array = [];
$strex = explode(",", $str);
foreach ($strex as $str2) {
    $alphanumeric = explode("-", $str2);
    $array[$alphanumeric[0]] = $alphanumeric[1];
}

can i do this in a better way?

Joe Doe
  • 523
  • 2
  • 9
  • 1
    This is clear and understandable code. – u_mulder Jul 15 '19 at 16:09
  • PD of [PHP Split Delimited String into Key/Value Pairs (Associative Array)](//stackoverflow.com/q/5290342) / [PHP - split String in Key/Value pairs](//stackoverflow.com/q/4923951) / [PHP Regex extract key-value comma separated](//stackoverflow.com/q/35495032) – mario Jul 15 '19 at 16:17
  • Search sample: https://duckduckgo.com/?q=site%3Astackoverflow.com+php+extract+comma+colon+key+value+pairs – mario Jul 15 '19 at 16:18

9 Answers9

4

You can use preg_match_all for this:

<?php
    $str = "1-a,2-b,3-c";

    preg_match_all('/[0-9]/', $str, $keys);
    preg_match_all('/[a-zA-Z]/', $str, $values);

    $new = array_combine($keys[0], $values[0]);

    echo '<pre>'. print_r($new, 1) .'</pre>';

here we take your string, explode() it and then preg_match_all the $value using patterns:

  • /[0-9]/ -> numeric value
  • /[a-zA-Z]/ -> letter

then use array_combine to get it into one array

Thanks to u_mulder, can shorten this further:

<?php
    $str = "1-a,2-b,3-c";

    preg_match_all('/(\d+)\-([a-z]+)/', $str, $matches);
    $new = array_combine($matches[1], $matches[2]);

    echo '<pre>'. print_r($new, 1) .'</pre>';
treyBake
  • 6,440
  • 6
  • 26
  • 57
3

just a little benchmark:

  • 5000 iterations
  • Debian stretch, php 7.3
  • parsed string: "1-a,2-b,3-c,4-d,5-e,6-f,7-g,8-h,9-i"

exploding string bench

[edit] Updated with the last 2 proposals [/edit]

jcheron
  • 193
  • 1
  • 9
2

You can use preg_split with array_filter and array_combine,

function odd($var)
{
    // returns whether the input integer is odd
    return $var & 1;
}
function even($var)
{
    // returns whether the input integer is even
    return !($var & 1);
}
$str = "1-a,2-b,3-c";
$temp = preg_split("/(-|,)/", $str); // spliting with - and , as said multiple delim
$result =array_combine(array_filter($temp, "even", ARRAY_FILTER_USE_KEY), 
                       array_filter($temp, "odd",ARRAY_FILTER_USE_KEY));
print_r($result);

array_filter — Filters elements of an array using a callback function

Note:- ARRAY_FILTER_USE_KEY - pass key as the only argument to callback instead of the value

array_combine — Creates an array by using one array for keys and another for its values

Demo

Output:-

Array
(
    [1] => a
    [2] => b
    [3] => c
)
Rahul
  • 18,271
  • 7
  • 41
  • 60
2

One way to do with array_map(),

<?php
$my_string = '1-a,2-b,3-c';
$my_array = array_map(function($val) {list($key,$value) = explode('-', $val); return [$key=>$value];}, explode(',', $my_string));
foreach(new RecursiveIteratorIterator(new RecursiveArrayIterator($my_array)) as $k=>$v){
    $result[$k]=$v;
}
print_r($result);
?>

WORKING DEMO: https://3v4l.org/aYmOH

A l w a y s S u n n y
  • 36,497
  • 8
  • 60
  • 103
1

Not a better way but one more example:

$str = "1-a,2-b,3-c";
$arr1 = explode(",", preg_replace("/\-([a-zA-Z]+)/", "", $str));
$arr2 = explode(",", preg_replace("/([0-9]+)\-/", "", $str));

print_r(array_combine($arr1, $arr2));
blues911
  • 840
  • 8
  • 9
1

Tokens all the way down...

<?php

$str   = '1-a,2-b,3-c';
$token = '-,';

if($n = strtok($str, $token))
    $array[$n] = strtok($token);
while($n = strtok($token))
    $array[$n] = strtok($token);

var_export($array);

Output:

array (
    1 => 'a',
    2 => 'b',
    3 => 'c',
  )

Or perhaps more terse without the first if...:

$array = [];
while($n = $array ? strtok($token) : strtok($str, $token))
    $array[$n] = strtok($token);
Progrock
  • 7,373
  • 1
  • 19
  • 25
  • This was a very busy day for you -- four answers on one question. But should this question have been closed as a duplicate instead? – mickmackusa Jun 06 '21 at 03:44
  • 1
    @mickmackusa I didn't think it was aligned that well to the dupe. And the question might not be seen as appropriate for SO. I find the long drawn out answers with different solutions personally confusing, so prefer multi-answer approaches. But I realise that's all a matter of taste. On the face of it, this does read as pretty yucky but the benchmark adds interest. Would suit the cookbook style. Titles are the most difficult nut to crack here for people seeking solutions. IMHO. – Progrock Jun 15 '21 at 00:12
  • 1
    @mickmackusa there are regular famliar questions with familiar solutions on the site, but they don't quite align and many people just find it quicker to write a solution or approach. It's quite difficult finding close matches. I think SO needs an incubation area for questions. – Progrock Jun 15 '21 at 00:16
1

Mandatory one-liner (your mileage may vary):

<?php
parse_str(str_replace([',', '-'], ['&', '='], '1-a,2-b,3-c'), $output);
var_export($output);

Output:

array (
    1 => 'a',
    2 => 'b',
    3 => 'c',
  )
Progrock
  • 7,373
  • 1
  • 19
  • 25
1

This one explodes the string as the OP has on the comma, forming the pairs: (1-a) and (2-b) etc. and then explodes those pairs. Finally array_column is used to create the associated array:

<?php

$str = '1-a,2-b,3-c';
$output =
array_column(
    array_map(
        function($str) { return explode('-', $str); }, 
        explode(',', $str)
    ),
    1,
    0
);
var_export($output);

Output:

array (
  1 => 'a',
  2 => 'b',
  3 => 'c',
)
Progrock
  • 7,373
  • 1
  • 19
  • 25
1

You can do one split on both the , and -, and then iterate through picking off every other pair ($k&1 is a check for an odd index):

<?php
$str = '1-a,2-b,3-c';

foreach(preg_split('/[,-]/', $str) as $k=>$v) {
    $k&1 && $output[$last] = $v;
    $last = $v;
}

var_export($output);

Output:

array (
  1 => 'a',
  2 => 'b',
  3 => 'c',
)

The preg_split array looks like this:

array (
  0 => '1',
  1 => 'a',
  2 => '2',
  3 => 'b',
  4 => '3',
  5 => 'c',
)
Progrock
  • 7,373
  • 1
  • 19
  • 25