PHP: Remove duplicate elements and get the latest data in the array - 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'
]
];
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');

Related

Remove a array from an multidimensional array using object value in laravel

i need to remove duplicate array from below array.
first and third arrays are same, consider only "id"
$data = [
[
'id' => 'test_fun%test',
'text' => 'test_fun',
'data-value' => 'test',
],
[
'id' => 'test_fun1%test',
'text' => 'test_fun1',
'data-value' => 'test',
],
[
'id' => 'test_fun%test',
'text' => 'test_fun',
'data-value' => 'test',
'selected' => true
]
];
i'm tried to below code.
-> array_unique($data);
-> array_map("unserialize", array_unique(array_map("serialize", $data)));
Expected Output
$data = [
[
'id' => 'test_fun1%test',
'text' => 'test_fun1',
'data-value' => 'test',
],
[
'id' => 'test_fun%test',
'text' => 'test_fun',
'data-value' => 'test',
'selected' => true
]
];
array_unique is not going to work since you have "selected" in the third array. I agree with the comments that this is quite unclear but to me it seems you're looking for a custom filtration rule, so a plain old foreach is the tool for the job.
<?php
$data = [
[
'id' => 'test_fun%test',
'text' => 'test_fun',
'data-value' => 'test',
],
[
'id' => 'test_fun1%test',
'text' => 'test_fun1',
'data-value' => 'test',
],
[
'id' => 'test_fun%test',
'text' => 'test_fun',
'data-value' => 'test',
'selected' => true
]
];
$filtered = [];
foreach ($data as $row) {
$id = $row['id'];
$selected = $row['selected'] ?? false;
if (isset($filtered[$id])) {
if (!$selected) {
continue;
}
unset($filtered[$id]);
}
$filtered[$id] = $row;
}
// optional use if you don't want ids for keys
$filtered = array_values($filtered);
print_r($filtered);

How to transform array of arrays into grouped arrays containing key and values?

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().

Merge/Flatten 3rd level data to create an array of arrays

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?

Search in multidimensional array by several values

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

Need to push the key and value inside associative Array?

I need to push the more key and its value inside the array. If I use below code first key pair replaced by 2nd one.
For your Reference:
Code Used:
foreach ($projectData['projectsections'] as $key => $name) {
$projectData['projectsections'][$key] = ['name' => $name];
$projectData['projectsections'][$key]= ['id' => '1'];
}
Current result:
'projectsections' => [
(int) 0 => [
'id' => '1'
],
(int) 1 => [
'id' => '1'
]
],
Expected:
'projectsections' => [
(int) 0 => [
'name' => 'test1',
'id' => '1'
],
(int) 1 => [
'name' => 'test2',
'id' => '1'
]
],
How can I build this array in PHP?? Any one help??
You need to either add the entire array:
$projectData['projectsections'][$key] = ['name' => $name, 'id' => '1'];
Or add with the key name:
$projectData['projectsections'][$key]['name'] = $name;
$projectData['projectsections'][$key]['id'] = '1';
With
$projectData['projectsections'][$key] = ['name' => $name];
$projectData['projectsections'][$key]= ['id' => '1'];
you are setting a new Array for that $key. This is not what you want.
This should work:
$projectData['projectsections'][$key] = ['name' => $name, 'id' => '1'];
Change it to :
foreach ($projectData['projectsections'] as $key => $name) {
$projectData['projectsections'][$key]['name'] = $name;
$projectData['projectsections'][$key]['id'] = '1';
}

Categories