4

I am working with a web service that returns JSON data, which, when I decode with PHP's json_decode function, gives me an array like the following:

Array
(
 [0] => eBook
 [1] => 27
 [2] => Trade Paperback
 [3] => 24
 [4] => Hardcover
 [5] => 4
)

Is there a PHP function that will take this array and combine it into an associative array where every other element is a key and the following element is its value? What I want to come up with is the following:

Array
(
 [eBook] => 27
 [Trade Paperback] => 24
 [Hardcover] => 4
)
Andrew
  • 2,084
  • 20
  • 32

5 Answers5

5

As far as I know, there is no built-in function that does this, but you could use a function like the following:

function combineLinearArray( $arrayToSmush, $evenItemIsKey = true ) {
    if ( ( count($arrayToSmush) % 2 ) !== 0 ) {
        throw new Exception( "This array cannot be combined because it has an odd number of values" );
    }

    $evens = $odds = array();

    // Separate even and odd values
    for ($i = 0, $c = count($arrayToSmush); $i < $c; $i += 2) {
        $evens[] = $arrayToSmush[$i];
        $odds[] = $arrayToSmush[$i+1];
    }

    // Combine them and return
    return ( $evenItemIsKey ) ? array_combine($evens, $odds) : array_combine($odds, $evens);
}

You can call that with the array you want to combine into an associative array and and optional flag indicating whether to use even or odd elements as the keys.

Edit: I changed the code to use only one for loop, rather than a separate loop to extract even and odd values.

Andrew
  • 2,084
  • 20
  • 32
  • 6
    If you knew the answer why ask it? – Shubham Jun 29 '12 at 15:41
  • 1
    stackoverflow encourages that sort of knowledge-sharing: http://blog.stackoverflow.com/2011/07/its-ok-to-ask-and-answer-your-own-questions/ Since there is no function that does this in PHP's library, I wanted to make it available to people who may be searching for a solution to this sort of problem. – Andrew Jun 29 '12 at 15:43
  • @RobertHarvey , please notice the timestamps of question and answer – tereško Jun 29 '12 at 16:11
  • @tereško So? Instant self-answers are now *officially condoned.* Read the meta post I linked. – Robert Harvey Jun 29 '12 at 16:13
4

Your own solution is clearer for sure, but this one-liner, made of PHP functions only, does the same job:

$output = call_user_func_array('array_combine', call_user_func_array('array_map', array_merge(array(null), array_chunk($input, 2))));

Your question was "is there a PHP function...". The answer is no, but for a combination thereof it is yes.

The tricky part here is the transposition of the chunked array, which is achieved by calling array_map with null as the first argument (see the manual where it says "an interesting use of this function...")

Walter Tross
  • 12,237
  • 2
  • 40
  • 64
  • I like that. I'd definitely opt for this code (plus some good documentation so that everyone other contributors don't have to scratch their heads) – Andrew Jun 29 '12 at 16:03
  • ...but you have already opted for another code. The documentation is all in the PHP manual, except for the matrix transposition trick that is a bit hidden. – Walter Tross Jun 29 '12 at 16:28
  • No problem. I had accepted the other answer before you posted your question. They are both _great_ answers, but I think that yours adds more to the discussion (which is what SO is all about, right?) – Andrew Jun 29 '12 at 16:51
1

A loop like this could work:

$array = json_decode(....);

$received = array();
for ($i = 0; $i < count($array); $i++) {
    $received[$array[$i]] = $array[$i+1];
    $i++;
}

var_dump($received);
ircmaxell
  • 163,128
  • 34
  • 264
  • 314
Mike Mackintosh
  • 13,917
  • 6
  • 60
  • 87
  • Yes, that's what I'd suggest, except why <= on count -1? – somedev Jun 29 '12 at 15:44
  • Because count will start counting at 1, but your arrays' key starts at 0. – Mike Mackintosh Jun 29 '12 at 15:47
  • If you didn't add the -1, you'd have an empty array key/value at the end of your array. – Mike Mackintosh Jun 29 '12 at 15:48
  • Drop the <=, make it <, and remove the -1, if the count were 3, you're telling it to loop until less than or equal to 2, where you could have just said, less than 3 (which is 2) – somedev Jun 29 '12 at 15:52
  • @sixeightzero: Maybe thats why we have '<' operator as well. :) – Shubham Jun 29 '12 at 15:54
  • 3
    **please** don't use `sizeof()`. It's an alais and does nothing but make it harder to read. Use the proper function `count()`... – ircmaxell Jun 29 '12 at 15:56
  • 1
    Do you expect the original array to change? If no, then why are you re-counting it all the time. And the way you iterate is just confusing: `for( $i = 0; $i < $max ; $i+=2 )` would be much cleaner. – tereško Jun 29 '12 at 16:05
  • @tereško correct, but we don't know the size of the array or if/when it will change. To prevent the need to keep changing `$max`, just do a count. It is not a costly function. – Mike Mackintosh Jun 29 '12 at 16:08
1

Adjustment to the code in the other answer:

function combineLinearArray( $arrayToSmush) {

if ( ( count($arrayToSmush) % 2 ) !== 0 ) {
    throw new Exception( "This array cannot be combined because it has an odd number of values" );
}

$combined = array();
for ($i = 0, $i<count($arrayToSmush); $i++) {
    $combined[$arrayToSmush[$i]] = $arrayToSmush[$i+1];
    $i++; // next key
}

// Combine them and return
return $combined;
}
somedev
  • 1,053
  • 1
  • 9
  • 27
0

Speaking of 1-liners:

array_reduce(array_chunk($input, 2), function(&$r, $i) { !empty($i[0]) && $r[$i[0]] = @$i[1]; return $r; }, array());

This 1-liner also verifies the immediate validity of the resulting assoc key and is 10 or so chars shorter than the accepted one https://stackoverflow.com/a/11265111/1990515

Community
  • 1
  • 1
ION
  • 1