32

I have a string like 1-350,9-390.99,..., and I need to turn it into an associative array like this:

 Array
    (
        [1] => 350
        [9] => 390.99
        ...........
    )

Is it possible to do this using only array functions, without a loop?

Pramod
  • 1,031
  • 3
  • 13
  • 26
  • 2
    Explode is your friend. Try it at first with "," than with "-" and use the first index as key. – rekire Jan 03 '13 at 06:01
  • how about this one :) parse_str(str_replace(",","&",$str), $output); – Wasim A. Dec 03 '16 at 19:47
  • I contested the duplicate marking, on the argument that this question specifically asks how to do it _without a loop_. The other question makes no such requirement. – bishop Jul 09 '18 at 18:05
  • The dupe target also deals with a single delimiting character, whereas this question is dealing with two delimiting characters. Such as https://stackoverflow.com/q/31619865/2943403 , https://stackoverflow.com/q/4923951/2943403 , https://stackoverflow.com/q/63742901/2943403 , https://stackoverflow.com/q/41912366/2943403 , https://stackoverflow.com/q/9259640/2943403 – mickmackusa Aug 04 '21 at 03:58
  • @WasimA. Please do not litter this page with multiple redundant resolving comments. – mickmackusa Aug 04 '21 at 04:01

10 Answers10

39

PHP 5.5+ two-line solution, using array_chunk and array_column:

$input  = '1-350,9-390.99';

$chunks = array_chunk(preg_split('/[-,]/', $input), 2);
$result = array_combine(array_column($chunks, 0), array_column($chunks, 1));

print_r($result);

Yields:

Array
(
    [1] => 350
    [9] => 390.99
)

See it online at 3v4l.org.

bishop
  • 37,830
  • 11
  • 104
  • 139
21

Here's a way to do it without a for loop, using array_walk:

$array = explode(',', $string);
$new_array = array();
array_walk($array,'walk', $new_array);

function walk($val, $key, &$new_array){
    $nums = explode('-',$val);
    $new_array[$nums[0]] = $nums[1];
}

Example on Ideone.com.

Ricky Smith
  • 2,379
  • 1
  • 13
  • 29
bozdoz
  • 12,550
  • 7
  • 67
  • 96
  • 1
    +1 Good answer! The only thing I'd shy away from is the `global`. You should be able to pass an external array in by reference as the 3rd parameter for `array_walk`. – hafichuk Jan 03 '13 at 06:54
  • I tried passing the array with `&$new_array`, but it wasn't working. Why is `global` bad? – bozdoz Jan 03 '13 at 06:54
  • Found it. I have to put &$new_array in the array_walk function, and not the "walk" function. Thanks @hafichuk! – bozdoz Jan 03 '13 at 06:57
  • They aren't inherently bad. I mainly do OOP so I just shy away from them because of scope issues. – hafichuk Jan 03 '13 at 07:02
  • parse_str(str_replace(",","&",$str), $output); – Wasim A. Dec 03 '16 at 19:47
  • apparently you can't pass variable by reference to array_walk ***array_walk($array,'walk', &$new_array);*** as this will throw error. – Jitesh Dhamaniya Dec 16 '20 at 05:26
8

Something like this should work:

$string = '1-350,9-390.99';

$a = explode(',', $string);

foreach ($a as $result) {
    $b = explode('-', $result);
    $array[$b[0]] = $b[1];
}
jel
  • 1,172
  • 10
  • 8
  • Although January 3rd of 2013 around 6:05 was incredibly popular time to post "Try this" answers (an unfortunate consequence of FGITW posting), this answer is missing its educational explanation. After you answered, the OP stipulated that they are not interested in answers that leverage language constructs and would prefer to receive function-based techniques. – mickmackusa Dec 07 '20 at 07:05
7

This uses array_walk with a closure.

<?php
$string = "1-350,9-390.99";
$partial = explode(',', $string);
$final = array();
array_walk($partial, function($val,$key) use(&$final){
    list($key, $value) = explode('-', $val);
    $final[$key] = $value;
});
print_r($final);
?>

Interactive fiddle.

hafichuk
  • 10,351
  • 10
  • 38
  • 53
3
$string = '1-350,9-390.99........';
$final_result = array();
foreach (explode(',', $string) as $piece) {
    $result = array();
    $result[] = explode('-', $piece);
    $final_result[$result[0]] = $result[1];
}

print_r($final_result);
Vinoth Babu
  • 6,724
  • 10
  • 36
  • 55
  • Although January 3rd of 2013 around 6:05 was incredibly popular time to post "Try this" answers (an unfortunate consequence of FGITW posting), this answer is missing its educational explanation. After you answered, the OP stipulated that they are not interested in answers that leverage language constructs and would prefer to receive function-based techniques. – mickmackusa Dec 07 '20 at 07:02
2
$x='1-350,9-390.99';
$arr1=explode(',',$x);
$res_arr=array();
foreach($arr1 as $val){
    $arr2=explode('-',$val);
    $res_arr[$arr2[0]]=$arr2[1];
    }

print_r($res_arr);
Amit Garg
  • 3,867
  • 1
  • 27
  • 37
  • Although January 3rd of 2013 around 6:05 was incredibly popular time to post "Try this" answers (an unfortunate consequence of FGITW posting), this answer is missing its educational explanation. After you answered, the OP stipulated that they are not interested in answers that leverage language constructs and would prefer to receive function-based techniques. – mickmackusa Dec 07 '20 at 07:02
2

Technically, it is possible to do this without using loops (demo on codepad.org):

$string = '1-350,9-390.99';

// first, split the string into an array of pairs
$output = explode(',', $string);
function split_pairs ($str) {
    return explode('-', $str, 2);
}
$output = array_map(split_pairs, $output);

// then transpose it to get two arrays, one for keys and one for values
array_unshift($output, null);
$output = call_user_func_array(array_map, $output);

// and finally combine them into one
$output = array_combine($output[0], $output[1]);

var_export($output);

However, this is really not something you'd want to do in real code — not only is it ridiculously convoluted, but it's also almost certainly less efficient than the simple foreach-based solution others have already given (demo on codepad.org):

$output = array();
foreach ( explode( ',', $string ) as $pair ) {
    list( $key, $val ) = explode( '-', $pair, 2 );
    $output[$key] = $val;
} 
Ilmari Karonen
  • 49,047
  • 9
  • 93
  • 153
  • Functions that iterate data are still "looping". – mickmackusa Dec 07 '20 at 07:03
  • @mickmackusa: Sure, there's probably a loop somewhere under the hood there. For that matter, the PHP interpreter is almost certainly using a loop to execute the code anyway, so even doing `echo "Hello, World!"` probably involves a loop (or several!) if you look deep enough. Still, there are no *explicit* loops in the code above, which is really the most one can ask for. – Ilmari Karonen Dec 07 '20 at 09:24
1

Try this:

$string = '1-350,9-390.99';
$array = explode(',', $string);

$output = array();
foreach($array as $arr){
    $chunk = explode('-', $arr);
    $output[$chunk[0]] = $chunk[1];
}
echo '<pre>'; print_r($output); echo '</pre>';
Sithu
  • 4,752
  • 9
  • 64
  • 110
  • Although January 3rd of 2013 around 6:05 was incredibly popular time to post "Try this" answers (an unfortunate consequence of FGITW posting), this answer is missing its educational explanation. After you answered, the OP stipulated that they are not interested in answers that leverage language constructs and would prefer to receive function-based techniques. – mickmackusa Dec 07 '20 at 07:02
0

Is this the thing you want?

<?php 
//the string to process
$str = "1-350,9-390.99";

//explode it
$str_exploded = explode(",",$str);

$final_arr;
foreach($str_exploded as $str_elem){
    //extract
    $str_elem_final = explode("-",$str_elem);
    //the first elem is the index and the last elem is the value
    $final_arr[(int)$str_elem_final[0]] = $str_elem_final[1];

}
print_r($final_arr);

?>

http://rextester.com/VEY59445

Netorica
  • 18,523
  • 17
  • 73
  • 108
0

Personally i use:

/**
 * @desc String to associative array
 * 
 * @param string $string
 * @param string $element_delimiter
 * @param string $value_delimiter
 * 
 * @example
  $string = "1:9|class:fa fa-globe";
  $array = string_to_array($string);
 * 
 * @return array $results
 */
function string_to_array($string, $element_delimiter = '|', $value_delimiter = ':') {
    $results = array();
    $array = explode($element_delimiter, $string);
    foreach ($array as $result) {
        $element = explode($value_delimiter, $result);
        $results[$element[0]] = $element[1];
    }
    return $results;
}

/**
 * @desc Associative array to string
 * 
 * @param type $array
 * @param type $element_delimiter
 * @param type $value_delimiter
 * 
 * @example
  $array = array('class' => 'in-line', 'rel' => 'external');
  $string = array_to_string($array);
 * 
 * @return string
 */
function array_to_string($array, $element_delimiter = '|', $value_delimiter = ':') {
    array_walk($array, create_function('&$i,$k', 'if (strlen($k) > 0){$i="' . $element_delimiter . '$k' . $value_delimiter . '$i";}'));
    return substr(implode($array, ""), 1);
}
onalbi
  • 2,609
  • 1
  • 24
  • 36