This question already has answers here:
PHP - How to map elements of one array as keys to another array and return resulting values as an array?
(4 answers)
Closed 4 months ago.
I am having one (associative) data array $data with values, and another associative array $replacements.
I am looking for a short, easy and fast way to replace values in $data using the $replacements array.
The verbose way would be this:
function replace_array_values(array $data, array $replacements) {
$result = [];
foreach ($data as $k => $value) {
if (array_key_exists($value, $replacements)) {
$value = $replacements[$value];
}
$result[$k] = $value;
}
return $result;
}
Is there a native way to do this?
I know array_map(), but maybe there is something faster, without an extra function call per item?
Example:
See https://3v4l.org/g0sIJ
$data = array(
'a' => 'A',
'b' => 'B',
'c' => 'C',
'd' => 'D',
);
$replacements = array(
'B' => '(B)',
'D' => '(D)',
);
$expected_result = array(
'a' => 'A',
'b' => '(B)',
'c' => 'C',
'd' => '(D)',
);
assert($expected_result === replace_array_values($data, $replacements));
The simplest/least verbose way I can think of:
return array_map(function($value) use ($replacements) {
return array_key_exists($value, $replacements) ? $replacements[$value] : $value;
}, $data);
Using array_map is basically just looping over the array, which any other base function would also have to do anyway.
You can give a try to array_replace
Related
I am searching for a built in php function that takes array of keys as input and returns me corresponding values.
for e.g. I have a following array
$arr = array("key1"=>100, "key2"=>200, "key3"=>300, 'key4'=>400);
and I need values for the keys key2 and key4 so I have another array("key2", "key4")
I need a function that takes this array and first array as inputs and provide me values in response. So response will be array(200, 400)
I think you are searching for array_intersect_key. Example:
array_intersect_key(array('a' => 1, 'b' => 3, 'c' => 5),
array_flip(array('a', 'c')));
Would return:
array('a' => 1, 'c' => 5);
You may use array('a' => '', 'c' => '') instead of array_flip(...) if you want to have a little simpler code.
Note the array keys are preserved. You should use array_values afterwards if you need a sequential array.
An alternative answer:
$keys = array("key2", "key4");
return array_map(function($x) use ($arr) { return $arr[$x]; }, $keys);
foreach($input_arr as $key) {
$output_arr[] = $mapping[$key];
}
This will result in $output_arr having the values corresponding to a list of keys in $input_arr, based on the key->value mapping in $mapping. If you want, you could wrap it in a function:
function get_values_for_keys($mapping, $keys) {
foreach($keys as $key) {
$output_arr[] = $mapping[$key];
}
return $output_arr;
}
Then you would just call it like so:
$a = array('a' => 1, 'b' => 2, 'c' => 3);
$values = get_values_for_keys($a, array('a', 'c'));
// $values is now array(1, 3)
Below is an array of strings and numbers. How could the string and number values be split into separate arrays (with strings in one array and numbers in another array)?
array('a','b','c',1,2,3,4,5,'t','x','w')
You could also do this in one line using array_filter()
$numbers = array_filter($arr,function($e){return is_numeric($e);});
$alphas = array_filter($arr,function($e){return !is_numeric($e);});
print_r($numbers);
print_r($alphas);
Loop through them, check if is_numeric and add to appropriate array:
$original = array('a','b','c',1,2,3,4,5,'t','x','w');
$letters = array();
$numbers = array();
foreach($original as $element){
if(is_numeric($element)){
$numbers[] = $element;
}else{
$letters[] = $element;
}
}
https://3v4l.org/CAvVp
Using a foreach() like in #jnko's answer will be most performant because it only iterates over the array one time.
However, if you are not concerned with micro-optimization and prefer to write concise or functional-style code, then I recommend using array_filter() with is_numeric() calls, then making key comparisons between the first result and the original array.
Code: (Demo)
$array = ['a','b',0,'c',1,2,'ee',3,4,5,'t','x','w'];
$numbers = array_filter($array, 'is_numeric');
var_export($numbers);
var_export(array_diff_key($array, $numbers));
Output:
array (
2 => 0,
4 => 1,
5 => 2,
7 => 3,
8 => 4,
9 => 5,
)
array (
0 => 'a',
1 => 'b',
3 => 'c',
6 => 'ee',
10 => 't',
11 => 'x',
12 => 'w',
)
$data = array('a','b','c',1,2,3,4,5,'t','x','w');
$integerArray = array();
$stringArray = array();
$undefinedArray = array();
foreach($data as $temp)
{
if(gettype($temp) == "integer")
{
array_push($integerArray,$temp);
}elseif(gettype($temp) == "string"){
array_push($stringArray,$temp);
}else{
array_push($undefinedArray,$temp);
}
}
This question already has answers here:
How to access and manipulate multi-dimensional array by key names / path?
(10 answers)
Closed 6 years ago.
How can I convert a flat array into a nested array where the nested keys are prefixed with the same value. For example say I have the following array:
[
'name' => 'a',
'content' => 'b',
'author_fullName' => 'c',
'author_email' => 'd',
'author_role_name' => 'e'
]
Then the out of the array would be:
[
'name' => 'a',
'content' => 'b',
'author' => [
'fullName' => 'c',
'email' => 'd',
'role' => [
'name' => 'e'
]
]
]
Ideally I'd like a solution using the built in array functions as I prefer functional syntax rather than using for loops. I'd appreciate the help. Thanks
Try below code:
<?php
$a = [
'name' => 'a',
'content' => 'b',
'author_fullName' => 'c',
'author_email' => 'd',
'author_role_name' => 'e'
];
$finalArray =[];
array_walk($a, function(&$value, $key) use(&$finalArray) {
$indexes = explode('_',$key);
foreach ($indexes as $index){
$finalArray = &$finalArray[$index];
}
$finalArray = $value;
});
print_r($finalArray);
Another solution
$delimiter = '_';
$result = [];
foreach($array as $k => $v)
{
$split = explode($delimiter, $k, 2);//explode only as much as we need
if(count($split) > 1)
{
if(!isset($result[$split[0]]))
{
$result[$split[0]] = [];
}
//this assumes we're not interested in more than two depths
//in tandem with the explode limit
$result[$split[0]][$split[1]] = $v;
}
else
{
$result[$k] = $v;
}
}
This question already has answers here:
Merge two indexed arrays of indexed arrays based on first column value
(2 answers)
Closed 5 months ago.
I need to compare two 2D arrays in PHP. The arrays look like this:
Array one
ID Name
11 Aa
11 Ab
12 Bb
13 Cc
14 Dd
15 Ee
Array two
ID Content
11 Cat
13 Dog
14 Donkey
Now I'd need to combine these two into an array like this:
ID Name Conent
11 Aa Cat
11 Ab Cat
12 Bb
13 Cc Dog
14 Dd Donkey
15 Ee
How can I accomplish this? I have had no luck with array_merge() or $array3 = $array1 + $array2;
A quick way would be to iterate over the first array and append the value from the second:
$array1 = array('11' => 'Aa', '12' => 'Bb', '13' => 'Cc', '14' => 'Dd', '15' => 'Ee');
$array2 = array('11' => 'Cat', '13' => 'Dog', '14' => 'Donkey');
$combined = array();
foreach ($array1 as $key => $val) {
$combined[$key] = $val . (isset($array2[$key]) ? ' '.$array2[$key] : '');
}
This will loop through every key/value in $array1 and add it to the $combined array. If a value in $array2 exists with the same index, it will append it to that value from $array1, separated with a space.
UPDATE: I misread the format of the arrays (again). I assumed ID was the actual index in the array, but as the example array output has both Name and Content, I'm assuming ID is an actual index string value and not the index in the array itself. To stick with the loop scenario, you can iterate through the first array and have a nested loop iterate through the second:
$array1 = array(
array('ID' => '11', 'Name' => 'Aa'),
array('ID' => '12', 'Name' => 'Bb'),
array('ID' => '13', 'Name' => 'Cc'),
array('ID' => '14', 'Name' => 'Dd'),
array('ID' => '15', 'Name' => 'Ee'),
);
$array2 = array(
array('ID' => '11', 'Content' => 'Cat'),
array('ID' => '13', 'Content' => 'Dog'),
array('ID' => '14', 'Content' => 'Donkey')
);
$combined = array();
foreach ($array1 as $arr) {
$comb = array('ID' => $arr['ID'], 'Name' => $arr['Name'], 'Content' => '');
foreach ($array2 as $arr2) {
if ($arr2['ID'] == $arr['ID']) {
$comb['Content'] = $arr2['Content'];
break;
}
}
$combined[] = $comb;
}
This will add every value in $array1 to the combined array and if, and only if, a value in $array2 contains the same ID field will it add it's Content field to the array too. This can be extended to handle any number of fields as well, either by name, or by changing the inner-if block to have $comb += $arr2; instead (which should merge all non-existing indexes).
You will have to make your own function:
function putThemTogether($array1, $array2) {
$output = array();
foreach($array1 as $key => $value) {
if (!isset($output[$key]))
$output[$key] = array();
$output[$key][] = $value;
}
foreach($array2 as $key => $value) {
if (!isset($output[$key]))
$output[$key] = array();
$output[$key][] = $value;
}
return $output;
}
To make this better you could make it take an arbitrary number of arguments.
$result = array_map (
function ($item) { return is_array($item) ? implode(' ', $item) : $item; },
array_merge_recursive($array1, $array2);
);
Note, that both arrays require string keys
Another solution for this is to use array_search and array_column (since PHP 5.5.0).
foreach ($array1 as $key => $val) {
$found_key = array_search($val['ID'], array_column($array2, 'ID'));
if ($found_key !== false) { $array1[$key]['Content'] = $array2[$found_key]['Content']; }
}
Try this I hope It'll work
function merge_two_arrays($array1,$array2) {
$data = array();
$arrayAB = array_merge($array1,$array2);
foreach ($arrayAB as $value) {
// This assumes there is a field called "id"
$id = $value['id'];
if (!isset($data[$id])) {
$data[$id] = array();
}
$data[$id] = array_merge($data[$id],$value);
}
return $data;
}
$master_array = merge_two_arrays($array1,$array2);
I know this is quite easily accomplished with a foreach, then a while->list, etc procedure, (I have already accomplished it), however I sense that my code is a bit dirty and it doesn't look like the best solution... I'm looking to use native PHP array functions to do the following:
I have two arrays that look like this:
[
['rank' => '579', 'id' => '1'],
['rank' => '251', 'id' => '2'],
]
and
[
['size' => 'S', 'status' => 'A', 'id' => '1'],
['size' => 'L', 'status' => 'A', 'id' => '2'],
]
And I need merge them to produce:
[
['size' => 'S', 'status' => 'A', 'id' => '1', 'rank' => '579'],
['size' => 'L', 'status' => 'A', 'id' => '2', 'rank' => '251'],
]
Is there a way to be able to merge two arrays with the id value (or any other) without going into a endless set of foreachs?
Use array_merge_recursive()
$array = array_merge_recursive($array1, $array2);
or make your own function (it may be faster)
function my_array_merge(&$array1, &$array2) {
$result = Array();
foreach($array1 as $key => &$value) {
$result[$key] = array_merge($value, $array2[$key]);
}
return $result;
}
$array = my_array_merge($array1, array2);
print_r($array);
As Ray noticed in a comment, the accepted answer does not actually answer the question. I was unable to find an answer, so I created the following small utility function:
function array_merge_callback($array1, $array2, $predicate) {
$result = array();
foreach ($array1 as $item1) {
foreach ($array2 as $item2) {
if ($predicate($item1, $item2)) {
$result[] = array_merge($item1, $item2);
}
}
}
return $result;
}
Use it as follows:
array_merge_callback($array1, $array2, function ($item1, $item2) {
return $item1['id'] == $item2['id'];
});
Have a nice one to merging arrays like another languages.
It's because php have auto numbering array elements, and merging will dublicate or replace different elements by keys.
Now, it's changed.
// array_fork
public static function array_fork() {
$args = func_get_args();
$result = array();
foreach ($args as $arr) {
is_array($arr) || exit('[' . __METHOD__ . '] Each item must be an array.');
foreach ($arr as $key => $val) {
if (is_array($val)) {
// recursion
!isset($result[$key]) && $result[$key] = array();
$result[$key] = self::array_fork($result[$key], $arr[$key]);
continue;
}
if (is_numeric($key)) {
if (!in_array($arr[$key], $result))
$result[] = $arr[$key];
} else
$result[$key] = $arr[$key];
}
}
return $result;
}
function custom_array_merge(&$array1, &$array2) {
$result = Array();
foreach ($array1 as $key_1 => &$value_1) {
// if($value['name'])
foreach ($array2 as $key_1 => $value_2) {
if($value_1['name'] == $value_2['name']) {
$result[] = array_merge($value_1,$value_2);
}
}
}
return $result;
}
// Pass $array1, &$array2 and change the $value_2['name'] // name based on which u want to merge.
ok, let's suppost your arrays are called $arr1 and $arr2, you could do this:
<?php
$newarray = Array();
foreach ($arr1 as $element=>$value){
$newarray = array_merge($arr1[$element],$arr2[$element])
}
?>
It is not necessary to use a recursive technique nor multiple loops. Merge the two arrays together, then assign temporary first-level keys in the output array based on the rows' id value. If the id is being encountered for the first time, merge the row's data with an empty array; otherwise merge the pre-existing row data from result array. To remove the first-level keys after looping, call array_values().
Code: (Demo)
$a = [
['rank' => '579', 'id' => '1'],
['rank' => '251', 'id' => '2'],
];
$b = [
['size' => 'S', 'status' => 'A', 'id' => '1'],
['size' => 'L', 'status' => 'A', 'id' => '2'],
];
$result = [];
foreach (array_merge($a, $b) as $row) {
$result[$row['id']] = $row + ($result[$row['id']] ?? []);
}
var_export(array_values($result));
Not represented by the question's sample data, if the two data sets have columnar data collisions in their respective id group, then later encountered values will overwrite earlier stored values. Demo To reverse that behavior, you can simply swap the data on either side of the "array union operator". Demo Be warned that array union is suitable in this case because the rows contain non-numeric keys. For other scenarios, it may be more reliable to use array_merge() or array_replace() instead of the union operator.