wadkar
wadkar

Reputation: 960

php array_combine only if keys match

I have

$map = array('id' => 'clmId', 'name' => 'clmName' => 'value' => 'clmValue',);
$value = array('id' => 1, 'name' => 'Foo', 'value' => 'Bar',);

and I want to get

$expected = array('clmId' => 1, 'clmName' => 'Foo', 'clmValue' => 'Bar');

of course I did $expected = array_combine($map, $value) and it works most of the time, but fails (to my surprise) for following

$map = array('id' => 'clmId', 'name' => 'clmName' => 'value' => 'clmValue',);
$value = array('name' => 'Foo', 'id' => 1, 'value' => 'Bar',);
$expected = array_combine($map, $value);
//you get
//$expected = array('clmId' => Foo, 'clmName' => 1, 'clmValue' => 'Bar');

clearly, array_combine is not meant for combining associative arrays. What can be done to achieve this ?
I am doing a primitive foreach($map as $key => $mapValue) { ... but I am guessing a smarter map/reduce or some cool array function should do it for me.
Return array()/FALSE in case $value has no corresponding key from $map

Upvotes: 1

Views: 3282

Answers (3)

Ben Swinburne
Ben Swinburne

Reputation: 26467

function combine_if_same_keys( $array_one, $array_two ) {
    $expected = false;

    ksort($array_one);
    ksort($array_two);

    $diff = array_diff_key($array_one, $array_two);
    if( empty($diff) && count($array_one) == count($array_two) ) {
        $expected = array_combine( $array_one, $array_two );
    }

    return $expected;
}

Returns false if the keys don't match and an array if they did match.

$map = array('id' => 'clmId', 'name' => 'clmName', 'value' => 'clmValue');
$value = array('id' => 1, 'name' => 'Foo', 'value' => 'Bar');
$value2 = array('ids' => 1, 'name' => 'Foo', 'value' => 'Bar');

var_dump( combine_if_same_keys( $map, $value ) );
var_dump( combine_if_same_keys( $map, $value2 ) );

Outputs:

array(3) { ["clmId"]=> int(1) ["clmName"]=> string(3) "Foo" ["clmValue"]=> string(3) "Bar" }
bool(false)

Edit: Benchmarking

Just read some comments on another answer which suggested that ksort() will cause a performance hit, so I did a bit of benchmarking Ran ksort() on 2 arrays with (albeit numeric keyed arrays) 10,000,000 keys each which only took 0.010757923126221 seconds on Intel Q8200 @ 2.33ghz (4CPUs), 3072MB RAM, Windows 7 x64 .

Edit (by OP): Number of keys should match as well array_diff_key($a1, $a2) returns empty array even if count($a2) > count($a1), the array_combine returns FALSE while generating a warning.

One can suppress it by @array_combine, but I would rather put the count condition (along with the appropriate empty() test on the array_key_diff return) and then combine the array.

Upvotes: 4

knittl
knittl

Reputation: 265231

I think there is no builtin way

function combine_assoc($map, $values) {
  $output = array();
  foreach($map as $key => $values) {
    if(!array_key_exists($key, $value)) return FALSE;
    $output[$value] = $values[$key];
  }
  return $output;
}

Of course, you could simply sort your arrays by key first, but this does not take care of missing key/value pairs and has a somewhat decreased performance:

ksort($map);
ksort($value);
$output = array_combine($map, $value);

Version without foreach loop, which does check for matching keys, but I do not recommend it, since it will not perform well …

function combine_assoc_slow($map, $value) {
  ksort($map);
  ksort($value);
  if(array_keys($map) != array_keys($value)) return FALSE;
  return array_combine($map, $value);
}

Upvotes: 2

Tim S.
Tim S.

Reputation: 13843

So array_combine doesn't work if the order is different? Well, easiest solution for you: sorting both arrays by key!

$map = array('id' => 'clmId', 'name' => 'clmName' => 'value' => 'clmValue');
$value = array('name' => 'Foo', 'id' => 1, 'value' => 'Bar');

ksort($map);
ksort($value);

// keys are "aligned", ready to combine
$expected = array_combine($map, $value);

Upvotes: 0

Related Questions