Compare some keys from 2 multidimensional arrays - php

I need to compare the value of the keys from 2 multidimensional arrays :
array1 [
0 => [
"designation" => "multiple"
"type" => "AAAAA"
"model" => "B"
"isSim" => false
"order" => 5
]
etc...
]
array2 [
0 => [
"designation" => "single"
"type" => "AACAA"
"model" => "B"
]
etc...
]
I would like to compare 'designation', 'type', 'model' from array1 to array2 and if the values are the same, I will set the 'isSim' to true.
I know how to set 'isSim' but I've got some difficulties to compare the 2 multidimensional arrays
NOTE => The 2 arrays don't have the same size

Should be something like the following:
$basearray = [["designation" => "multiple",
"type" => "AAAAA",
"model" => "B",
"isSim" => false,
"order" => 5 ]];
$compareto = [["designation" => "single"
"type" => "AACAA"
"model" => "B"]];
foreach($basearray as $base){
foreach($compareto as $compare){
if($compare["designation"] == $base["designation"] &&
$compare["type"] == $base["type"] &&
$compare["model"] == $base["model"]){
$base["isSim"] = true;
}
}
}
Additionally if you are sure that there can only be one array in $compareto that is the same as an array from $basearray you can put a break; after $base["isSim"] = true;.

Related

Merge two multidimensional arrays using recursion, but not on full data set

I'm trying to add 2 array data to each other with array_merge(). It's just attached to the back. But lower levels are ignored.
Is there an alternative to array_merge() that will merge the user values without duolicating the color values?
Existing array data:
$existingtArr = [
"A" => [
"color" => 'red',
"user" => [
"Daniel" => ["01:18:08", "04:10:12"],
"Max" => ["01:04:00"],
"Serto" => ["02:00:02"],
]
],
"B" => [
"color" => 'blue',
"user" => [
"Franz" => ["08:40:52"],
"Hugo" => ["07:08:58"],
]
]
];
New array data:
$newArr = [
"A" => [
"color" => 'red',
"user" => [
"Fabian" => ["06:03:00"], // + 1 user
"Max" => ["04:10:12"], // + 1 new time
"Serto" => ["02:00:02"],
]
],
"B" => [
"color" => 'blue',
"user" => [
"Franz" => ["08:40:52", "14:05:32", "20:34:15"], // an older one is available, + 2 new times
"Hugo" => ["04:10:12"], // + 1 time
]
],
"C" => [ // + new whole group
"color" => 'green',
"user" => [
"Maxi" => ["07:08:58", "04:10:12"],
]
]
];
Supplement the existing data with the new data:
echo '<pre>';
print_r(array_merge($existingtArr, $newArr));
echo '</pre>';
Expected result array data:
$resultArr = [
"A" => [
"color" => 'red',
"user" => [
"Daniel" => ["01:18:08", "04:10:12"],
"Fabian" => ["06:03:00"],
"Max" => ["01:04:00", "04:10:12"],
"Serto" => ["02:00:02"],
]
],
"B" => [
"color" => 'blue',
"user" => [
"Franz" => ["08:40:52", "14:05:32", "20:34:15"],
"Hugo" => ["07:08:58", "04:10:12"],
]
],
"C" => [
"color" => 'green',
"user" => [
"Maxi" => ["07:08:58", "04:10:12"],
]
]
];
You cannot simply call array_merge_recursive() on the whole data sets because they will generated repeated color values, but you want the color values to remain singular and the user data to be recursively merged.
To accommodate this logic (assuming it is okay to simply mutate the $existingtArr array with the data from $newArr), perform a check for the existence of each letter-set, and either push the whole set for a non-present letter, or recursively merge the shared letter-sets.
Code: (Demo)
foreach ($newArr as $letter => $set) {
if (!isset($existingtArr[$letter])) {
$existingtArr[$letter] = $set;
} else {
$existingtArr[$letter]['user'] = array_merge_recursive(
$existingtArr[$letter]['user'],
$set['user']
);
}
}
var_export($existingtArr);

Merge arrays in laravel including keys

I have 2 arrays and I want to merge them. (I can merge them) but I also need to include their unique keys in merged results and that part I cannot achieve.
sample
$prices = [
['112802' => "500000"],
['113041' => "1000000"],
];
$notes = [
['112802' => "note 2"],
['113041' => "note 1"],
];
$collection = collect($prices);
$zipped = $collection->zip($notes);
$zipped->toArray();
Unique keys are 112802 and 113041.
When I merge my array all I get is this:
[
[
"1000000",
"note 1"
],
[
"500000",
"note 2"
]
]
What I'm looking for is like this:
[
[
"id" => "112802",
"price" => "500000",
"note" => "note 2",
],
[
"id" => "113041",
"price" => "1000000",
"note" => "note 1",
]
}]
any suggestion?
This does what you want with the data you provide.
NOTE it will only work if your 2 arrays are the same size and the the keys are in the same order.
If this data comes from a database, it is likely it could have been produced in the format you actually wanted rather than having to fiddle with the data post fetch.
$prices = [
['112802' => "500000"],
['113041' => "1000000"],
];
$notes = [
['112802' => "note 2"],
['113041' => "note 1"],
];
$new = [];
foreach ($prices as $i=>$pr){
$k = key($pr);
$new[] = [ 'id' => $k,
'price' => $pr[$k],
'note' => $notes[$i][$k] ];
}
print_r($new);
RESULT
Array
(
[0] => Array (
[id] => 112802
[price] => 500000
[note] => note 2
)
[1] => Array (
[id] => 113041
[price] => 1000000
[note] => note 1
)
)
Here's another solution using some of Laravel's Collection methods.
It's not the most elegant, but it can be a starting point for you.
$prices = collect([
['112802' => "500000"],
['113041' => "1000000"],
])->mapWithKeys(function($item) {
// This assumes that the key will always be the ID and the first element is the price.
// Everythng else for each element will be ignored.
$id = array_keys($item)[0];
return [$id => ["id" => $id, "price" => reset($item)]];
});
$notes = collect([
['112802' => "note 2"],
['113041' => "note 1"],
])->mapWithKeys(function($item) {
$id = array_keys($item)[0];
return [$id => ["id" => $id, "note" => reset($item)]];
});
$result = $prices->zip($notes)->map(function ($item) {
// Feel free to call `toArray()` here if you don't want a Collection.
return collect($item)->mapWithKeys(function ($a) { return $a; });
});
Below is the $result (called using dd()).
Illuminate\Support\Collection {#1886 ▼
#items: array:2 [▼
0 => Illuminate\Support\Collection {#1888 ▼
#items: array:3 [▼
"id" => 112802
"price" => "500000"
"note" => "note 2"
]
}
1 => Illuminate\Support\Collection {#1889 ▼
#items: array:3 [▼
"id" => 113041
"price" => "1000000"
"note" => "note 1"
]
}
]
}
It's achieved by extracting the ID so that the zip can join there, but then we need a little hack with the map and mapWithKeys in the $result.
That's just because otherwise each element in $result will still have two separate arrays for $prices and $notes.

PHP efficient way to combine two associative arrays into one multidimensional associative array

This is the first problem:
I have two Associative Arrays, one containing sales persons and one containing clients.
$salesPersons = array(
array(
"id" => "1",
"name" => "Mr Smith",
"email" => "mrsmith#email.com",
"clients" => array()
),
array(
"id" => "2",
"name" => "James Bond",
"email" => "jamesbond#email.com",
"clients" => array()
)
);
$clients = array(
array(
"id" => "1",
"name" => "Lucifer Enterprises",
"salesPersonId" => "1"
),
array(
"id" => "2",
"name" => "Charlies Chocolate Factory",
"salesPersonId" => "1"
),
array(
"id" => "3",
"name" => "Geckos Investments",
"salesPersonId" => "2"
),
);
I want to map $salesPersons['id'] to clients['salesPersonId'] by ID and return a multidimensional associative array like this:
$result_i_want = array(
array(
"id" => "1",
"name" => "Mr Smith",
"email" => "mrsmith#email.com",
"clients" => array(
array(
"id" => "1",
"name" => "Lucifer Enterprises",
),
array(
"id" => "2",
"name" => "Charlies Chocolate Factory",
),
)
),
array(
"id" => "2",
"name" => "James Bond",
"email" => "jamesbond#email.com",
"clients" => array(
array(
"id" => "3",
"name" => "Geckos Investments",
),
)
)
);
My solution to the first problem
I have solved it using nested foreach-loops and array_push
$result = array();
foreach ($clients as $c_record) {
foreach ($salesPersons as $s_record) {
if ($c_record['salesPersonId'] == $s_record['id']) {
array_push($s_record['clients'], array(
"id" => $c_record['id'],
"name" => $c_record['name']
));
array_push($result, $s_record);
}
}
}
The remaining problem
This solution doesn't seem to be very efficient.
For each client record I check all sales persons to see if there is a match. I think the number of computations are:
no. of clients * no. of sales persons
I have a huge database and also need to add even more dimensions by mapping projects to the clients and deliverables to the projects. I think this could pose a problem.
Question
Is there a more efficient way to get the same result?
Build an index :
you need to access your salesPerson entries by id, you can start by creating an associative array id => salesPerson, and then use this associative array in your loop.
$salesById = array();
foreach ($salesPersons as $s_record) {
$salesById[ $s_record['id'] ] = $s_record;
}
$result = array();
foreach ($clients as $c_record) {
$s_record = $salesById[ $c_record['salesPersonId'] ];
if ($s_record == null) {
// you may want to handle invalid ids in the client array
// one way is to simply ignore this client record :
continue;
}
array_push($s_record['clients'], array(
"id" => $c_record['id'],
"name" => $c_record['name']
));
array_push($result, $s_record);
}
Notes
There may be a problem in the way you create your $result array :
if a sales person has n clients, the $result array will reference that sales person n times.
Look closer into what result you actually want, you may simply want to return $salesPersons, or $salesById.
As LeGEC said:
you need to access your salesPerson entries by id, you can start by creating an associative array id => salesPerson, and then use this associative array in your loop.
You need to set the index of your arrays with the id:
<?php
$salesPersons = array(
1 => array(
"id" => "1",
"name" => "Mr Smith",
"email" => "mrsmith#email.com",
"clients" => array()
),
2 => array(
"id" => "2",
"name" => "James Bond",
"email" => "jamesbond#email.com",
"clients" => array()
)
);
$clients = array(
1 => array(
"id" => "1",
"name" => "Lucifer Enterprises",
"salesPersonId" => "1"
),
2 => array(
"id" => "2",
"name" => "Charlies Chocolate Factory",
"salesPersonId" => "1"
),
3 => array(
"id" => "3",
"name" => "Geckos Investments",
"salesPersonId" => "2"
),
);
Then:
$result = array();
foreach ($clients as $id => $c_record) {
if (isset($salesPersons[$id])) {
$result[] = array_merge($clients[$id], $salesPersons[$id]);
} else {
$result[] = $clients[$id];
}
}
var_dump($result);
Result here: http://sandbox.onlinephpfunctions.com/code/e590bdb5aaea2794fc5a04ee60f61db766129664
PS:
My code works with your use case, but it will not work if the size of the $salesPersons array is bigger than the $clients array

PHP - Get the key that has a value in multiple indexes

I have the below array:
$myArray = [
[
"name" => null,
"price" => [
"height" => 0.0098974902792506,
"left" => 0.8385,
"page" => 1,
"top" => 0.51290208554259,
"width" => 0.0275,
],
],
[
"name" => null
"price" => [
"height" => 0.0098974902792506,
"left" => 0.838,
"page" => 1,
"top" => 0.56981265464829,
"width" => 0.028,
]
],
[
"name" => null
"price" => [
"height" => 0.010250972074938,
"left" => 0.5905,
"page" => 1,
"top" => 0.44114528101803,
"width" => 0.0285,
]
]
];
I am trying to check the array and get the name of the key that has a value (is not null) in each array. In the above example, this would be price.
However, the array could also look like this:
[
[
"name" => null,
"price" => [
"height" => 0.0098974902792506,
"left" => 0.8385,
"page" => 1,
"top" => 0.51290208554259,
"width" => 0.0275,
],
],
[
"name" => null
"price" => null
],
[
"name" => null
"price" => null
]
]
In this case, there is not an array key that has a value in all of the arrays.
Below is my attempt to achieve this:
$originalKeyWithValue = null;
foreach($myArray as $key => $item)
{
$originalKeyWithValue = array_key_first($item);
if (isset($myArray[$key+1])) {
$nextKeyWithValue = array_key_first($myArray[$key+1]);
if($originalKeyWithValue != $nextKeyWithValue){
$originalKeyWithValue = $nextKeyWithValue;
}
}
}
return $originalKeyWithValue;
However the code above returns name as the key, even though it is null in all of the arrays in $myArray.
This is what would I do:
// I take first element of array as a source for indexes
foreach ($myArray[0] as $index => $item) {
// next I extract all elements from all subarrays under current `$index`
$values = array_column($myArray, $index);
// then I filter values to remove nulls.
// This also removes 0, empty arrays, false,
// so maybe you should change filter process
$values_filtered = array_filter($values);
// if number of filtered items is same as in original array - no nulls found
if (count($values_filtered) === count($values)) {
echo $index;
// optionally
// break;
}
}
Although there is an accepted answer, I thought I would share a way to do this using Laravel collections.
$uniqueKeysWithValues = collect($myArray)->map(function($item){
return array_keys( collect($item)->filter()->toArray() ); //filter will remove all null
})->flatten()->unique();
This approach will give you all keys that has values in it, even if there are values in both keys.

Removing an element from a nested array in PHP

Am working on a Laravel application whereby I have an associative array that am to pass to an API endpoint, Before posting to the API, I want to delete the img key together with its value . I have tried to use unset function but it is not removing the img key
Array where I want to remove the image property
$a[] = [
0 => array:4 [
"name" => "Martoo nnn"
"relationship" => "Spouse"
"dob" => "2001-02-03"
"img" => "img.png"
]
1 => array:4 [
"name" => "sdsdsd sdsdsd"
"relationship" => "Child"
"dob" => "2019-04-04"
"img" => "img1.png"
]
2 => array:4 [
"name" => "sdsdsd sddds"
"relationship" => "Child"
"dob" => "2019-04-05"
"img" => "img2.png"
]
3 => array:4 [
"name" => "dssdsd dsdsd"
"relationship" => "Child"
"dob" => "2019-04-02"
"img" => "img3.png"
]
4 => array:4 [
"name" => "dssdsd dssdsd"
"relationship" => "Child"
"dob" => "2019-04-04"
"img" => "img4.png"
]
];
Unset method
$array = $a;
unset($array['img']);
//dd($a);
You can do something like this,
foreach ($array as $key => &$value) { // & defines changes will be made # value itself
unset($value['img']);
}
And Yes, I don't understand why you initialised $a as $a[]?
$newarray = array_filter($a, function($k) {
return $k != 'img';
}, ARRAY_FILTER_USE_KEY);
and pass this new array

Categories