I am trying to loop through an array of block components, that each can have n number of nested components (profile or avatar).
Now, what I want to do is to show these blocks x number of times, where x is the number of data from a payload array:
$payload['users'] = [
['name' => 'Oliver'],
['name' => 'John']
];
So since the above payload users length is 2, this should be rendered:
- block #1
-- profile
-- avatar
- block #2
-- profile
-- avatar
I am trying to render the above the same way by using a nested foreach loop. See the below code:
$payload['users'] = [
['name' => 'Oliver'],
['name' => 'John']
];
$schema = [
"id" => 1,
"name" => "Users",
"components" => [
[
"key" => "0",
"name" => "block",
"components" => [
[
"key" => "1",
"name" => "profile"
],
[
"key" => "2",
"name" => "avatar"
]
],
]
],
];
$toPush = [];
foreach ($schema['components'] as $key => $value) {
foreach ($value['components'] as $no => $component) {
$iterator = $payload['users'];
for ($x = 0; $x < count($iterator); $x ++) {
$copy = $component;
$copy['item'] = $iterator[$x];
$copy['key'] = $copy['key'] . '-' . $x;
$toPush[] = $copy;
}
$schema['components'][$key]['components'] = $toPush;
}
}
print_r($toPush);
The problem is that the above prints it out like this:
- block #1
-- profile
-- profile
- block #2
-- avatar
-- avatar
I have created an 3v4l of this, which can be found here.
How can I achieve my desired scenario?
For reference I am using the Laravel framework.
Desired output
Also available as an 3v4l here.
[
"components" => [
[
"key" => "1",
"name" => "profile",
"item" => [
"name" => "Oliver"
]
],
[
"key" => "2",
"name" => "avatar",
"item" => [
"name" => "Oliver"
]
],
[
"key" => "3",
"name" => "profile",
"item" => [
"name" => "John"
]
],
[
"key" => "4",
"name" => "avatar",
"item" => [
"name" => "John"
]
]
],
];
This logic may be of some help to you.
$toPush = [];
$count = 0;
foreach ($schema['components'] as $value) {
foreach ($value['components'] as $key => $component) {
foreach ($payload['users'] as $idx => $user) {
$toPush['components'][$count]['key'] = $count;
$toPush['components'][$count]['name'] = $value['components'][$idx]['name'];
$toPush['components'][$count]['item'] = $payload['users'][$key];
$count++;
}
}
}
demo
Related
I have nth level of nested array with string naming key , I want to convert that in indexing key only for array of item key.
i tried it to convert but that conversation only possible for limited level of nested array rather than nth level .
Input array:
$input_array= [
"NOCPL-All -working" => [
"name" => "NOCPL-All -working",
"item" => [
"apis for web" => [
"name" => "apis for web",
"item" => [
"0" => [
"name" => "update user branch maps"
]
]
],
"update user web" => [
"name" => "update user web",
"item" => [
"0" => [
"name" => "update user"
],
"1" => [
"name" => "add user"
]
]
]
]
]
];
I tried below code to convert indexing of 'item' nested array for limited level
function cleanArrayKeys($arr) {
foreach($arr as $k=>$arr1) {
if(isset($arr[$k]['item'])) {
$arr[$k]['item'] = array_values($arr[$k]['item']);
foreach($arr[$k]['item'] as $k1=>$arr2) {
if(isset($arr[$k]['item'][$k1]['item'])) {
$arr[$k]['item'][$k1]['item'] = array_values($arr[$k]['item'][$k1]['item']);
foreach($arr[$k]['item'][$k1]['item'] as $k3=>$arr3) {
if(isset($arr[$k]['item'][$k1]['item'][$k3]['item'])) {
$arr[$k]['item'][$k1]['item'][$k3]['item'] = array_values($arr[$k]['item'][$k1]['item'][$k3]['item']);
foreach($arr[$k]['item'][$k1]['item'][$k3]['item'] as $k4=>$arr4) {
if(isset($arr[$k]['item'][$k1]['item'][$k3]['item'][$k4]['item'])) {
$arr[$k]['item'][$k1]['item'][$k3]['item'][$k4]['item'] = array_values($arr[$k]['item'][$k1]['item'][$k3]['item'][$k4]['item']);
foreach($arr[$k]['item'][$k1]['item'][$k3]['item'][$k4]['item'] as $k5=>$arr5) {
if(isset($arr[$k]['item'][$k1]['item'][$k3]['item'][$k4]['item'][$k5]['item'])) {
$arr[$k]['item'][$k1]['item'][$k3]['item'][$k4]['item'][$k5]['item'] = array_values($arr[$k]['item'][$k1]['item'][$k3]['item'][$k4]['item'][$k5]['item']);
}
}
}
}
}
}
}
}
}
}
return $arr;
}
print_r(cleanArrayKeys($input_array));
?>
Expected Output :
[
"NOCPL-All -working" => [
"name" => "NOCPL-All -working",
"item" => [
"0" => [
"name" => "apis for web",
"item" => [
"0" => [
"name" => "update user branch maps"
],
"1" => [
"name" => "add user branch maps"
]
]
],
"1" => [
"name" => "update user web",
"item" => [
"0" => [
"name" => "update user"
]
]
]
]
]
];
Try using a recursion:
function aValues(&$arr) {
if (array_key_exists('item', $arr)) {
$arr['item'] = array_values($arr['item']);
}
foreach ($arr['item'] as &$el) {
if (array_key_exists('item', $el)) {
aValues($el);
}
}
}
aValues($input_array);
print_r($input_array);
This question already has answers here:
Filter/Remove rows where column value is found more than once in a multidimensional array
(4 answers)
Closed 10 months ago.
I have the following Associative Array below, and I wish to remove from the $filtered_results or $results the duplicated values based on the nid (number_id) field.
The solution I came up with, was to do a foreach loop, populate the new array with the key unique value that I wish and then return the array_values of that new array.
Is there a more elegant solution to tackle this problem ?
The order is irrelevant ( Replacing or keeping the current value);
Solution 1: Replacing the current value for the next.
$filtered_results = [];
foreach ($results as $k => $v) {
$filtered_results[ $v['nid'] ] = $v ;
}
return array_values ( $filtered_results ) ;
Solution 2: Keeping the first value found.
$filtered_results = [];
foreach ($results as $k => $v) {
if ( isset( $filtered_results[ $v['nid'] ] )) {
continue;
}
$filtered_results[ $v['nid'] ] = $v ;
}
Associative Array
$results = [
[
"date" => "2019-03-09",
"name" => "NameOne",
"phone" => "56784678",
"nid" => 1,
],
[
"date" => "2019-03-09",
"name" => "NameTwo",
"phone" => "123123123",
"nid" => 2,
],
[
"date" => "2019-03-09",
"name" => "NameThree",
"phone" => "6784568",
"nid" => 3,
],
[
"date" => "2019-03-09",
"name" => "NameFour",
"phone" => "90909090",
"nid" => 2,
],
[
"date" => "2019-03-09",
"name" => "NameFive",
"phone" => "3456356",
"nid" => 1,
],
];
Filtered Results
$filtered_results = [
[
"date" => "2019-03-09",
"name" => "NameThree",
"phone" => "6784568",
"nid" => 3,
],
[
"date" => "2019-03-09",
"name" => "NameFour",
"phone" => "90909090",
"nid" => 2,
],
[
"date" => "2019-03-09",
"name" => "NameFive",
"phone" => "3456356",
"nid" => 1,
],
]
Since is a duplicated question, the best solution I have found is :
array_values(array_column($results,NULL,'nid'))
Demo : https://onlinephp.io/c/fe78a
return array_intersect_key($results, array_unique(array_column($results, 'nid')));
use this :
$filtered_results = array_combine(array_column($results, 'nid'), $results);
I have an array with fields
[
"house" => "30|30|30",
"street" => "first|second|third",
...
]
I want to get array
[
[
"house" => "30",
"street" => "first",
...
],
[
"house" => "30",
"street" => "second",
...
],
[
"house" => "30",
"street" => "third",
...
]
]
I know how I can solve this using PHP and loop, but maybe this problem has more beautiful solution
use zip
$data = [
"house" => "30|30|30",
"street" => "first|second|third",
];
$house = collect(explode('|',$data['house']));
$street = collect(explode('|',$data['street']));
$out = $house->zip($street);
$out->toarray();
Here's something I managed to do with tinker.
$original = [
"house" => "30|30|30",
"street" => "first|second|third",
];
$new = []; // technically not needed. data_set will instantiate the variable if it doesn't exist.
foreach ($original as $field => $values) {
foreach (explode('|', $values) as $index => $value) {
data_set($new, "$index.$field", $value);
}
}
/* dump($new)
[
[
"house" => "30",
"street" => "first",
],
[
"house" => "30",
"street" => "second",
],
[
"house" => "30",
"street" => "third",
],
]
*/
I tried using collections, but the main problem is the original array's length is not equal to the resulting array's length, so map operations don't really work. I suppose you can still use each though.
$new = []; // Since $new is used inside a Closure, it must be declared.
collect([
"house" => "30|30|30",
"street" => "first|second|third",
...
])
->map(fn($i) => collect(explode('|', $i))
->each(function ($values, $field) use (&$new) {
$values->each(function ($value, $index) use ($field, &$new) {
data_set($new, "$index.$field", $value);
});
});
$array = ["house" => "30|30|30","street" => "first |second| third"];
foreach($array as $key=> $values){
$explodeval = explode('|',$values);
for($i=0; $i<count($explodeval); $i++){
$newarray[$i][$key]= $explodeval[$i];
}
}
output:
Array
(
[0] => Array
(
[house] => 30
[street] => first
)
[1] => Array
(
[house] => 30
[street] => second
)
[2] => Array
(
[house] => 30
[street] => third
)
)
i have 1 array like below :
0 => array:4 [
"id" => "1"
"date" => "2021-08-03"
"from_time" => "09"
"to_time" => "14"
]
1 => array:4 [
"id" => "2"
"date" => "2021-08-03"
"from_time" => "09"
"to_time" => "14"
]
now what i want to do ?? as you can see the date and from_time and to_time have the same value . i want to merge them to 1 item like below :
0 => array:4[
"date" => "2021-08-03"
"from_time" => "09"
"to_time" => "14"
"id" => ["1" , "2"]
].
so i can have the same day ids in 1 index of array and if for example the same date and time got 4 ids i get the id key with 4ids . i used array_merge_recursive but it didnt help me with the same keys of an array
this is how i am building the array :
foreach ($arrays as $key => $array) {
$options[$key]['id'] = last(str_split($array['id']));
$options[$key]['date'] = substr($array['id'],0,-2);
$options[$key]['from_time'] = Carbon::createFromTimestamp($array['pickup']['from'])->format('H');
$options[$key]['to_time'] = Carbon::createFromTimestamp($array['pickup']['to'])->format('H');
}
. thanks in advance for help
<?php
//define items
$items = [
[
"id" => "1",
"date" => "2021-08-03",
"from_time" => "09",
"to_time" => "14",
],[
"id" => "2",
"date" => "2021-08-03",
"from_time" => "09",
"to_time" => "14",
]
];
$options = [];
//loop through the items
foreach ($items as $item) {
//set up the hashing key to use to locate if we hit dup entry
$key = "{$item['date']}-{$item['from_time']}-{$item['to_time']}";
//if indexing key not in options = never looked at it before
if (!array_key_exists($key, $options)) {
//have the key points to the current entry
$options[$key] = $item; //attach the whole item to it
//we want the id to be an array to initialize it to be one
$options[$key]['id'] = [];
}
//gets here then we know options[$key] exists
//if the item id not in the id array of our dict
if (!in_array($item['id'], $options[$key]['id'])) {
//add to it
$options[$key]['id'][] = $item['id'];
}
}
//array_values to get the values and not worry about the keys
print_r(array_values($options));
You can do something like this:
$arr = [
[
"id" => "1",
"date" => "2021-08-03",
"from_time" => "09",
"to_time" => "14"
],
[
"id" => "2",
"date" => "2021-08-03",
"from_time" => "09",
"to_time" => "14"
],
[
"id" => "3",
"date" => "2021-08-03",
"from_time" => "14",
"to_time" => "16"
]
];
$res = array_reduce($arr, function($carry, $entry) use(&$arr) {
$matches = array_filter($arr, function($item) use($entry) {
return $item['from_time'] === $entry['from_time'] && $item['to_time'] && $entry['to_time'];
});
//print_r([ $entry['id'], $matches ]);
foreach($matches as $match) {
unset($arr[array_search($match['id'], array_column($matches, 'id'))]);
}
if (!count($matches)) {
return $carry;
}
$carry[] = [
'id' => array_column($matches, 'id'),
'date' => $entry['date'],
'from_time' => $entry['from_time'],
'to_time' => $entry['to_time'],
];
return $carry;
}, []);
Here is the thing I trying deal with
I have array which looks like this and have duplicates
$products = [
[
"product_name" => "Adidas1",
"address" => "street 2"
],
[
"product_name" => "Adidas2",
"address" => "street 2"
],
[
"product_name" => "Adidas3",
"address" => "street 2"
],
[
"product_name" => "Adidas4",
"address" => "street 2"
],
[
"product_name" => "Nike1",
"address" => "street name1"
],
[
"product_name" => "Nike2",
"address" => "street name1"
]];
Result that I need to get is below .
I did try different ways to do it but still can bring it to the finel result that have to come up
$final_result = [
[
"address" => "street 2",
"products" => [
"addidas1",
"addidas2",
"addidas3",
"addidas4",
]
],
[
"address" => "street name1",
"products" => [
"Nike1",
"Nike2",
]
]
any suggestion how to do it ?
here is my best solution that I tried
$stor_sorted = array();
foreach ($products as $product) {
if (array_count_values($product) > 1) {
$stor_sorted[] = ["address" => $product['address'], "items" => [$product['product_name']]];
}
}
try this code
$products = [
[
"product_name" => "Adidas1",
"address" => "street 2"
],
[
"product_name" => "Adidas2",
"address" => "street 2"
],
[
"product_name" => "Adidas3",
"address" => "street 2"
],
[
"product_name" => "Adidas4",
"address" => "street 2"
],
[
"product_name" => "Nike1",
"address" => "street name1"
],
[
"product_name" => "Nike2",
"address" => "street name1"
]];
$final_result = [];
foreach ($products as $pr){
$original_key = array_search($pr['address'], array_column($final_result, 'address'), true);
if($original_key === false){
$temp_array['address'] = $pr['address'];
$temp_array['products'] = [$pr['product_name']];
$final_result[] =$temp_array;
}else{
$final_result[$original_key]['products'][] = $pr['product_name'];
}
}
your result will be in final_result array
Use address values as temporary keys in your result array.
When an address is encountered for the first time, cast the product name as an array within the row and store the row.
On subsequent encounters, merely push the product name into the group's subarray.
When finished, re-index the result with array_values().
Code: (Demo)
$result = [];
foreach ($products as $row) {
if (!isset($result[$row['address']])) {
$row['product_name'] = (array)$row['product_name'];
$result[$row['address']] = $row;
} else {
$result[$row['address']]['product_name'][] = $row['product_name'];
}
}
var_export(array_values($result));
Same output with a body-less foreach() using array destructuring: (Demo)
$result = [];
foreach (
$products
as
[
'address' => $key,
'address' => $result[$key]['address'],
'product_name' => $result[$key]['product_name'][]
]
);
var_export(array_values($result));
Same output with functional style programming and no new globally-scoped variables: (Demo)
var_export(
array_values(
array_reduce(
$products,
function($result, $row) {
$result[$row['address']]['product_name'] = $row['product_name'];
$result[$row['address']]['address'][] = $row['address'];
return $result;
}
)
)
);