Related
This question already has answers here:
How to access and manipulate multi-dimensional array by key names / path?
(10 answers)
Closed 1 year ago.
I'm trying to create a function that will assign new values to a specific indexes in a multidimensional array:
I Have the array that looks like this:
data[i]['checkin'];
data[i]['checkout'];
data[i]['content'][x]['price'];
data[i]['content'][x]['profit'];
data[i]['content'][x]['exchangerate'];
first parameter of my function will get the array, And second parameter will get the indexes that I want to redefine:
For example:
function defineNewValues(&$arr, $keys) {
//logic
}
Call the function:
defineNewValues($myArray, [
'data.*.content.*.price' => 0,
'data.*.content.*.profit => 0,
]);
Im beliving that recursion is the key for my problem ,
But not really know how to solve it.
Thank You.
could something like this be okay?
I only ask you to study this code not to implement it, for the simple reason that in the future you may have the same type of problem.
function setValue($key,$value,&$array){
$find_parts = explode(".", $key);
$find = $find_parts[0]??null;
if ($find!=null){
if ($find == "*"){
array_shift($find_parts);
foreach($array as &$sub_array){
setValue(implode(".",$find_parts),$value,$sub_array);
}
}else{
if (count($find_parts)>1){
if (array_key_exists($find,$array)){
array_shift($find_parts);
setValue(implode(".",$find_parts),$value,$array[$find]);
}
}else{
if (array_key_exists($find,$array)){
$array[$find] = $value;
}
}
}
}
}
function defineNewValues(&$arr, $keys) {
foreach($keys as $key=>$value){
setValue($key,$value,$arr);
}
}
$myArray=[
"data"=>[
"a"=>[
"content"=>[
"aa"=>[
"price" => 3,
"profit" => 2,
"other" => 1
],
"ab"=>[
"price" => 3,
"profit" => 2,
"other" => 2
]
]
],
"b"=>[
"content"=>[
"ba"=>[
"price" => 3,
"profit" => 2,
"other" => 4
],
"bb"=>[
"price" => 3,
"profit" => 2,
"other" => 5
]
]
],
]
];
defineNewValues($myArray, [
"data.*.content.*.price" => 0,
"data.*.content.*.profit" => 0,
]);
print_r($myArray);
/* OUTPUT
Array
(
[data] => Array
(
[a] => Array
(
[content] => Array
(
[aa] => Array
(
[price] => 0
[profit] => 0
[other] => 1
)
[ab] => Array
(
[price] => 0
[profit] => 0
[other] => 2
)
)
)
[b] => Array
(
[content] => Array
(
[ba] => Array
(
[price] => 0
[profit] => 0
[other] => 4
)
[bb] => Array
(
[price] => 0
[profit] => 0
[other] => 5
)
)
)
)
)
*/
Because the keys you want to replace only occur at one level of the data, the solution doesn't really need to take the entire array structure into account. You can just replace every price and profit key.
array_walk_recursive($example, function(&$value, $key) {
if (in_array($key, ['price', 'profit'])) {
$value = 0;
}
});
Based on your comment on the other answer, my opinion on the "correct and professional way" is that we should try to solve the problem in the simplest way possible, because simple solutions are easy to maintain.
I have a php array that looks like this...
(
[name] => Test
[age] => 50
[items] => Array
(
[23456] => Array
(
[id] => 12
)
[3345] => Array
(
[id] => 344
[status] => stock
)
[2236] => Array
(
[id] => 876
)
)
)
I am trying to search for any mention of status in the items section of the array.
I have tried using array_key_exists like this...
array_key_exists('test',$arr);
But this is giving me false, as an alternative I was thinking of flattening the array somehow and then searching to make it work with my array.
Is this the best choice?
You can use also use array_column() to see if the key exists :
$exist = !empty(array_column($arr['items'], 'status'));
But, #Barmar answer could be more efficient on large arrays.
Loop over the items array and check each item.
function status_exists_in_items($arr) {
foreach ($arr['items'] as $item) {
if (array_key_exists('status', $item)) {
return true;
}
}
return false;
}
Just filter the array and handle just those items, that have a status key.
$data = [
'name' => 'Test',
'age' => 50,
'items' => [
23456 => [
'id' => 12,
],
3345 => [
'id' => 344,
'status' => 'stock',
],
2236 => [
'id' => 876,
],
],
];
$result = array_filter($data['items'], function($item) {
if (isset($item['status'])) return $item;
});
var_dump($result);
Results into:
array(1) {
[3345] => array(2) {
["id"] => int(344)
["status"] => string(5) "stock"
}
}
This solution could be slow (as every function that handles native arrays) depending on how big your array is. You can work with filter iterators, which work as yields and do not consume as much memory as arrays do.
this is quite beyond me. Appreciate some help.
I have an array in php like so:
[0] => Array
(
[cust_id] => 1006
[no_of_subs] => 2
[dlv_id] => 1000
)
[1] => Array
(
[cust_id] => 1011
[no_of_subs] => 3
[dlv_id] => 1000
)
[2] => Array
(
[cust_id] => 1012
[no_of_subs] => 5
[dlv_id] => 1001
)
[3] => Array
(
[cust_id] => 1013
[no_of_subs] => 6
[dlv_id] => 1001
)
I don't need the cust_id field. I just need to group the dlv_id and the sum of no_of_subs for each matching dlv_id. The result should look like this:
[0] => Array
(
[dlv_id] => 1000
[no_of_subs] => 5
)
[1] => Array
(
[cust_id] => 1011
[no_of_subs] => 11
)
Thank you for any help.
I don't understand the downvotes for this question. Am i doing it all wrong? Downvoting without a reason is not helping.
The simplest, most efficient way to group and sum is to perform a single loop and assign temporary associative keys.
When a row is identified as a new dlv_id row, save the two desired elements, otherwise add the no_of_subs value to the pre-existing value.
Optionally, remove the temporary keys with array_values().
Code (Demo)
$array = [
["cust_id" => 1006, "no_of_subs" => 2, "dlv_id" => 1000],
["cust_id" => 1011, "no_of_subs" => 3, "dlv_id" => 1000],
["cust_id" => 1012, "no_of_subs" => 5, "dlv_id" => 1001],
["cust_id" => 1013, "no_of_subs" => 6, "dlv_id" => 1001]
];
foreach ($array as $row) {
if (!isset($result[$row["dlv_id"]])) {
$result[$row["dlv_id"]] = ["dlv_id" => $row["dlv_id"], "no_of_subs" => $row["no_of_subs"]];
} else {
$result[$row["dlv_id"]]["no_of_subs"] += $row["no_of_subs"];
}
}
var_export(array_values($result));
Output:
array (
0 =>
array (
'dlv_id' => 1000,
'no_of_subs' => 5,
),
1 =>
array (
'dlv_id' => 1001,
'no_of_subs' => 11,
),
)
Using array_column function, we can extract out dlv_id and no_of_subs separately in two different arrays, using cust_id as the key.
Now, simply loop over the array of dlv_id, and if matching key found, add the no_of_subs to it, else set the value (for the first time).
We use isset function to check if the key exists already or not.
Try the following:
// your input array is $input_array
// get all dlv_id maintaining the cust_id as index
$dlv_id = array_column($input_array, 'dlv_id', 'cust_id');
// get all no_of_subs maintaining the cust_id as index
$no_of_subs = array_column($input_array, 'no_of_subs', 'cust_id');
$output = array();
foreach ($dlv_id as $key => $value) {
if (isset($output[$value]['dlv_id'])) {
$output[$value]['dlv_id'] += $no_of_subs[$key];
} else {
$output[$value]['dlv_id'] += $no_of_subs[$key];
}
}
This is the array:
Array
(
[0] => Array
(
[product_details] => {"5f93f983524def3dca464469d2cf9f3e":{"id":"110","qty":1,"option":"{\"color\":{\"title\":\"Color\",\"value\":null}}","price":1400,"name":"Foot Massage","tax":null,"image":"http:\/\/acme.dev\/uploads\/product_image\/product_110_1_thumb.jpg","coupon":"9","book_date_":"2017-04-19","book_date_name_":"wed","start_timeslot_":"09:00:00","end_timeslot_":"10:00:00","has_already_rescheduled":0,"discount_":"0","rowid":"5f93f983524def3dca464469d2cf9f3e","subtotal":1400}}
)
[1] => Array
(
[product_details] => {"2723d092b63885e0d7c260cc007e8b9d":{"id":"109","qty":1,"option":"{\"color\":{\"title\":\"Color\",\"value\":null}}","price":700,"name":"Body Massage","tax":0,"image":"http:\/\/acme.dev\/uploads\/product_image\/product_109_1_thumb.jpg","coupon":"","book_date_":"2017-04-18","book_date_name_":"tue","start_timeslot_":"09:00:00","end_timeslot_":"10:00:00","has_already_rescheduled":0,"discount_":"0","rowid":"2723d092b63885e0d7c260cc007e8b9d","subtotal":700}}
)
[2] => Array
(
[product_details] => {"a3c65c2974270fd093ee8a9bf8ae7d0b":{"id":"108","qty":1,"option":"{\"color\":{\"title\":\"Color\",\"value\":null}}","price":3000,"name":"Alo","tax":0,"image":"http:\/\/acme.dev\/uploads\/product_image\/default.jpg","coupon":"","book_date_":"2017-04-21","book_date_name_":"fri","start_timeslot_":"10:00:00","end_timeslot_":"12:00:00","has_already_rescheduled":0,"discount_":"0","rowid":"a3c65c2974270fd093ee8a9bf8ae7d0b","subtotal":3000}}
)
[3] => Array
(
[product_details] => {"a3c65c2974270fd093ee8a9bf8ae7d0b":{"id":"108","qty":1,"option":"{\"color\":{\"title\":\"Color\",\"value\":null}}","price":3000,"name":"Alo","tax":0,"image":"http:\/\/acme.dev\/uploads\/product_image\/default.jpg","coupon":"","book_date_":"2017-04-12","book_date_name_":"wed","start_timeslot_":"08:00:00","end_timeslot_":"10:00:00","has_already_rescheduled":0,"discount_":"0","rowid":"a3c65c2974270fd093ee8a9bf8ae7d0b","subtotal":3000}}
)
)
What I need is to create a new simple array containing the values from all the "id" elements.
Hope this simple foreach will be helpful for you.
Solution 1: Try this code snippet here
$result=array();
foreach($array as $value)
{
$array= json_decode($value["product_details"],true);
$result[]=$array[key($array)]["id"];
}
print_r($result);
Here we are using array_column to extract product_details then we are using to array_map to iterate over $personalDetails which contain all the JSON's then we are using to key function which will return first key of the array, and through that key we are accessing, its id.
Solution 2: Try this code snippet here
<?php
ini_set('display_errors', 1);
$array = Array
(
0 => Array
(
"product_details" => '{"5f93f983524def3dca464469d2cf9f3e":{"id":"110","qty":1,"option":"{\"color\":{\"title\":\"Color\",\"value\":null}}","price":1400,"name":"Foot Massage","tax":null,"image":"http:\/\/acme.dev\/uploads\/product_image\/product_110_1_thumb.jpg","coupon":"9","book_date_":"2017-04-19","book_date_name_":"wed","start_timeslot_":"09:00:00","end_timeslot_":"10:00:00","has_already_rescheduled":0,"discount_":"0","rowid":"5f93f983524def3dca464469d2cf9f3e","subtotal":1400}}'
),
1 => Array
(
"product_details" => '{"2723d092b63885e0d7c260cc007e8b9d":{"id":"109","qty":1,"option":"{\"color\":{\"title\":\"Color\",\"value\":null}}","price":700,"name":"Body Massage","tax":0,"image":"http:\/\/acme.dev\/uploads\/product_image\/product_109_1_thumb.jpg","coupon":"","book_date_":"2017-04-18","book_date_name_":"tue","start_timeslot_":"09:00:00","end_timeslot_":"10:00:00","has_already_rescheduled":0,"discount_":"0","rowid":"2723d092b63885e0d7c260cc007e8b9d","subtotal":700}}'
),
2 => Array
(
"product_details" => '{"a3c65c2974270fd093ee8a9bf8ae7d0b":{"id":"108","qty":1,"option":"{\"color\":{\"title\":\"Color\",\"value\":null}}","price":3000,"name":"Alo","tax":0,"image":"http:\/\/acme.dev\/uploads\/product_image\/default.jpg","coupon":"","book_date_":"2017-04-21","book_date_name_":"fri","start_timeslot_":"10:00:00","end_timeslot_":"12:00:00","has_already_rescheduled":0,"discount_":"0","rowid":"a3c65c2974270fd093ee8a9bf8ae7d0b","subtotal":3000}}'
),
3 => Array
(
"product_details" => '{"a3c65c2974270fd093ee8a9bf8ae7d0b":{"id":"108","qty":1,"option":"{\"color\":{\"title\":\"Color\",\"value\":null}}","price":3000,"name":"Alo","tax":0,"image":"http:\/\/acme.dev\/uploads\/product_image\/default.jpg","coupon":"","book_date_":"2017-04-12","book_date_name_":"wed","start_timeslot_":"08:00:00","end_timeslot_":"10:00:00","has_already_rescheduled":0,"discount_":"0","rowid":"a3c65c2974270fd093ee8a9bf8ae7d0b","subtotal":3000}}'
)
);
$personalDetails= array_column($array, "product_details");
$result=array_map(function($value){
$array=json_decode($value,true);
return $array[key($array)]["id"];
}, $personalDetails);
print_r($result);
Output:
Array
(
[0] => 110
[1] => 109
[2] => 108
[3] => 108
)
use array_column and json_decode
$new_one = array_column($array,'product_details');
$new_array=[];
foreach($new_one as $key=>$row)
{
foreach(json_decode($row,true) as $key1=>$row1)
{
$new_array[]=$row1['id'];
}
}
print_r($new_array);
you may use array_map & array_value to achieve this,
here is a quick example, and you need to modify it to be fit with your needs :
$ar = [
0 => ['product_details' => '{"5f93f983524def3dca464469d2cf9f3e":{"id": 3}}'],
1 => ['product_details' => '{"2723d092b63885e0d7c260cc007e8b9d":{"id": 8}}'],
2 => ['product_details' => '{"a3c65c2974270fd093ee8a9bf8ae7d0b":{"id": 5}}'],
3 => ['product_details' => '{"a3c65c2974270fd093ee8a9bf8ae7d0b":{"id": 1}}'],
];
$ar = array_map(function ($value) {
return array_values(json_decode($value['product_details'], true))[0]['id'];
}, $ar);
print_r($ar);
live demo : https://3v4l.org/koXee
Try this code, live demo
print_r(array_column(array_map(function($v){return current(json_decode($v));},array_column($array, 'product_details')), 'id'));
You "product_details" seems to be a JSON string. Loop through your array, decode the JSON and store the "id" in a new array.
This question already has answers here:
Sort multi-dimensional array by specific key
(6 answers)
Closed 7 years ago.
I have a function sortBy() that I use to sort multidimensional arrays by a particular key. Here is a sample array:
Array
(
[0] => Array
(
[id] => 4
[type] => 1
[game] => 1
[platform] => 0
[TotalPot] => 7550
)
[1] => Array
(
[id] => 5
[type] => 0
[game] => 2
[platform] => 0
[TotalPot] => 7500
)
)
Here is the function
function sortBy($arr, $field='id', $order=1) {
$a = array();
if ( !is_array($arr) )
return false;
foreach($arr as $subArr) {
$a[$subArr[$field]] = $subArr;
}
if ( $order == 1 ) sort($a);
else rsort($a);
return $a;
}
In this case, calling sortBy($array, 'TotalPot'); would work fine, because the two values for TotalPot are different. However, if you run this example and set both TotalPot fields to $7500, it overwrites the first occurrence with the latter.
What would be the best way to make this function allow for two items with the same value but still keep them in relevant order? I thought about adding another character, an A or 1 to the end, but this seems sloppy and not very predictable, so a better course of action would be greatly appreciated.
You can simplify your code and just use usort(), e.g.
function sortArrayByField(array &$arr, $field = "id", $ASC = TRUE) {
usort($arr, function($a, $b)use($field, $ASC){
if($a[$field] == $b[$field])
return 0;
return $a[$field] > $b[$field] ? $ASC : !$ASC;
});
}
Then just call it like this:
sortArrayByField($array, "TotalPot", TRUE);
print_r($array);
The reason they are getting overwritten is because you're creating an array where the index is the value of the totalPot.
If there are duplicates, then you will only have one array element with the totalPot.
Easiest way is just to usort this:
<?php
$array = [
[
"id" => 4,
"type" => 1,
"game" => 1,
"platform" => 0,
"TotalPot" => 7550
], [
"id" => 5,
"type" => 0,
"game" => 2,
"platform" => 0,
"TotalPot" => 7500
]
];
usort($array, function($a, $b) {
return $a['TotalPot'] - $b['TotalPot'];
});
print_r($array);
Output:
Array
(
[0] => Array
(
[id] => 5
[type] => 0
[game] => 2
[platform] => 0
[TotalPot] => 7500
)
[1] => Array
(
[id] => 4
[type] => 1
[game] => 1
[platform] => 0
[TotalPot] => 7550
)
)
You can also make this a function:
function sortBy($arr, $field='id', $order=1) {
usort($arr, function($a, $b) use ($field, $order) {
if ($order == 1)
return $a[$field] - $b[$field];
else
return $b[$field] - $a[$field];
});
}