PHP array intersect (sort of) - php

Given two arrays:
$foo = array('a', 'b', 'c');
$bar = array('a' => 1, 'b' => 2, 'c' => 3, 'd' => 4, 'e' => 5);
Is there a built-in PHP function to produce the following result array?
$result = array('a' => 1, 'b' => 2, 'c' => 3);
I've been through the Array Functions list on php.net, but can't seem to find what I'm looking for. I know how to do it myself if need be, but I figured this might be a common-enough problem that there might be a built-in function that does it and didn't want to reinvent the wheel.

Another way using array_flip and array_intersect_keys:
$foo = array('a', 'b', 'c');
$bar = array('a' => 1, 'b' => 2, 'c' => 3, 'd' => 4, 'e' => 5);
$common = array_intersect_key($bar, array_flip($foo));
Output
array(3) {
["a"]=>
int(0)
["b"]=>
int(1)
["c"]=>
int(2)
}

It's a bit of a dirty hack, but it works:
function extractKeys($keys, $data) {
extract($data);
return call_user_func_array('compact', $keys);
}
$foo = array('a', 'b', 'c');
$bar = array('a' => 1, 'b' => 2, 'c' => 3, 'd' => 4, 'e' => 5);
var_dump(extractKeys($foo, $bar));
Output:
array(3) {
["a"]=>
int(1)
["b"]=>
int(2)
["c"]=>
int(3)
}

After posting, I thought of one way of doing this:
array_intersect_key($bar, array_fill_keys($foo, NULL))
Though, this isn't really the concise, built-in function that I had hoped for, it's definitely better than constructing the resultant array manually.

Related

Move key-specified element to the front of an associative array

I have an array with string indices, that I need partially sorted. That is, some elements must be moved first, but the others should remain untouched in their current (PHP-internal) order:
# The element with key "c" should be first
$foo = array(
"a" => 1,
"b" => 2,
"c" => 3,
"d" => 4,
);
uksort($foo, function ($a, $b) {
if ($a === "c") {
return -1;
} elseif ($b === "c") {
return 1;
}
return 0;
});
var_dump($foo);
What I expected:
array(4) { ["c"]=> int(3) ["a"]=> int(1) ["b"]=> int(2) ["d"]=> int(4) }
//--------------------------^ "a" remains first of the unsorted ones
What I got:
array(4) { ["c"]=> int(3) ["d"]=> int(4) ["b"]=> int(2) ["a"]=> int(1) }
//--------------------------^ "d" moved above "a"
This seems due to the sorting algorithm uksort() uses internally, which destroys the fragile order of elements. Is there any other way to achieve this sorting?
Using any sort function is overkill for this task. You merely need to merge the input array into a lone array containing the element which should come first. The array union operator (+) will do nicely for your associative array (otherwise array_merge() will do).
Codes: (Demos)
if key c is guaranteed to exist:
$foo = array(
"a" => 1,
"b" => 2,
"c" => 3,
"d" => 4,
);
$foo = ['c' => $foo['c']] + $foo;
var_export($foo);
if key c might not exist check for it first:
$bar = array(
"a" => 1,
"b" => 2,
"d" => 4,
);
if (array_key_exists('c', $bar)) {
$bar = ['c' => $bar['c']] + $bar;
}
var_export($bar);
Output:
array (
'c' => 3,
'a' => 1,
'b' => 2,
'd' => 4,
)
and
array (
'a' => 1,
'b' => 2,
'd' => 4,
)
This worked for me and returned:
array(4) { ["c"]=> int(3) ["a"]=> int(1) ["b"]=> int(2) ["d"]=> int(4) }
<?php
# The element with key "c" should be first
$foo = array(
"a" => 1,
"b" => 2,
"c" => 3,
"d" => 4,
);
uksort($foo, function ($a, $b) {
if ($a === "c") {
return -1;
} else
return 1;
});
var_dump($foo);
?>

Reverse array values while keeping keys

Here is an array I have:
$a = array('a' => 'a1', 'b' => 'a2', 'c' => 'a3', 'd' => 'a4', 'e' => 'a5');
What I would like to do is reverse the values of the array while keeping the keys intact, in other words it should look like this:
$a = array('a' => 'a5', 'b' => 'a4', 'c' => 'a3', 'd' => 'a2', 'e' => 'a1');
How should I go about it?
P.S. I tried using array_reverse() but it didn't seem to work
Some step-by-step processing using native PHP functions (this can be compressed with less variables):
$a = array('a' => 'a1', 'b' => 'a2', 'c' => 'a3', 'd' => 'a4', 'e' => 'a5');
$k = array_keys($a);
$v = array_values($a);
$rv = array_reverse($v);
$b = array_combine($k, $rv);
var_dump($b);
Result:
array(5) {
'a' =>
string(2) "a5"
'b' =>
string(2) "a4"
'c' =>
string(2) "a3"
'd' =>
string(2) "a2"
'e' =>
string(2) "a1"
}
It is possible by using array_combine, array_values, array_keys and array_values. May seem like an awful lot of functions for a simple task, and there may be easier ways though.
array_combine( array_keys( $a ), array_reverse( array_values( $a ) ) );
Here another way;
$keys = array_keys($a);
$vals = array_reverse(array_values($a));
foreach ($vals as $k => $v) $a[$keys[$k]] = $v;
I think this should work..
<?php
$old = array('a' => 'a1', 'b' => 'a2', 'c' => 'a3', 'd' => 'a4', 'e' => 'a5');
$rev = array_reverse($old);
foreach ($old as $key => $value) {
$new[$key] = current($rev);
next($rev);
}
print_r($new);
?>
This'll do it (just wrote it, demo here):
<?php
function value_reverse($array)
{
$keys = array_keys($array);
$reversed_values = array_reverse(array_values($array), true);
return array_combine($keys, $reversed_values);
}
$a = array('a' => 'a1', 'b' => 'a2', 'c' => 'a3', 'd' => 'a4', 'e' => 'a5');
print_r( value_reverse($a) );

Replace elements in an associative array using another associative array

How can assign the values from one array to another array? For example:
//array with empty value
$targetArray = array(
'a' => '',
'b' => '',
'c' => '',
'd' => ''
);
// array with non-empty values, but might be missing keys from the target array
$sourceArray = array(
'a'=>'a',
'c'=>'c',
'd'=>'d'
);
The result I would like to see is the following:
$resultArray = array(
'a'=>'a',
'b'=>'',
'c'=>'c',
'd'=>'d'
);
I think the function you are looking for is array_merge.
$resultArray = array_merge($targetArray,$sourceArray);
Use array_merge:
$merged = array_merge($targetArray, $sourceArray);
// will result array('a'=>'a','b'=>'','c'=>'c','d'=>'d');
Use array_merge():
$targetArray = array('a'=>'','b'=>'','c'=>'','d'=>'');
$sourceArray = array('a'=>'a','c'=>'c','d'=>'d');
$result = array_merge( $targetArray, $sourceArray);
This outputs:
array(4) {
["a"]=>
string(1) "a"
["b"]=>
string(0) ""
["c"]=>
string(1) "c"
["d"]=>
string(1) "d"
}
Perhaps a more intuitive/indicative function for this task is array_replace(). It performs identically to array_merge() on associative arrays. (Demo)
var_export(
array_replace($targetArray, $sourceArray)
);
Output:
array (
'a' => 'a',
'b' => '',
'c' => 'c',
'd' => 'd',
)
A similar but not identical result can be achieved with the union operator, but notice that its input parameters are in reverse order and the output array has keys from $targetArray then keys from $sourceArray.
var_export($sourceArray + $targetArray);
Output:
array (
'a' => 'a',
'c' => 'c',
'd' => 'd',
'b' => '',
)

Moving array element to top in PHP

$arr = array(
'a1'=>'1',
'a2'=>'2'
);
I need to move the a2 to the top, as well as keep the a2 as a key how would I go on about it I can't seem to think a way without messing something up :)
Here is a solution which works correctly both with numeric and string keys:
function move_to_top(&$array, $key) {
$temp = array($key => $array[$key]);
unset($array[$key]);
$array = $temp + $array;
}
It works because arrays in PHP are ordered maps.
Btw, to move an item to bottom use:
function move_to_bottom(&$array, $key) {
$value = $array[$key];
unset($array[$key]);
$array[$key] = $value;
}
You can achieve that this way:
$arr = array(
'a1'=>'1',
'a2'=>'2'
);
end($arr);
$last_key = key($arr);
$last_value = array_pop($arr);
$arr = array_merge(array($last_key => $last_value), $arr);
/*
print_r($arr);
will output (this is tested):
Array ( [a2] => 2 [a1] => 1 )
*/
try this:
$key = 'a3';
$arr = [
'a1' => '1',
'a2' => '2',
'a3' => '3',
'a4' => '4',
'a5' => '5',
'a6' => '6'
];
if (isset($arr[ $key ]))
$arr = [ $key => $arr[ $key ] ] + $arr;
result:
array(
'a3' => '3',
'a1' => '1',
'a2' => '2',
'a4' => '4',
'a5' => '5',
'a6' => '6'
)
Here's a simple one liner to get this done with array_splice() and the union operator:
$arr = array('a1'=>'1', 'a2'=>'2', 'a3' => '3');
$arr = array_splice($arr,array_search('a2',array_keys($arr)),1) + $arr;
Edit:
In retrospect I'm not sure why I wouldn't just do this:
$arr = array('a2' => $arr['a2']) + $arr;
Cleaner, easier and probably faster.
You can also look at array_multisort This lets you use one array to sort another. This could, for example, allow you to externalize a hard-coded ordering of values into a config file.
<?php
$ar1 = array(10, 100, 100, 0);
$ar2 = array(1, 3, 2, 4);
array_multisort($ar1, $ar2);
var_dump($ar1);
var_dump($ar2);
?>
In this example, after sorting, the first array will contain 0, 10, 100, 100. The second array will contain 4, 1, 2, 3. The entries in the second array corresponding to the identical entries in the first array (100 and 100) were sorted as well.
Outputs:
array(4) {
[0]=> int(0)
[1]=> int(10)
[2]=> int(100)
[3]=> int(100)
}
array(4) {
[0]=> int(4)
[1]=> int(1)
[2]=> int(2)
[3]=> int(3)
}

Remove a set of fields from a array

Is there a native PHP function that can remove a set of keys from a array?
for eg. if I have a array like
array('a' => 'aaa', 'b' => 'bbb', 'c' => 'ccc', 'd' => 'ddd');
and I want to remove 'b', 'c' and get array('a' => 'aaa', 'd' => 'ddd'); ?
It's array_diff_key.
$input = array(...);
$remove = array_flip(array('a', 'b')); // 'a' and 'b' are the keys to remove
$output = array_diff_key($input, $remove);
See it in action.
$array = array('a', 'b', 'c', 'd')
foreach($array as $k=>$v){
if (in_array($v,array('b','c'))) unset($array[$k]);
}
An alternate to everyone else's answer, though all valid in their own way, is the array_splice function.
$foo = Array(
'a' => 'aaaa',
'b' => 'bbbb',
'c' => 'cccc',
'd' => 'dddd'
);
var_dump($foo);
array_splice($foo, 1, 2);
var_dump($foo);
Which produces:
array(4) {
["a"]=>
string(4) "aaaa"
["b"]=>
string(4) "bbbb"
["c"]=>
string(4) "cccc"
["d"]=>
string(4) "dddd"
}
array(2) {
["a"]=>
string(4) "aaaa"
["d"]=>
string(4) "dddd"
}
If you don't have too many fields to remove, you can use unset():
unset($foo['b']);
unset($foo['c']);
var_dump($foo)

Categories