Edit: I just figured out that my situation was a bit more complex. I edited the question consequently.
I have an array in this format:
[
[
"key" => "key1",
"field1" => "a1",
"field2" => "b1"
],
[
"key" => "key2",
"field1" => "a2",
"field2" => "b2"
]
]
I want to define a function to convert it into this:
[
"key1" => [
"field1" => "a1",
"field2" => "b1"
],
"key2" => [
"field1" => "a2",
"field2" => "b2"
]
]
And another function to reverse the process.
I managed to write the first function
function ($array, $key) {
return array_reduce($array, function ($carry, $item) use ($key) {
$new = array_diff_key($item, [$key=>0]);
$carry[$item[$key]] = $new;
return $carry;
}, []);
}
but now i'm having trouble with the reverse.
PS: I'm trying to avoid for loops
Any idea?
PHP >= 5.5 has a built-in function called array_column() to do this for you:
$array = array_column($array, 'value', 'key');
Related
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;
}, []);
This is $multidimensional data result :
[
{
"2018-11-02": [
"2"
]
},
{
"2018-11-02": [
"8",
"3"
]
}
{
"2018-11-21": [
"11",
"35",
"94",
"98",
"163"
]
},
]
$filter = [3,98,11]
How to remove object and value in $multidimensional where value not exist in $filter and after unset, the result will be turned into an object like the one below :
{
"3": 2018-11-02,
"98": 2018-11-21,
"11" : 2018-11-21
}
In my case, I am using unserialize :
for($w=0;$w<count($multidimensional);$w++) {
$hasilId2[] = (object) [
$multidimensional[$w]->date=> unserialize($multidimensional[$w]->invoiceid)
];
}
I've already try using loop :
foreach($multidimensional as $key => $value) {
if(!in_array($key, $filter)) {
unset($multidimensional[$key]);
}
}
You need a loop for the main array and a loop for the internal arrays
So it is better to put 2 loop inside each other
There is also no need to uset
You can put the correct results in a separate variable and then use it
You wanted the key to that array to be the final array value
So I used the key function to get the array key and gave the new value like this:
$result[array value] = [array key];
And finally I printed the new array:
$multidimensional = [
[
"2018-11-02" => [
"2"
]
],
[
"2018-11-02" => [
"8",
"3"
]
],
[
"2018-11-21" => [
"11",
"35",
"94",
"98",
"163"
]
],
];
$filter = [3, 98, 11];
$result = [];
foreach ($multidimensional as $val1) {
foreach (array_values($val1)[0] as $key => $val2) {
if (in_array($val2, $filter)) {
$result[$val2] = key($val1);
}
}
}
print_r($result);
Result:
Array
(
[3] => 2018-11-02
[11] => 2018-11-21
[98] => 2018-11-21
)
Reads all the prefix value in an array. If slug value is modules the result would be api/v1/tenants/modules/{id}, in contrast if slug value fetch the result would be api/v1/tenants/fetch/{id}.
"slug" => "api",
"children" => [
"prefix" => "v1",
"slug" => "v1",
"children" => [
"prefix" => "tenants",
"slug" => "tenants",
"children" => [
[
"prefix" => "fetch/{id}",
"slug" => "fetch",
],
[
"prefix" => "modules/{id}",
"slug" => "modules",
]
],
],
],
You can use array_walk_recursive to traverse array recursively,
$res = [];
// & so that it keeps data of $res in every loop
array_walk_recursive($arr, function ($item, $key) use (&$res) {
if ($key == 'prefix') {
$res[] = $item; // fetching only prefix values recursively
}
});
// this is your generated url
echo implode("/", $res);
Demo.
Output:
api/v1/tenants/modules/{id}
I use array-walk-recursive as:
function getPrefix($v, $k) { global $ps; if ($k == "prefix") $ps[] = $v; }
array_walk_recursive($arr, 'getPrefix');
Now, $ps is array of the prefix. Then you can use implode to add the /
Live example: 3v4l
I have the following array:
$arr = [
"elem-1" => [ "title" => "1", "desc" = > "" ],
"elem-2" => [ "title" => "2", "desc" = > "" ],
"elem-3" => [ "title" => "3", "desc" = > "" ],
"elem-4" => [ "title" => "4", "desc" = > "" ],
]
First I need to change the value from [ "title" => "1", "desc" = > "" ] to 1 (title's value).
I did this using array_walk:
array_walk($arr, function(&$value, $key) {
$value = $value["title"];
});
This will replace my value correctly. Our current array now is:
$arr = [
"elem-1" => "1",
"elem-2" => "2",
"elem-3" => "3",
"elem-4" => "4",
]
Now, I need to transform each element of this array into its own subarray. I have no idea on how to do this without a for loop. This is the desired result:
$arr = [
[ "elem-1" => "1" ],
[ "elem-2" => "2" ],
[ "elem-3" => "3" ],
[ "elem-4" => "4" ],
]
You can change your array_walk callback to produce that array.
array_walk($arr, function(&$value, $key) {
$value = [$key => $value["title"]];
});
Run the transformed array through array_values if you need to get rid of the string keys.
$arr = array_values($arr);
To offer an alternative solution you could achieve all of this with array_map
<?php
$arr = [
"elem-1" => [ "title" => "1", "desc" => "" ],
"elem-2" => [ "title" => "2", "desc" => "" ],
"elem-3" => [ "title" => "3", "desc" => "" ],
"elem-4" => [ "title" => "4", "desc" => "" ],
];
function convertToArray($key,$elem){
return [$key => $elem['title']];
}
$arr = array_map("convertToArray", array_keys($arr), $arr);
echo '<pre>';
print_r($arr);
echo '</pre>';
?>
outputs
Array
(
[0] => Array
(
[elem-1] => 1
)
[1] => Array
(
[elem-2] => 2
)
[2] => Array
(
[elem-3] => 3
)
[3] => Array
(
[elem-4] => 4
)
)
It doesn't make much sense to use array_walk() and modify by reference because the final result needs to have completely new keys on both levels. In other words, the output structure is completely different from the input and there are no salvageable/mutable parts. Mopping up the modified array with array_values() only adds to the time complexity cost.
array_map() has to bear a cost to time complexity too because array_keys() must be passed in as an additional parameter.
If you want to use array_walk(), use use() to modify the result array. This will allow you to enjoy the lowest possible time complexity.
More concise than array_walk() and cleaner to read, I would probably use a classic foreach() in my own project.
Codes: (Demo)
$result = [];
array_walk(
$arr,
function($row, $key) use(&$result) {
$result[] = [$key => $row['title']];
}
);
Or:
$result = [];
foreach ($arr as $key => $row) {
$result[] = [$key => $row['title']];
}
var_export($result);
You need to use array_map like
$new_arr= array_map(function($key,$val){
return [$key => $val['title']];},array_keys($arr),$arr);