Lower child array keys and combine items - php

I've one array
$arr = [
'parent' => [
'CHILD' => [
5,6
],
'child' => [
1,2,3,4
],
'Child' => [
5,6,7,8
],
...
]
];
I want to lower the child keys and combine each child having the same case insensitive keys like
$arr = [
'parent' => [
'child' => [
1,2,3,4,5,6,7,8
],
]
];
I've tried with array_change_key_case which always takes the last element and ignores the others.
An array may have multiple children with the same key (with different case)

Try the code below should work:
<?php
$arr = [
'parent' => [
'CHILD' => [
5,6
],
'child' => [
1,2,3,4
],
]
];
$arNew = [];
foreach ($arr as $sParent => $ar) {
foreach ($ar as $sChild => $ar1) {
$sChild = strtolower($sChild);
if (empty($arNew[$sParent][$sChild])) {
$arNew[$sParent][$sChild] = $ar1;
} else {
$arNew[$sParent][$sChild] = array_merge($arNew[$sParent][$sChild], $ar1);
}
}
}
print_r($arNew);

Related

PHP: Translation table to convert mutiple values to another value?

I have a a number of values/IDs that need to be translated to a single ID, what is the recommended method using PHP?
For example, I want IDs 38332, 84371, 37939, 1275 to all translate to ID 1234 and IDs222, 47391, 798 to all translate to ID 1235, etc. .
I'm thinking PHP has something built-in to handle this efficiently?
I'm thinking PHP has something built-in to handle this efficiently?
You can use the standard array as a map, quickly translating one ID to another:
$table[38332]; # int(1234)
depending on how you store your overall translation table, you can create a function that returns the translation from its input:
$table = $translation('I want IDs 38332, 84371, 37939, 1275 to all translate to ID 1234');
$result = $table[1275] ?? null; # int(1234)
Example:
$parseId = static fn(string $i) => (int)trim($i);
$translation = static fn(string $buffer): array
=> preg_match_all('~((?:\d+,\s*)+\d+)\s+to all translate to ID\s*(\d+)~', $buffer, $_, PREG_SET_ORDER)
? array_reduce($_, static fn (array $carry, array $item): array => [
$ids = array_map($parseId, explode(',', $item[1])),
$carry += array_fill_keys($ids, $parseId($item[2])),
$carry,][2], []) : [];
This is pretty easy to accomplish with PHP, here's one way you could do it:
Using this method, you populate the $map array, using the id you want to replace with as the key, and the value being an array of the keys you want to be replaced. It then calculates a simple key => value array based on this to make comparison a lot quicker.
Instead of creating a copy of the data, you could use foreach ($data as &$record)
$data = [
[
'id' => 1,
'foreign_id' => 38332,
'text' => 'a'
],
[
'id' => 2,
'foreign_id' => 84371,
'text' => 'b'
],
[
'id' => 3,
'foreign_id' => 37939,
'text' => 'c'
],
[
'id' => 4,
'foreign_id' => 1275,
'text' => 'd'
],
[
'id' => 5,
'foreign_id' => 222,
'text' => 'e'
],
[
'id' => 5,
'foreign_id' => 47391,
'text' => 'f'
],
[
'id' => 5,
'foreign_id' => 798,
'text' => 'g'
]
];
$map = [
123 => [
38332,
84371,
37939,
1275
],
1235 => [
222,
47391,
798
]
];
// Calculate a map to speed things up later
$map_calc = [];
foreach ($map as $destination_id => $ids) {
foreach ($ids as $id) {
$map_calc[$id] = $destination_id;
}
}
$new_data = [];
foreach ($data as $record) {
if (isset($map_calc[$record['foreign_id']]))
$record['foreign_id'] = $map_calc[$record['foreign_id']];
$new_data[] = $record;
}
var_dump($new_data);

PHP array diff: merge arrays recursively and show 'new' vs 'old' values in result

I would like to merge two arrays to compare old vs new values. For example, $arr1 is old values $arr2 is new values.
In case when the data is deleted $arr2 is an empty array. Example:
$arr1 = [
"databases" => [
0 => [
"id" => 1
"name" => "DB1"
"slug" => "db1"
"url" => "https://www.db1.org"
]
]
];
$arr2 = [];
For this my expected output after merge is
$merged = [
"databases" => [
0 => [
"id" => [
'old' => 1,
'new' => null
],
"name" => [
'old' => "DB1",
'new' => null
],
"slug" => [
'old' => "db1",
'new' => null
],
"url" => [
'old' => "https://www.db1.org",
'new' => null
],
]
]
];
if arr2 is different then the values should be present in the new field instead of null.
For example:
$arr1 = [
"databases" => [
0 => [
"id" => 1
"name" => "DB1"
"slug" => "db1"
"url" => "https://www.db1.org"
]
]
];
$arr2 = [
"databases" => [
0 => [
"id" => 5
"name" => "DB2"
"slug" => "db2"
"url" => "https://www.db2.com"
]
]
];
expected output:
$merged = [
"databases" => [
0 => [
"id" => [
'old' => 1,
'new' => 5
],
"name" => [
'old' => "DB1",
'new' => "DB2"
],
"slug" => [
'old' => "db1",
'new' => "db2"
],
"url" => [
'old' => "https://www.db1.org",
'new' => "https://www.db2.com"
],
]
]
];
Case 3 is when $arr1 is empty but $arr2 is populated:
$arr1 = [];
$arr2 = [
"databases" => [
0 => [
"id" => 1
"name" => "DB1"
"slug" => "db1"
"url" => "https://www.db1.org"
]
]
];
and the expected output is:
$merged = [
"databases" => [
0 => [
"id" => [
'old' => null,
'new' => 1
],
"name" => [
'old' => null,
'new' => "DB1"
],
"slug" => [
'old' => null,
'new' => "db1"
],
"url" => [
'old' => null,
'new' => "https://www.db1.org"
],
]
]
];
The inbuilt php functions cannot format the data in old vs new format so was wondering how to go about this? Any solutions/suggestions would be appreciated.
Update
Here is what I had tried before:
I had tried simple array_merge_recursive but it does not store the source array. So if you have $arr1 key not there, the final merged array will only have one value.
I tried some more recursive functions late in the night but failed so in essence didn't have anything to show for what I had tried. However, this morning, I came up with the solution and have posted it as an answer in case anyone needs to use it.
Interesting question, as long as a (non-empty) array on one side means to traverse into it and any skalar or null is a terminating node (while if any of old or new being an array would enforce traversing deeper so dropping the other non-array value):
It works by mapping both old and new on one array recursively and when the decision is to make to traverse to offer null values in case a keyed member is not available while iterating over the super set of the keys of both while null would represent no keys:
$keys = array_unique(array_merge(array_keys($old ?? []), array_keys($new ?? [])));
$merged = [];
foreach ($keys as $key) {
$merged['old'] = $old[$key] ?? null;
$merged['new'] = $new[$key] ?? null;
}
This then can be applied recursively, for which I found it is easier to handle both $old and $new as ['old' => $old, 'new' => $new] for that as then the same structure can be recursively merged:
function old_and_new(array $old = null, array $new = null): array
{
$pair = get_defined_vars();
$map =
static fn(callable $map, array $arrays): array => in_array(true, array_map('is_array', $arrays), true)
&& ($parameter = array_combine($k = array_keys($arrays), $k))
&& ($keys = array_keys(array_flip(array_merge(...array_values(array_map('array_keys', array_filter($arrays, 'is_array'))))))
)
? array_map(
static fn($key) => $map($map, array_map(static fn($p) => $arrays[$p][$key] ?? null, $parameter)),
array_combine($keys, $keys)
)
: $arrays;
return $map($map, $pair);
}
print_r(old_and_new(new: $arr2));
Online demo: https://3v4l.org/4KdLs#v8.0.9
The inner technically works with more than two arrays, e.g. three. And it "moves" the array keys upwards, similar to a transpose operation. Which btw. there is a similar question (but only similar, for the interesting part in context of your question it is not answered and my answer here doesn't apply there directly):
Transposing multidimensional arrays in PHP
After reviewing my own code here is the solution I came up with. I am posting it here in case someone else needs a solution for this:
/**
* Function to merge old and new values to create one array with all entries
*
* #param array $old
* #param array $new
* #return void
*/
function recursiveMergeOldNew($old, $new) {
$merged = array();
$array_keys = array_keys($old) + array_keys($new);
if($array_keys) {
foreach($array_keys as $key) {
$oldChildArray = [];
$newChildArray = [];
if(isset($old[$key])) {
if(!is_array($old[$key])) {
$merged[$key]['old'] = $old[$key];
} else {
$oldChildArray = $old[$key];
}
} else {
$merged[$key]['old'] = null;
}
if(isset($new[$key])) {
if( !is_array($new[$key])) {
$merged[$key]['new'] = $new[$key];
} else {
$newChildArray = $new[$key];
}
} else {
$merged[$key]['new'] = null;
}
if($oldChildArray || $newChildArray) {
$merged[$key] = recursiveMergeOldNew($oldChildArray, $newChildArray);
}
}
}
return $merged;
}
Note - this solution needs testing.

Combine two array using a field in PHP

I have an array in which i want to combine the common fields together.
So that the common names get grouped together and they contain the common values of that particular name.
Below is my array
[
[
count_employee: 2,
name: "Harry"
],
[
count_employee: 61,
name: "Jack"
],
[
count_employee: 11,
name: "John"
],
[
count_warehouse: 1,
name: "Harry"
],
[
count_warehouse: 77,
name: "John"
],
[
count_warehouse: 45,
name: "Jack"
]
]
I want the output to be
[
[
name: "Harry",
count_employee:2
count_warehouse:1
],
[
name: "Jack",
count_employee: 61
count_warehouse: 45
],
[
name: "John",
count_employee:11
count_warehouse:77
],
]
So far i have tried this out
foreach ($data as $key => $value) {
$group[$value['name']]['name'] = $value['name'];
$group[$value['name']][$key]['count_employee'] = $value['count_employee'];
$group[$value['name']][$key]['count_warehouse'] = $value['count_warehouse'];
}
Loop over the array, and use the name as the index of each element. If no element by that index does not exist, define it as an empty array.
Then all you need to do is add the fields (if they exist) to the proper column.
Your issue was that you were creating an array with one too many dimensions, instead of adding each value to the current count - in addition to the fact that you will not always have both the warehouse and employee count defined for each iteration.
$result = [];
foreach ($arr as $v) {
// Initialize the person
if (!isset($result[$v['name']])) {
$result[$v['name']] = ["name" => $v['name'], "count_employee" => 0, "count_warehouse" => 0];
}
// Add values
if (isset($v['count_employee']))
$result[$v['name']]['count_employee'] += $v['count_employee'];
if (isset($v['count_warehouse']))
$result[$v['name']]['count_warehouse'] += $v['count_warehouse'];
}
// print_r($result);
Live demo at https://3v4l.org/TeNKF
You can use array_walk with array_key_exists
$res=[];
array_walk($arr, function($v,$k) use (&$res){
if(array_key_exists($v['name'], $res))
$res[$v['name']]['count_warehouse'] = $v['count_warehouse'];
else
$res[$v['name']] = $v;
});
print_r(array_values($res));
Live Demo
Assuming all the array has a name key for each sub array contained within, we can use the name as a key for an array and merge arrays with corresponding name values.
<?php
$data=
[
[
'count_employee'=> 2,
'name'=> 'Harry'
],
[
'count_employee'=> 61,
'name'=> 'Jack'
],
[
'count_employee'=> 11,
'name'=> 'John'
],
[
'count_warehouse'=> 1,
'name'=> 'Harry'
],
[
'count_warehouse'=> 77,
'name'=> 'John'
],
[
'count_warehouse'=> 45,
'name'=> 'Jack'
]
];
$output = [];
foreach($data as $item) {
$output[$item['name']] = array_merge($item, $output[$item['name']] ?? []);
}
var_export($output);
Output:
array (
'Harry' =>
array (
'count_warehouse' => 1,
'name' => 'Harry',
'count_employee' => 2,
),
'Jack' =>
array (
'count_warehouse' => 45,
'name' => 'Jack',
'count_employee' => 61,
),
'John' =>
array (
'count_warehouse' => 77,
'name' => 'John',
'count_employee' => 11,
),
)

How can I match array in php?

I have 2 arrays, I want match this arrays and get results with keys.
Can I search in first array with second array keys or match diffrent way?
$boardLists = [
[
'_id' => 'a1a1a1',
'name' => 'Board Name #1',
'code' => 'B1'
],
[
'_id' => 'b2b2b2',
'name' => 'Board Name #2',
'code' => 'B2
]
];
and
$boards = [
'a1a1a1',
'b2b2b2',
'c3c3c3'
];
My result with array_intersect:
array(1) { [0]=> string(6) "a1a1a1" }
My expected result if match 'a1a1a1':
[
'_id' => 'a1a1a1',
'name' => 'Board Name #1',
'code' => 'B1'
],
That I could understand you want to search in the first array according to what you have in the second array, so here is one example:
$boardLists = [
[
'_id' => 'a1a1a1',
'name' => 'Board Name #1',
'code' => 'B1'
],
[
'_id' => 'b2b2b2',
'name' => 'Board Name #2',
'code' => 'B2'
]
];
$boards = [
'a1a1a1',
'b2b2b2',
'c3c3c3'
];
$boardListIds = array_column($boardLists, '_id');
$results = [];
foreach ($boards as $board) {
$find_key = array_search($board, $boardListIds);
if($find_key !== false)
$results[] = $find_key;
}
#printing the results
foreach ($results as $result) {
print_r($boardLists[$result]);
}
There many ways to do it, this is just one. I hope it helps. :)
It would be more efficient to have the array index of your first array the _id. However with the way the array is setup currently you could do:
foreach($boards as $key1=>board){
foreach($boardLists as $key2=>$boardList){
if($boardList['_id']==$key1){
echo $key1 . PUP_EOL;
print_r($boardList);
}
}
}
Try this
$finalArray = array();
foreach($boardLists as $key=>$val):
if(in_array($val['_id'],$boards))
{
$finalArray[] = $val2;
}
endforeach;

Merge collection of nested array elements into one array

I'm trying to merge a collection of nested array elements into one array.
Array:
crop_data = [
[
["crop" => "soy"] // 0
],
[
["crop" => "rye"] // 1
],
[
["crop" => "tree"] // 2
]
],
[
[
["crop" => "salt"] // 0
],
[
["crop" => "farm"] // 1
]
],
[
[
["year" => "2015"]
]
]
I've tried the following...
$crop_data = array(); // new array
foreach($crop_list as $value) {
$crop_data = array_merge($value, $crop_list));
}
I would like to merge the inner elements of the three arrays into one array. Any tips on how to achieve this?
You can use array_walk_recursive for this.
$merged = array();
array_walk_recursive($crop_data, function($v, $k) use (&$merged) {
$merged[$k][] = $v;
});

Categories