multidimensional array remove item from child array - php

i have a problem with my multidimensional array. I want to remove some items from child array by $id value.
here is my multidimensional example array and selectedIds:
$myArray = [
['id' => '2',
'name' => 'Punk'
],[
'id' => '5',
'name' => 'Rock',
'children' => [
'30' => ['id' => '30',
'name' => 'Hard Rock',
'parentId' => '5'
],
'40' => ['id' => '40',
'name' => 'Soft Rock',
'parentId' => '5'
],
'50' => ['id' => '50',
'name' => 'Glam Rock',
'parentId' => '5'
]
]
]
];
$selectedIds = [2,5,30];
and i want to remove from array those items which are not in selectedIds array.
so i want to have output:
$outputArray = [
[
'id' => '2',
'name' => 'Punk'
],[
'id' => '5',
'name' => 'Rock',
'children' => [
'30' => ['id' => '30',
'name' => 'Hard Rock',
'parentId' => '5']
]
]
];
i try to make it with foreach and array_key_exist but its not correct:
foreach ($myArray as $key=>$value) {
if (array_key_exists('children', $value)) {
foreach ($selectedIds as $id) {
if (isset($value['children'][$id])) {
$outputArray[] = $value['children'][$id];
}
}
}
}
print_r($outputArray);
this outpus is only item with id 30

write else part into your code if array has no children key
else{
foreach ($selectedIds as $id) {
if ($value['id'] == $id) {
$outputArray[$key] = $value;
}
}
}
Final code
<?PHP
$myArray = [
[
'id' => '2',
'name' => 'Punk'
],
[
'id' => '5',
'name' => 'Rock',
'children' => [
'30' => ['id' => '30',
'name' => 'Hard Rock',
'parentId' => '5'
],
'40' => ['id' => '40',
'name' => 'Soft Rock',
'parentId' => '5'
],
'50' => ['id' => '50',
'name' => 'Glam Rock',
'parentId' => '5'
]
]
]
];
$selectedIds = [2,5,30];
foreach ($myArray as $key=>$value) {
if (array_key_exists('children', $value)) {
foreach ($selectedIds as $id) {
if (isset($value['children'][$id])) {
$outputArray[$key]['id'] = $value['id'];
$outputArray[$key]['name'] = $value['name'];
$outputArray[$key]['children'][$id] = $value['children'][$id];
}
}
}else{
foreach ($selectedIds as $id) {
if ($value['id'] == $id) {
$outputArray[$key] = $value;
}
}
}
}
echo "<pre>";
print_r($outputArray);
?>
Output
Array
(
[0] => Array
(
[id] => 2
[name] => Punk
)
[1] => Array
(
[id] => 5
[name] => Rock
[children] => Array
(
[30] => Array
(
[id] => 30
[name] => Hard Rock
[parentId] => 5
)
)
)
)

Hey i make other code more simple. That´s here:
just change a bit the foreach content:
foreach ($myArray as $key=>&$value) {
if (array_key_exists('children', $value)) {
$value['children'] = array_intersect_key($value['children'], array_flip($selectedIds));
}
}
Use array_flipfor transform keys on values and array_intersect_keyfor get only they id´s that exist in 2 arrays.
here you can see a live demo
NOTE: take care that i´m passing the value by referer &$value in the foreach for modify the original array, if you dont want this just duplicate the original array and modify the second.

Related

php in_array between 2 arrays

I am trying to determine which elements coincide in 2 arrays. The issue is that only the last element in my second array is selected instead of all 3. What am I missing here?
<?php
$containers = [
0 => ['id'=>'1', 'name'=>'Peta'],
1 => ['id'=>'2', 'name'=>'Epta'],
3 => ['id'=>'3', 'name'=>'Fras'],
4 => ['id'=>'4', 'name'=>'Maxs'],
5 => ['id'=>'5', 'name'=>'Gtay'],
6 => ['id'=>'6', 'name'=>'Prat'],
7 => ['id'=>'7', 'name'=>'Drat'],
];
$invoices = [
0 => ['id'=>'1', 'name'=>'Lebo'],
1 => ['id'=>'3', 'name'=>'Efta'],
2 => ['id'=>'4', 'name'=>'Gadr'],
];
foreach ($containers as $container) {
foreach ($invoices as $invoice) {
if (in_array($container['id'], $invoice)) {
$selected = 'selected';
} else {
$selected = '';
}
}
echo $container['name'].' -> '.$selected.'<br>';
} ?>
Add "break" after found in array.
<?php
$containers = [
0 => ['id' => '1', 'name' => 'Peta'],
1 => ['id' => '2', 'name' => 'Epta'],
3 => ['id' => '3', 'name' => 'Fras'],
4 => ['id' => '4', 'name' => 'Maxs'],
5 => ['id' => '5', 'name' => 'Gtay'],
6 => ['id' => '6', 'name' => 'Prat'],
7 => ['id' => '7', 'name' => 'Drat'],
];
$invoices = [
0 => ['id' => '1', 'name' => 'Lebo'],
1 => ['id' => '3', 'name' => 'Efta'],
2 => ['id' => '4', 'name' => 'Gadr'],
];
foreach ($containers as $container) {
foreach ($invoices as $invoice) {
if (in_array($container['id'], $invoice)) {
$selected = 'selected';
break;
} else {
$selected = '';
}
}
echo $container['name'] . ' -> ' . $selected . '<br>';
} ?>
$containers = [
[ 'id' => '1', 'name' => 'Peta' ],
[ 'id' => '2', 'name' => 'Epta' ],
[ 'id' => '3', 'name' => 'Fras' ],
[ 'id' => '4', 'name' => 'Maxs' ],
[ 'id' => '5', 'name' => 'Gtay' ],
[ 'id' => '6', 'name' => 'Prat' ],
[ 'id' => '7', 'name' => 'Drat' ],
];
$invoices = [
[ 'id' => '1', 'name' => 'Lebo' ],
[ 'id' => '3', 'name' => 'Efta' ],
[ 'id' => '4', 'name' => 'Gadr' ],
];
$result = array_filter(
$containers,
fn($item) => in_array($item['id'], array_column($invoices, 'id'))
);
print_r($result);
Output:
Array
(
[0] => Array
(
[id] => 1
[name] => Peta
)
[2] => Array
(
[id] => 3
[name] => Fras
)
[3] => Array
(
[id] => 4
[name] => Maxs
)
)
Seems the easiest solution was to create a new array:
foreach ($invoices as $invoice) {
$compare_id[] = $invoice['id'];
}
foreach ($containers as $container) {
if (in_array($container['id'], $compare_id)) {
$selected = 'selected';
} else {
$selected = '';
}
echo $container['name'].' -> '.$selected.'<br>';
}

How can I create an array without duplicates with this structure

I have this array structure:
array (
0 =>
array (
'id' => '17',
'name' => 'aba aba',
'english_name' => 'ABA ABA',
'group_id' => '1',
),
1 =>
array (
'id' => '23',
'name' => 'bcb bcb',
'english_name' => 'BCB BCB',
'group_id' => '2',
),
2 =>
array (
'id' => '17',
'name' => 'aba aba',
'english_name' => 'ABA ABA',
'group_id' => '4',
),
);
I want to create another array with no duplicates but having in mind in which group_id are the duplicate ones. I'm looking for this structure:
array (
17 =>
array (
'name' => 'ABA ABA',
'groups' =>
array (
0 => '1',
1 => '4',
),
),
23 =>
array (
'name' => 'BCB BCB',
'groups' =>
array (
0 => '2',
),
),
);
I tried with this code but it doesn't give me what I'm looking for, I don't know what I'm doing wrong.
Code:
foreach ($array as $value) {
if (!in_array($value['id'], $array[$value['id']] )) {
$interested [$value['id']]['name'] = $value['english_name'];
$interested [$value['id']]['groups'][]= $value['group_id'];
} else if (in_array($value['id'], $array[$value['id']] )){
$interested [$value['id']]['groups'][] = $value['group_id'];
}
}
Simple loop and assign using the id as your pivot:
<?php
$data =
array (
0 =>
array (
'id' => '17',
'name' => 'aba aba',
'english_name' => 'ABA ABA',
'group_id' => '1',
),
1 =>
array (
'id' => '23',
'name' => 'bcb bcb',
'english_name' => 'BCB BCB',
'group_id' => '2',
),
2 =>
array (
'id' => '17',
'name' => 'aba aba',
'english_name' => 'ABA ABA',
'group_id' => '4',
),
);
foreach($data as $item) {
$result[$item['id']]['name'] = $item['english_name'];
$result[$item['id']]['groups'][] = $item['group_id'];
}
var_export($result);
Output:
array (
17 =>
array (
'name' => 'ABA ABA',
'groups' =>
array (
0 => '1',
1 => '4',
),
),
23 =>
array (
'name' => 'BCB BCB',
'groups' =>
array (
0 => '2',
),
),
)
$data = array (
0 =>
array (
'id' => '17',
'name' => 'aba aba',
'english_name' => 'ABA ABA',
'group_id' => '1',
),
1 =>
array (
'id' => '23',
'name' => 'bcb bcb',
'english_name' => 'BCB BCB',
'group_id' => '2',
),
2 =>
array (
'id' => '17',
'name' => 'aba aba',
'english_name' => 'ABA ABA',
'group_id' => '4',
),
);
function unique_multidim_array($array, $key) {
$temp_array = array();
$i = 0;
$key_array = array();
foreach($array as $val) {
if (!in_array($val[$key], $key_array)) {
$key_array[$i] = $val[$key];
$temp_array[$i] = $val;
}
$i++;
}
return $temp_array;
}
$newdata = unique_multidim_array($data,'id');
The function taken from here. Details on : https://www.php.net/manual/tr/function.array-unique.php
It isn't very clear from your code what you are trying to do, but below is one way.
Loop over your subarrays one by one.
have a new array, say $set which will be an associative array of keys and values where keys are the IDs and values are the name and groups attributes.
If $set has the ID isset already, add to groups, else, create a new one and then add groups.
Snippet:
<?php
$set = [];
foreach($array as $val){
$group_id = $val['group_id'];
if(!isset($set[$val['id']])){
$set[$val['id']] = [
'name' => $val['english_name'],
'groups' => []
];
}
$set[$val['id']]['groups'][] = $group_id;
}
print_r($set);
Demo: http://sandbox.onlinephpfunctions.com/code/af65effc35a0275bdf6908c77dc0cb701d36010e
Functional way)
function group( $groups, $item ) {
$id = $item['id'];
if ( !isset($groups[$id]) ) {
$groups[$id] = array (
'name' => $item['name'],
'groups' => array(),
);
}
array_push($groups[$id]['groups'], $item['group_id']);
return $groups;
}
array_reduce($data, 'group', array());
Please take a look at playground
Also to make groups array unique PHP Collections could be used. For example, Set data structure.

Group/Merge rows from two 2d arrays based on 3 identifying columns and fill missing column values with null

I'm need to merge two 2d arrays by their time, size, and type values. This should created grouped data where value_one and value_two elements may exist in the same row. If there aren't two rows to merge together, then I need the missing element to be set to null -- this way all rows will have the same elements/structure.
$array1 = [
[
'date' => '2018-06-23',
'size' => 'L',
'type' => 'shoes',
'value_one' => '66',
],
[
'date' => '2018-06-23',
'size' => 'XL',
'type' => 'shirt',
'value_one' => '43',
],
[
'date' => '2018-06-23',
'size' => 'M',
'type' => 'Bag',
'value_one' => '23',
]
];
And
$array2 = [
[
'date' => '2018-06-23',
'size' => 'L',
'type' => 'shoes',
'value_two' => '28',
],
[
'date' => '2018-06-23',
'size' => 'XL',
'type' => 'shirt',
'value_two' => '56',
],
[
'date' => '2018-06-23',
'size' => 'M',
'type' => 'Bag',
'value_two' => '14',
],
[
'date' => '2018-06-23',
'size' => 'S',
'type' => 'Cap',
'value_two' => '29',
]
]
Desired result:
[
[
'date' => '2018-06-23',
'size' => 'L',
'type' => 'shoes',
'value_one' => '66',
'value_two' => '28',
],
[
'date' => '2018-06-23',
'size' => 'XL',
'type' => 'shirt',
'value_one' => '43',
'value_two' => '56',
],
[
'date' => '2018-06-23',
'size' => 'M',
'type' => 'Bag',
'value_one' => '23',
'value_two' => '14',
],
[
'date' => '2018-06-23',
'size' => 'S',
'type' => 'Cap',
'value_one' => null,
'value_two' => '29',
]
]
I want to solve this case with php, laravel or collection "Laravel" class.
I tried to create the array and merge using array_merge_recursive(), array_merge(), or using this code:
foreach ($d as $k => $v) {
$new_arr[$v['date']][] = $v;
}
try
//both arrays will be merged including duplicates
$result = array_merge( $array1, $array2 );
//duplicate objects will be removed
$result = array_map("unserialize", array_unique(array_map("serialize", $result)));
//array is sorted on the bases of id
sort( $result );
For an elegant solution that only needs one loop, use the following:
Hardcode an array of default keys in your desired order.
Merge the arrays and iterate.
Identifying matching data sets by the first three elements in each row.
Depending on whether the composite key has been encountered before, overwrite the default or cached data with the current row.
To remove temporary composite key after looping, call array_values() on the result array.
Code: (Demo)
$defaults = array_fill_keys(['date', 'size', 'type', 'value_one', 'value_two'], null);
$result = [];
foreach (array_merge($array1, $array2) as $row) {
$compositeKey = implode('_', array_slice($row, 0, 3));
$result[$compositeKey] = array_merge($result[$compositeKey] ?? $defaults, $row);
}
var_export(array_values($result));
You can try this
$Array_final= [];
foreach ($Array_one as $key1 => $value1) {
foreach ($Array_two as $key2 => $value2) {
if ($value1['date']==$value2['date']) {
$Array_final[]=$value2+$value1;
}
}
}
You can try this :-
$final = $arr1; // default get all values from first array
foreach ($arr2 as $value) { // loop through second array to match
$flag = 0;
foreach ($final as $key => $data) {
// Check for date, size and type
if ($data['date']===$value['date'] && $data['size']===$value['size'] && $data['type']===$value['type']) {
$final[$key]['value_two'] = $value['value_two'];
$flag = 1;
break;
}
}
if ($flag === 0) { // If similar not found, then add new one
array_push($final, $value);
}
}
print_r($final);
Output :-
Array
(
[0] => Array
(
[date] => 2018-06-23
[size] => L
[type] => shoes
[value_one] => 66
[value_two] => 28
)
[1] => Array
(
[date] => 2018-06-23
[size] => XL
[type] => shirt
[value_one] => 43
[value_two] => 56
)
[2] => Array
(
[date] => 2018-06-23
[size] => M
[type] => Bag
[value_one] => 23
[value_two] => 14
)
[3] => Array
(
[date] => 2018-06-23
[size] => S
[type] => Cap
[value_two] => 29
)
)
Fiddle link :- https://3v4l.org/fSh1V
try
var result = a1.slice(0);
for (var i = 0 ; i < result.length ; i++){
for (var j = 0; j < a2.length ; j++){
if (result[i]. date == a2[j]. date && result[i]. size == a2[j]. size && result[i]. type == a2[j]. type){
result[i]. value_one = a2[j]. value_one;
result[i]. value_two = a2[j].value_two;
}
};
};
console.log(result);

Counting occurrences in an array that has more than 1 key

I'm trying to get the occurrences of an array taking in count 1 key value, for example:
$newarray[0] = [
'id' => '2',
'date' => '2016-04-22'
];
$newarray[1] = [
'id' => '2',
'date' => '2016-04-13'
];
$newarray[2] = [
'id' => '2',
'date' => '2016-04-12'
];
$newarray[3] = [
'id' => '1',
'date' => '2016-03-11'
];
$newarray[4] = [
'id' => '2',
'date' => '2016-03-05'
];
$newarray[5] = [
'id' => '1',
'date' => '2016-03-01'
];
I want to transform this, to something like this:
Array ( [0] => Array ( [id] => 1 [date] => 2016-03-11 [occurences] => 2 ) [1] => Array ( [id] => 2 [date] => 2016-04-22 [occurences] => 4 ) )
I tried doing this:
$cleanarray;
$newarray2=$newarray;
$newarray;
$k=0;
$num=1;
for($i=0; $i<count($newarray); $i++){
for($j=1; $j<count($newarray2); $j++){
if($newarray2[$j]["id"]==$newarray[$i]["id"]){
$num++;
}
}
$cleanarray[$k] = [
'id' => $newarray[$i]["id"],
'date' => $newarray[$i]["date"],
'occurences' => $num
];
$k++;
$num=0;
}
But a lot of items repeat, with the same occurrences but several times, and in other cases the repeated items (with same id) would have different occurrences, so I don't know what can I do, I know that there is a function of:
$occurences = array_count_values($array);
But it doesn't work in this case, how can I approach to the solution?
I know what are you looking for, but I think this could solve your problems:
$newarray[0] = [
'id' => '2',
'date' => '2016-04-22'
];
$newarray[1] = [
'id' => '2',
'date' => '2016-04-12'
];
$newarray[2] = [
'id' => '2',
'date' => '2016-04-12'
];
$newarray[3] = [
'id' => '1',
'date' => '2016-03-11'
];
$newarray[4] = [
'id' => '2',
'date' => '2016-03-05'
];
$newarray[5] = [
'id' => '1',
'date' => '2016-03-01'
];
foreach($newarray as $key => $value){
if(isset($found[$value['id']][$value['date']])) {
$found[$value['id']][$value['date']]++;
} else {
$found[$value['id']][$value['date']] = 1;
}
}
print_r($found);
this will return something like:-
Array
(
[2] => Array
(
[2016-04-22] => 1
[2016-04-12] => 2
[2016-03-05] => 1
)
[1] => Array
(
[2016-03-11] => 1
[2016-03-01] => 1
)
)
Using temporary keys for this process will be the most performant way. Temporary keys simplify the output array task, requiring less and faster checking. If you wish to sort on id after the result array is generated, the temporary keys allow a simple ksort() call.
Code: (Demo)
$newarray=[
['id' => '2','date' => '2016-04-22'],
['id' => '2','date' => '2016-04-13'],
['id' => '2','date' => '2016-04-12'],
['id' => '1','date' => '2016-03-11'],
['id' => '2','date' => '2016-03-05'],
['id' => '1','date' => '2016-03-01']
];
foreach($newarray as $a){
if(!isset($result[$a['id']])){
$result[$a['id']]=array_merge($a,['occurrences'=>1]); // use id as temp key, preserve first found date
}else{
++$result[$a['id']]['occurrences']; // only update occurrences to preserve date
}
}
ksort($result); // optionally sort on id ASC
var_export(array_values($result)); // remove temporary keys from first level and print to screen
Output:
array (
0 =>
array (
'id' => '1',
'date' => '2016-03-11',
'occurrences' => 2,
),
1 =>
array (
'id' => '2',
'date' => '2016-04-22',
'occurrences' => 4,
),
)
You can do it like below:-
$final_array = array();
foreach($newarray as $arr){
if(!in_array($arr['id'],array_keys($final_array))){
$final_array[$arr['id']] = $arr;
$final_array[$arr['id']]['occurences'] = 1;
}else{
$final_array[$arr['id']]['occurences'] += 1;
}
}
$final_array= array_values($final_array);
print_r($final_array);
Output:- https://eval.in/847242
Note:- if you want final array to be ascending order of id then use usort() function like below:-
function cmpId($a, $b) {
return ($a['id'] - $b['id']);
}
usort($final_array, "cmpId");
print_r($final_array);
Output:- https://eval.in/847245

Searching array from multidimensional by value

I have an array, what Is like this:
$itemx=
[
'Weapons'=>[
'Sword'=> [
'ID' => '1',
'Name' => 'Lurker',
'Value' => '12',
'Made' => 'Acient'
],
'Shield'=> [
'ID' => '2',
'Name' => 'Obi',
'Value' => '22',
'Made' => 'Acient'
],
'Warhammer'=> [
'ID' => '3',
'Name' => 'Clotch',
'Value' => '124',
'Made' => 'Acient'
]
],
'Drinks'=>[
'Water'=> [
'ID' => '4',
'Name' => 'Clean-water',
'Value' => '1',
'Made' => 'Acient'
],
'Wine'=> [
'ID' => '5',
'Name' => 'Soff',
'Value' => '5',
'Made' => 'Acient'
],
'Vodka'=> [
'ID' => '6',
'Name' => 'Laudur',
'Value' => '7',
'Made' => 'Acient'
]
]
];
I want to find an array from it by Name or ID, so my output should be like this.
*Search by ID=4*
'Water'=> [
'ID' => '4',
'Name' => 'Clean-water',
'Value' => '1',
'Made' => 'Acient'
]
I look at other topics and found that I should use array_search
But It didn't work. I tried like this:
$arra=$itemx["Drinks"];
$key = array_search(4, array_column($arra, 'ID'));
var_dump($arra[$key]);
It also dident work when I tried with Name as a search key.
How can I get this working?
You can do it like below:-
$search_id = 4;
$final_array = [];
foreach($itemx as $key=>$val){
foreach($val as $k=>$v){
if($v['ID'] == $search_id){
$final_array[$k] = $itemx[$key][$k];
}
}
}
print_r($final_array);
https://eval.in/852123
This should probably get you what you want.
function rec($itemx,$search=4){
foreach ($itemx as $key => $value) {
if (is_array($value)) {
foreach ($value as $k => $v) {
if ($v['ID'] == $search) {
return $value;
}
}
}
}
}
print_r(rec($itemx,4));

Categories