Reindex array by values - php

I have an array of the form
$a = array(
'a' => 0,
'b' => 0,
'c' => 1
);
and want an array of the form
array(
0 => array('a','b'),
1 => array('c')
);
What is the most efficient way to do this?

I think you'll just have to use a foreach, as array_flip will make you lose the duplicates:
$b = array();
foreach ($a as $k => $v) {
$b[$v][] = $k;
}
var_dump($b);

Related

Merge column values from two arrays to form an indexed array of associative arrays

I have two arrays:
$a = ['0' => 1, '1' => 2, '2' => 3]
$b = ['0' => 4, '1' => 5, '2' => 6]
I want to create a new array like this:
[
['a' => 1, 'b' => '4'],
['a' => '2', 'b' => '5']
]
I have tried using array_merge and array_merge_recursive, but I wasn't able to get the right results.
$data = array_merge_recursive(array_values($urls), array_values($id));
You have to apply array_map() with custom function:
$newArray = array_map('combine',array_map(null, $a, $b));
function combine($n){
return array_combine(array('a','b'),$n);
}
print_r($newArray);
Output:-https://3v4l.org/okML7
Try this one
$c = array_merge($a,$b)
$d[] = array_reduce($d, 'array_merge', []);
It will merge the two array and reduce and remerge it.
You can use foreach to approach this
$a = ['0' => 1, '1' => 2, '2' => 3];
$b = ['0' => 4, '1' => 5, '2' => 6];
$res = [];
$i = 0;
$total = 2;
foreach($a as $k => $v){
$res[$i]['a'] = $v;
$res[$i]['b'] = $b[$k];
$i++;
if($i == $total) break;
}
The idea is to have an array $ab = ['a','b'] and a array from your both arrays like this $merged_array = [[1,4],[2,5],[3,6]]. Now we can combine array $ab with each element of $merged_array and that will be the result we need.
$first = ['0' => 1, '1' => 2, '2' => 3];
$second = ['0' => 4, '1' => 5, '2' => 6];
$merged_array = [];
for($i=0;$i<count($first);$i++)
{
array_push($merged_array,[$first[$i],$second[$i]]);
}
$final = [];
$ab = ['a','b'];
foreach($merged_array as $arr)
{
array_push($final,array_combine($ab, $arr));
}
print_r($final);
All earlier answers are working too hard. I see excessive iterations, iterated function calls, and counter variables.
Because there are only two arrays and the keys between the two arrays are identical, a simple foreach loop will suffice. Just push associative arrays into the result array.
Code: (Demo)
$a = ['0' => 1, '1' => 2, '2' => 3];
$b = ['0' => 4, '1' => 5, '2' => 6];
$result = [];
foreach ($a as $k => $v) {
$result[] = ['a' => $v, 'b' => $b[$k]];
}
var_export($result);
Output:
array (
0 =>
array (
'a' => 1,
'b' => 4,
),
1 =>
array (
'a' => 2,
'b' => 5,
),
2 =>
array (
'a' => 3,
'b' => 6,
),
)

Two arrays to one

I have two arrays and I want one, can I add array 2 to array one?
$array1 = array("Germany" => 2, "Belgium"=> 3);
$array2 = array("France" => 4, "Italy"=> 5);
$final_array = {both arrays in one};
is this possible?
Yes, use the array_merge function, like this:
$final_array = array_merge($array1, $array2);
print_r($final_array);
When I run the above script it'll output:
Array (
[Germany] => 2
[Belgium] => 3
[France] => 4
[Italy] => 5
)
Take a quick read here: http://www.php.net/manual/de/function.array-merge.php
Use array_merge like
$final_arr = array_merge($array1 , $array2);
print_r($final_arr);
See this LINK for more
I would like to mention that on duplicated keys array_merge() returns the value from the second array. So, if you have different values with same keys - you should write your own function.
For example:
<?php
$a = array('rund' => '2', 'group' => '3', 'kupon' => 'utre', 'tralala' => 'shtur_kupon');
$b = array('grund' => '2', 'group' => 'ww', 'soup' => '1', 'tralala' => 'fd');
function two_arrays_merge_all_values(array $a, array $b) {
foreach ($b as $b_key => $b_value) {
$a_last_index = count($a);
$current_index = 1;
foreach ($a as $a_key => $a_value) {
if ($a_key === $b_key) {
$unique = uniqid();
$a[$b_key . '_' . $unique] = $b[$b_key];
unset($b[$b_key]);
break;
}
if ($current_index == $a_last_index) {
$a[$b_key] = $b[$b_key];
unset($b[$b_key]);
}
$current_index++;
}
}
return $a;
}

php - sort an array by key to match another array's order by key

I have two arrays, both have the same keys (different values) however array #2 is in a different order. I want to be able to resort the second array so it is in the same order as the first array.
Is there a function that can quickly do this?
I can't think of any off the top of my head, but if the keys are the same across both arrays then why not just loop over the first one and use its key order to create a new array using the the values from the 2nd one?
$arr1 = array(
'a' => '42',
'b' => '551',
'c' => '512',
'd' => 'gge',
) ;
$arr2 = array(
'd' => 'ordered',
'b' => 'is',
'c' => 'now',
'a' => 'this',
) ;
$arr2ordered = array() ;
foreach (array_keys($arr1) as $key) {
$arr2ordered[$key] = $arr2[$key] ;
}
You can use array_replace
$arr1 = [
'x' => '42',
'y' => '551',
'a' => '512',
'b' => 'gge',
];
$arr2 = [
'a' => 'ordered',
'x' => 'this',
'y' => 'is',
'b' => 'now',
];
$arr2 = array_replace($arr1, $arr2);
$arr2 is now
[
'x' => this,
'y' => is,
'a' => ordered,
'b' => now,
]
foreach(array_keys($array1) as $key)
{
$tempArray[$key] = $array2[$key];
}
$array2 = $tempArray;
I am not completely sure if this is what your after. anyways as long as the the array remains the same size, than this should work for you.
$gamey = array ("wow" => "World of Warcraft", "gw2" => "Guild Wars2", "wiz101" => "Wizard 101");
$gamex = array ("gw2" => "best game", "wiz101" => "WTF?", "wow" => "World greatest");
function match_arrayKeys ($x, $y)
{
$keys = array_keys ($x);
$values = array_values ($y);
for ($x = 0; $x < count ($keys); $x++)
{
$newarray [$keys[$x]] = $y[$keys[$x]];
}
return $newarray;
}
print_r (match_arrayKeys ($gamey, $gamex));
Output
[wow] => World greatest
[gw2] => best game
[wiz101] => WTF?
Try this
CODE
$fruits = array("d"=>"lemon", "a"=>"orange", "b"=>"banana", "c"=>"apple");
ksort($fruits);
foreach ($fruits as $key => $val) {
echo "$key = $val\n";
}
OUTPUT
a = orange
b = banana
c = apple
d = lemon
Check the php manual for ksort()

replace array keys with given respective keys

I have an array like below
$old = array(
'a' => 'blah',
'b' => 'key',
'c' => 'amazing',
'd' => array(
0 => 'want to replace',
1 => 'yes I want to'
)
);
I have another array having keys to replace with key information.
$keyReplaceInfoz = array('a' => 'newA', 'b' => 'newB', 'c' => 'newC', 'd' => 'newD');
I need to replace all keys of array $old with respective values in array $keyReplaceInfo.
Output should be like this
$old = array(
'newA' => 'blah',
'newB' => 'key',
'newC' => 'amazing',
'newD' => array(
0 => 'want to replace',
1 => 'yes I want to'
)
);
I had to do it manually as below. I am expecting better option. can anyone suggest better way to accomplish this?
$new = array();
foreach ($old as $key => $value)
{
$new[$keyReplaceInfoz[$key]] = $value;
}
I know this can be more simpler.
array_combine(array_merge($old, $keyReplaceInfoz), $old)
I think this looks easier than what you posed.
array_combine(
['newKey1', 'newKey2', 'newKey3'],
array_values(['oldKey1' => 1, 'oldKey2' => 2, 'oldKey3' => 3])
);
This should do the trick as long as you have the same number of values and the same order.
IMO using array_combine, array_merge, even array_intersect_key is overkill.
The original code is good enough, and very fast.
Adapting #shawn-k solution, here is more cleaner code using array_walk, it will only replace desired keys, of course you can modify as per your convenience
array_walk($old, function($value,$key)use ($keyReplaceInfoz,&$old){
$newkey = array_key_exists($key,$keyReplaceInfoz)?$keyReplaceInfoz[$key]:false;
if($newkey!==false){$old[$newkey] = $value;unset($old[$key]);
}
});
print_r($old);
I just solved this same problem in my own application, but for my application $keyReplaceInfoz acts like the whitelist- if a key is not found, that whole element is removed from the resulting array, while the matching whitelisted keys get translated to the new values.
I suppose you could apply this same algorithm maybe with less total code by clever usage of array_map (http://php.net/manual/en/function.array-map.php), which perhaps another generous reader will do.
function filterOldToAllowedNew($key_to_test){
return isset($keyReplaceInfoz[$key_to_test])?$keyReplaceInfoz[$key_to_test]:false;
}
$newArray = array();
foreach($old as $key => $value){
$newkey = filterOldToAllowedNew($key);
if($newkey){
$newArray[$newkey] = $value;
}
}
print_r($newArray);
This question is old but since it comes up first on Google I thought I'd add solution.
// Subject
$old = array('foo' => 1, 'baz' => 2, 'bar' => 3));
// Translations
$tr = array('foo'=>'FOO', 'bar'=>'BAR');
// Get result
$new = array_combine(preg_replace(array_map(function($s){return "/^$s$/";},
array_keys($tr)),$tr, array_keys($old)), $old);
// Output
print_r($new);
Result:
Array
(
[FOO] => 1
[baz] => 2
[BAR] => 3
)
This the solution i have implemented for the same subject:
/**
* Replace keys of given array by values of $keys
* $keys format is [$oldKey=>$newKey]
*
* With $filter==true, will remove elements with key not in $keys
*
* #param array $array
* #param array $keys
* #param boolean $filter
*
* #return $array
*/
function array_replace_keys(array $array,array $keys,$filter=false)
{
$newArray=[];
foreach($array as $key=>$value)
{
if(isset($keys[$key]))
{
$newArray[$keys[$key]]=$value;
}
elseif(!$filter)
{
$newArray[$key]=$value;
}
}
return $newArray;
}
This works irrespective of array order & array count. Output order & value will be based on replaceKey.
$replaceKey = array('a' => 'newA', 'b' => 'newB', 'c' => 'newC', 'd' => 'newD', 'e' => 'newE','f'=>'newF');
$array = array(
'a' => 'blah',
'd' => array(
0 => 'want to replace',
1 => 'yes I want to'
),
'noKey'=>'RESIDUAL',
'c' => 'amazing',
'b' => 'key',
);
$filterKey = array_intersect_key($replaceKey,$array);
$filterarray = array_intersect_key(array_merge($filterKey,$array),$filterKey);
$replaced = array_combine($filterKey,$filterarray);
//output
var_export($replaced);
//array ( 'newA' => 'blah', 'newB' => 'key', 'newC' => 'amazing', 'newD' => array ( 0 => 'want to replace', 1 => 'yes I want to' ) )
If you're looking for a recursive solution to use on a multidimensional array, have a look at the below method. It will replace all keys requested, and leave all other keys alone.
/**
* Given an array and a set of `old => new` keys,
* will recursively replace all array keys that
* are old with their corresponding new value.
*
* #param mixed $array
* #param array $old_to_new_keys
*
* #return array
*/
function array_replace_keys($array, array $old_to_new_keys)
{
if(!is_array($array)){
return $array;
}
$temp_array = [];
$ak = array_keys($old_to_new_keys);
$av = array_values($old_to_new_keys);
foreach($array as $key => $value){
if(array_search($key, $ak, true) !== false){
$key = $av[array_search($key, $ak)];
}
if(is_array($value)){
$value = array_replace_keys($value, $old_to_new_keys);
}
$temp_array[$key] = $value;
}
return $temp_array;
}
Using OP's example array:
$old = array(
'a' => 'blah',
'b' => 'key',
'c' => 'amazing',
'd' => array(
0 => 'want to replace',
1 => 'yes I want to'
)
);
$replace = ["a" => "AA", 1 => 11];
var_export(array_replace_keys($old, $replace));
Gives the following output:
array (
'AA' => 'blah',
'b' => 'key',
'c' => 'amazing',
'd' =>
array (
0 => 'want to replace',
11 => 'yes I want to',
),
)
DEMO
Inspired by the following snippet.
This uses #Summoner's example but keeps #Leigh's hint in mind:
$start = microtime();
$array = [ "a" => 1, "b" => 2, "c" => 3 ];
function array_replace_key($array, $oldKey, $newKey) {
$keys = array_keys($array);
$idx = array_search($oldKey, $keys);
array_splice($keys, $idx, 1, $newKey);
return array_combine($keys, array_values($array));
}
print_r(array_replace_key($array, "b", "z"));
<?php
$new = array();
foreach ($old as $key => $value)
{
$new[$keyReplaceInfoz][$key] = $value;
}
?>

Is there a cleaner way to filter by key's value?

$a = array(
0 => array( 'one' => 1, 'two' => 2 ),
1 => array( 'one' => 3, 'two' => 4 ),
2 => array( 'one' => 5, 'two' => 2 )
);
$c = count( $a );
$r = array();
for ( $i = 0; $i < $c; $i++ )
{
if ( $a[$i]['two'] == 2 )
$r[] = $a[$i];
}
Is there a cleaner way then to do all of the above?
Have you tried using array_filter()?
$r = array_filter($a, function($var) {
return ($var['two'] === 2);
});
The output of the above is slightly different than your original code:
Yours:
array(
0 => array('one' => 1, 'two' => 2),
1 => array('one' => 5, 'two' => 2)
)
Using array_filter:
array(
0 => array('one' => 1, 'two' => 2),
2 => array('one' => 5, 'two' => 2) // Note the key is 2, not 1
)
If you need the keys collapsed, you can follow up the array_filter() with array_values() or array_multisort()
You could write a function to do just this and then use array_walk or array_filter but that's about it.
Only way I can see to clean it up more would be to change the original datastructure.

Categories