I have two arrays: One generated from data extracted from a mySQL database with more than 100k elements. Each element is an associative array.
Now, I need to get each element from the second array and search for it (using certain keys to compare) in the first array and, if it doesn't exist, then add it.
Example:
$array1 = [
[
'uuid' => 001,
'name' => 'Isaak',
'surname' => 'Newton',
],
[
'uuid' => 002,
'name' => 'George',
'surname' => 'Washington',
],
[
'uuid' => 003,
'name' => 'Harry',
'surname' => 'Potter',
],
[
'uuid' => 004,
'name' => 'John',
'surname' => 'Doe',
],
[
'uuid' => 005,
'name' => 'Jack',
'surname' => 'Daniels',
],
[
'uuid' => 007,
'name' => 'Donnie',
'surname' => 'Trump',
],
[
'uuid' => 008,
'name' => 'Donnie',
'surname' => 'Trump',
]
];
Then, the second array
$array2 = [
[
'name' => 'Carl',
'surname' => 'Sagan',
],
[
'name' => 'Giorgio',
'surname' => 'Armani',
],
[
'name' => 'Harry',
'surname' => 'Potter',
]
];
In this example Carl Sagan and Giorgio Armani will be added to $array1. Currently I'm looping $array1 looking if there is an element with the same name and surname. If it doesn't, then add it.
The problem is, with the number of values that I have, the script is taking more than 2 hours to finish.
The function that I'm using to check if the element already exists is this:
foreach ($array2 as $array2Element)
foreach ($array1 as $array1Element) {
if ($array1Element['name'] == $array2Element['name'] &&
$array1Element['surname'] == $array2Element['surname']
) {
// Both keys matched, the element already exists!
$found = true;
break;
}
}
}
Is there any more efficient way to do this?
PS: The data comes as an array that I cannot control. I can add new keys if it helps, but I cannot change it another data structure.
Index both your arrays to use the comparison criteria as key. E.g.:
$array1 = [
'Isaak|Newton' => [
'uuid' => 001,
'name' => 'Isaak',
'surname' => 'Newton'
],
...
];
Make sure you create a unique key, so two different names won't concatenate to the same key accidentally.
Add both arrays together:
$array3 = $array1 + $array2;
Remove the keys again:
$array3 = array_values($array3);
Related
$arr = [
[
"id" => '6230061c0e88d709ca0d7bbc',
'name' => 'Mobile SamSung',
'slug' => 'mobile-samsung',
'createdAt' => '1648006346'
],
[
"id" => '5d1eff529a426778d4b92383',
'name' => 'Mobile Iphone',
'slug' => 'mobile-iphone',
'createdAt' => '1647314181'
],
[
"id" => '5d1eff6b9a426778d4b92dc4',
'name' => 'Mobile SamSung',
'slug' => 'mobile-samsung',
'createdAt' => '1647314460'
],
[
"id" => '5f894011266aea580b028cb0',
'name' => 'Mobile LG',
'slug' => 'mobile-lg',
'createdAt' => '1647314456'
]
];
I have an array, and in this array there are many duplicate subarrays, now I want to remove the duplicate arrays inside, keeping only the data with the latest createdAt. Please give me your opinion. Thanks
I would like to get an array like this:
$arr = [
[
"id" => '6230061c0e88d709ca0d7bbc',
'name' => 'Mobile SamSung',
'slug' => 'mobile-samsung',
'createdAt' => '1648006346'
],
[
"id" => '5d1eff529a426778d4b92383',
'name' => 'Mobile Iphone',
'slug' => 'mobile-iphone',
'createdAt' => '1647314181'
],
[
"id" => '5f894011266aea580b028cb0',
'name' => 'Mobile LG',
'slug' => 'mobile-lg',
'createdAt' => '1647314456'
]
];
You should not make more than one pass over your data. Just use the name values as temporary keys, then only retain a duplicate row's data if its createAt value is greater than what is stored. Re-index the array when you are finished looping.
Code: (Demo)
$result = [];
foreach ($arr as $row) {
if (!isset($result[$row['name']]) || (int)$row['createdAt'] > (int)$result[$row['name']]['createdAt']) {
$result[$row['name']] = $row;
}
}
var_export(array_values($result));
Output:
array (
0 =>
array (
'id' => '6230061c0e88d709ca0d7bbc',
'name' => 'Mobile SamSung',
'slug' => 'mobile-samsung',
'createdAt' => '1648006346',
),
1 =>
array (
'id' => '5d1eff529a426778d4b92383',
'name' => 'Mobile Iphone',
'slug' => 'mobile-iphone',
'createdAt' => '1647314181',
),
2 =>
array (
'id' => '5f894011266aea580b028cb0',
'name' => 'Mobile LG',
'slug' => 'mobile-lg',
'createdAt' => '1647314456',
),
)
Potentially helpful:
Laravel - fetch unique rows from table having highest value in x column
Remove duplicate objects from array based on one value, keep lowest of other value in PHP?
Filter rows with unique column value and prioritize rows with a particular value in another column
How to get max amount of value in same key in array
Explanation:
In this solution, I have gotten the data with a unique slug key with the latest createdAt key. we can have any unique key that matches into the multidimensional array and get the result whatever we want.
Code:
$newArray = [];
foreach ($array as $key => $value) {
$findIndex = array_search($value['slug'], array_column($newArray, 'slug'));
if ($findIndex === false) {
$newArray[] = $value;
} elseif ($findIndex !== false && $newArray[$findIndex]['createdAt'] <= $value['createdAt']) {
$newArray[$findIndex] = $value;
}
}
print_r($newArray);
Demo Link (With your Data): https://3v4l.org/f4kRM
Demo Link (Customized Data with my way): https://3v4l.org/sj4MW
First sort on created at, then remove duplicates.
<?php
$arr = [
[
"id" => '6230061c0e88d709ca0d7bbc',
'name' => 'Mobile SamSung',
'slug' => 'mobile-samsung',
'createdAt' => '1648006346'
],
[
"id" => '5d1eff529a426778d4b92383',
'name' => 'Mobile Iphone',
'slug' => 'mobile-iphone',
'createdAt' => '1647314181'
],
[
"id" => '5d1eff6b9a426778d4b92dc4',
'name' => 'Mobile SamSung',
'slug' => 'mobile-samsung',
'createdAt' => '1647314460'
],
[
"id" => '5f894011266aea580b028cb0',
'name' => 'Mobile LG',
'slug' => 'mobile-lg',
'createdAt' => '1647314456'
]
];
function sort_objects_by_created($a, $b) {
if($a['createdAt'] == $b['createdAt']){ return 0 ; }
return ($a['createdAt'] > $b['createdAt']) ? -1 : 1;
}
// Let's sort
usort($arr, 'sort_objects_by_created');
$slugs = [];
$result = [];
// Loop object
foreach($arr as $phone) {
// If slug is not found, add to result
if (!in_array($phone['slug'], $slugs)){
$slugs[] = $phone['slug'];
$result[] = $phone;
}
}
var_dump($result,$slugs);
Might be worth a note, that you might be able to improve this upstream when creating your array. (always look upstream!)
If you can give you base array a key of created At you can use Array sorting, which which will this step more effecient....
E.g.
$arr = [];
$arr[2022-01-01] = Array('id' => 123, 'name' = 'abc');
$arr[2022-04-01] = Array('id' => 123, 'name' = 'abc');
$arr[2022-08-01] = Array('id' => 123, 'name' = 'abc');
Following is the input array:
$input = [
[
'id' => 96,
'shipping_no' => 212755-1,
'part_no' => 'reterty',
'description' => 'tyrfyt',
'packaging_type' => 'PC'
],
[
'id' => 96,
'shipping_no' => 212755-1,
'part_no' => 'dftgtryh',
'description' => 'dfhgfyh',
'packaging_type' => 'PC'
],
[
'id' => 97,
'shipping_no' => 212755-2,
'part_no' => 'ZeoDark',
'description' => 's%c%s%c%s',
'packaging_type' => 'PC'
]
];
I want the above to be transformed into like this:
$output = [
[
'key' => 96,
'value' => [
[
'shipping_no' => 212755-1,
'part_no' => 'reterty',
'description' => 'tyrfyt',
'packaging_type' => 'PC'
],
[
'shipping_no' => 212755-1,
'part_no' => 'dftgtryh',
'description' => 'dfhgfyh',
'packaging_type' => 'PC'
]
]
],
[
'key' => 97,
'value' => [
[
'shipping_no' => 212755-2,
'part_no' => 'ZeoDark',
'description' => 's%c%s%c%s',
'packaging_type' => 'PC'
]
]
]
];
I have tried to implement it like this:
$result = [];
foreach ($input as $value) {
$result[] = ['key' => $value['id'], 'value' => ['shipping_no' => $value['shipping_no'], 'part_no' => $value['part_no'], 'description' => $value['description'], 'packaging_type' => $value['packaging_type']]];
}
It is not getting grouped based on common key. Please help me with the possible approach that I should take to solve this.
I can see that you've done a good job of crafting the new subarray structure, but the grouping should come first and because of how the grouping is done with temporary keys, the restructuring code can be simplified.
Code: (Demo)
$result = [];
foreach ($input as $row) {
$id = $row['id'];
unset($row['id']);
if (isset($result[$id])) {
$result[$id]['value'][] = $row;
} else {
$result[$id] = [
'key' => $id,
'value' => [$row]
];
}
}
var_export(
array_values($result)
);
To explain the process:
As you iterate the input array, cache the id of each encountered row of data.
Because you do not wish to retain the $row['id'] in your value subarray, you can now safely remove that element from the $row.
Then check if there is an existing group for the current $id with isset($result[$id]).
If the group already exists, then you can merely push the $row data as a new indexed row into the group's value subarray.
If the group does not already exist, then it needs to have all of the desired structure declared/populated. This means that the key element is declared and the value subarray must be declared with its first entry.
Finally, if you don't want the first level keys remove them with array_values().
I have an array with 3 levels and I'd like to merge/flatten all 3rd level subarrays into one subarray/row on the 2nd level.
$array = [
[
'User' => [
'id' => 57341,
'updated' => null,
'userId' => 57341,
'value' => null,
'lat' => 53.4537812,
'lon' => -2.1792437,
],
[
'feed_likes' => 'NA',
'category_idx' => -1,
'type' => 'User'
]
],
[
'User' => [
'id' => 57336,
'updated' => null,
'userId' => 57336,
'value' => null,
'lat' => 53.473684,
'lon' => -2.2399827,
],
[
'feed_likes' => 'NA',
'category_idx' => -1,
'type' => 'User'
]
],
];
The deep User-keyed subarrays (having 6 elements) should be merged with its sibling/indexed subarray (having 3 elements) to form a 9-element row on the second level.
Desired result:
[
[
'id' => 57341,
'updated' => null,
'userId' => 57341,
'value' => null,
'lat' => 53.4537812,
'lon' => -2.1792437,
'feed_likes' => 'NA',
'category_idx' => -1,
'type' => 'User'
],
[
'id' => 57336,
'updated' => null,
'userId' => 57336,
'value' => null,
'lat' => 53.473684,
'lon' => -2.2399827,
'feed_likes' => 'NA',
'category_idx' => -1,
'type' => 'User'
]
]
You can use splat ... operator with array_merge
foreach($a as $child){
$flatten[] = array_merge(...$child);
}
Working example :- https://3v4l.org/HkUh6
To merge and flatten the 3rd level data sets into consolidated 2nd level rows with functional style programming, make iterated calls of array_merge() which receive all 3rd level payloads at once. The spread operator (...) is a concise technique used to unpack multiple elements in an array. A special consideration is needed for this case because spreading elements which have non-numeric keys will cause code breakage. To overcome this, simply call array_values() to "index" the array (replace all keys with sequenial numbers) before spreading.
Code: (Demo)
var_export(
array_map(
fn($rows) => array_merge(...array_values($rows)),
$array
)
);
Slightly different to your example output, but you can merge your inner arrays.
<?php
$data =
[
[
'animal' => [
'type' => 'fox'
],
[
'colour' => 'orange'
]
],
[
'animal' => [
'type' => 'panda'
],
[
'colour' => 'black and white'
]
]
];
$result =
array_map(
function($v) {
return array_merge($v['animal'], $v[0]);
},
$data
);
var_export($result);
Output:
array (
0 =>
array (
'type' => 'fox',
'colour' => 'orange',
),
1 =>
array (
'type' => 'panda',
'colour' => 'black and white',
),
)
If I understood you correctly you need to merge User array and in this case with the second array in that key. it that case something like this should work
foreach($array as $key=>$deep1){
$newArray = [];
foreach($deep1 as $deep2){
$newArray = array_merge($newArray,$deep2)
}
$array[$key] = $newArray;
}
Did II understand your question correctly?
I have an array which I'm sure there are some duplicate values in it, I want to search in this array and find the duplicate values and return the key of that array.
let me explain with an example, this is my array:
[
0 => [
'name' => 'name0',
'family' => 'family0',
'email' => 'email0#sample.com',
'rate' => 10
],
1 => [
'name' => 'name1',
'family' => 'family1',
'email' => 'email1#sample.com',
'rate' => 4
],
2 => [
'name' => 'name0',
'family' => 'family0',
'email' => 'email0#sample.com',
'rate' => 6
]
];
Now, I want to search in this array by name, family, and email at the same time and return the key of the parent (in this example 0 and 2). because I want to create a new array like this :
[
0 => [
'name' => 'name0',
'family' => 'family0',
'email' => 'email0#sample.com',
'rate' => [
10,
6
]
],
1 => [
'name' => 'name1',
'family' => 'family1',
'email' => 'email1#sample.com',
'rate' => [
4
]
],
];
How can I do this in PHP?
You can use array-reduce and use the 3 similar fields as keys.
Define a function who create the key and set or add rate:
function combineRate($carry, $item) {
$k = implode('###', array($item['name'], $item['family'], $item['email']));
if (isset($carry[$k]))
$carry[$k]['rate'][] = $item['rate'];
else {
$item['rate'] = [$item['rate']];
$carry[$k] = $item;
}
return $carry;
}
Call it with empty array:
$res = array_values(array_reduce($a, 'combineRate', array()));
Live example: 3v4l
i have 2 array $dizi1 and $dizi2. And these are like this.
$dizi1 = [
[
'id' => 1,
'name' => 'özkan',
'surname' => 'özdemir',
],
[
'id' => 2,
'name' => 'çağrı',
'surname' => 'uğurel',
],
[
'id' => 3,
'name' => 'can',
'surname' => 'tokay'
],
[
'id' => 4,
'name' => 'lütfü',
'surname' => 'uzun'
]
];
$dizi2 = [
[
'id' => 2,
'birthday' => 1993
],
[
'id' => 3,
'birthday' => 1990
],
[
'id' => 4,
'birthday' => 1989
],
[
'id' => 1,
'birthday' => 1987
]
];
and this is what i want
istenenDizi = [
[
'id' => 1,
'name' => 'özkan',
'surname' => 'özdemir',
'birthday' => 1987,
]
];
i reseaxrh a lot bu i cant find a algortihm to do this. I will also create two excel table and i am gonna use this. Can you please help me how can i do this?
Thanksss!
You can use foreach(), array_search(),array_column() like below:-
$istenenDizi = [];
foreach($dizi1 as $dizi1){
$istenenDizi[$dizi1['id']] = $dizi1;
$istenenDizi[$dizi1['id']]['birthday'] = $dizi2[array_search($dizi1['id'],array_column($dizi2,'id'))]['birthday'];
}
$istenenDizi = array_values($istenenDizi);
print_r($istenenDizi);
Output:-https://eval.in/1000838
As you second array unsorted, you can sort it first. Then combine the two array by items. Demo.
usort($dizi2, function($a, $b){ return $a['id'] > $b['id'];});
foreach($dizi1 as $k=>$v){
$v['birthday'] = $dizi2[$k]['birthday'];
$result[] = $v;
}