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.
Related
I have an array that need to be validated on the server.
The array look like this:
array:2 [
0 => array:5 [
"sku" => "8x0c"
"price" => "30.00"
"stock" => 5
"option_1" => 2
"option_2" => 5
]
1 => array:5 [
"sku" => "qsaz"
"price" => "30.00"
"stock" => 5
"option_1" => 2
"option_2" => 5
]
]
This array contains only 2 entries (it can contain multiple entries).
option_1, option_2 and option_3 are dynamic fields and need to be unique.
The array can have minimum one dynamic field (option_1) and maximum 3 fields (option_1, option_2 and option_3)
In this case in the first array
"option_1" => 2
"option_2" => 5
and in the second
"option_1" => 2
"option_2" => 5
are the same (i have two variations for a product that have the same color and size - and I don't want this).
How can I validate / check for duplicates for the selected options ?
If the two options keys in the items array are always going to be present, then the below function would allow you to validate the options being unique:
function validateUniqueOptions(array $items): bool
{
// Keep track the options we've seen before
$optionsSeen = [];
foreach ($items as $item) {
// Generate a unique key for this item combining its selection options
$optionKey = $item['option_1'] . '_' . $item['option_2'];
if (in_array($optionKey, $optionsSeen)) {
// This item is a duplicate of another we've seen previously, validation failed
return false;
}
$optionsSeen[] = $optionKey;
}
// No duplicates found, validation successful
return true;
}
This function below could handle as many option you'd like and if there are three options and two options in the other it is unique as well.
function check_options_duplicate($arr) {
$options_arr = ["","",""]; //Place for three options..
foreach($arr as $topkey=>$toplevel) {
foreach($toplevel as $key=>$item) {
if (substr($key,0,7) == 'option_') {
$options_arr[$topkey] .= $item . ",";
}
}
}
//If number of items in array are not the same when removing
//duplicate values with array_unique => it is a duplicate
if (count($options_arr) !== count(array_unique($options_arr))) {
return true;
}
return false;
}
Usage:
$is_duplicate = check_options_duplicate($arr);
if ($is_duplicate) {
echo 'is duplicate';
}
else {
echo 'is not duplicate';
}
Example: If having the array $arr:
Array
(
[0] => Array
(
[sku] => 8x0c
[price] => 30.00
[stock] => 5
[option_1] => 4
[option_2] => 3
)
[1] => Array
(
[sku] => qsaz
[price] => 30.00
[stock] => 5
[option_1] => 4
[option_2] => 33
)
)
it would result in the $options_arr array
Array
(
[0] => 4,3,
[1] => 4,33,
[2] =>
)
If doing an array_unique() it would be the same:
Array
(
[0] => 4,3,
[1] => 4,33,
[2] =>
)
If it both options would be the same:
Array
(
[0] => 4,3,
[1] => 4,3,
[2] =>
)
and you're doing an unique_array() it would only contain two items instead of 3.
Therefore it's a duplicate when you compare original $options_arr with unique $options_arr.
Array
(
[0] => 4,3,
[2] =>
)
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];
}
}
I'm trying to merge/sums 2 arrays that can contain integers or more arrays (themselves containing integer).
When the values are integers, I need to sum them in the final array.
When the values are arrays, I need to loop through the values and sum them in the final array.
If a value or a sub-array exists only in 1 of the base array, it needs to be added in the sub-array of the final array. (This is what I can't do)..)
My arrays are like this:
ARRAY 1
[1466859600] => Array
(
[TOTAL] => 27217
[AAA] => Array
(
[FD_CDP] => 1746
[LO_SC_MIC] => 4654
[FD_ATS] => 893
[CDP] => 40
[SUPERVISION] => 9
[CONTROL] => 4
[ATS] => 4
[EVT_ACK] => 3
)
[BBB] => Array
(
[FD_CDP] => 1376
[LO_SC_MIC] => 4606
[FD_ATS] => 826
[FD_ATSS] => 451
[LO_SFRC] => 4
[FD_S2] => 259
[2_LOSC] => 2
)
[CCC] => Array
(
[FD_CDP] => 1333
[LO_SC_MIC] => 4725
[FD_ATS] => 856
[CONTROL] => 4
[ATS] => 2
[EVT_ACK] => 5
)
ARRAY 2
[1466859600] => Array
(
[TOTAL] => 95406
[AAA] => Array
(
[FD_ATSS] => 1719
[LO_SC_MIC] => 16830
[CONTROL] => 16
[NEW] => 7
[NOEL] => 206
)
[BBB] => Array
(
[SUPERVISION] => 23
[CDP] => 158
[CONTROL] => 40
[2_LOSC] => 14
[ATS] => 6
[EVT_ACK] => 4
)
[CCC] => Array
(
[EVT_ACK] => 167
[LO_SFRC] => 248
[SUPERVISION] => 23
)
I wrote a function like this :
function sumArrayValues($array1, $array2)
{
foreach ($array1 as $key => $value)
{
if (is_array($array1[$key]))
{
echo "it's an array\n I need to reloop\n";
sumArrayValues($array1[$key], $array2[$key]);
}
else
{
echo "FIRST VALUE TO SUM\n";
print_r($array1[$key]."\n");
echo "SECOND VALUE TO SUM\n";
print_r($array2[$key]."\n");
$array1[$key] = (int)$array1[$key] +(int)$array2[$key];
echo "--------RESULT of SUM array1&2----------\n";
}
}
return $array1;
}
But this function doesn't take into account 2 (and probably more) cases: if the sub-array are not in the same order, if a sub-array or a value only exist in second array.
A example of function would be a good help, but on a more fundamental level, I even can't figure the algorithm to do that.
Any ideas ?
You can get all the keys for the foreach loop, live demo.
Note, you also can check if a key of any array is undefined, then save the defined value for the key.
function sumArrayValues($array1, $array2)
{
$keys = array_keys($array1 + $array2);
foreach ($keys as $key)
{
if (is_array($array1[$key]) || is_array($array2[$key]))
$array1[$key] = sumArrayValues($array1[$key], $array2[$key]);
else
#$array1[$key] = (int)$array1[$key] +(int)$array2[$key];
}
return $array1;
}
I want to delete price index from each of the array.
Here is a sample code:
Array([0] => Array
(
[player_id] => 108
[trnmnt_team_id] => 1
[player_type] => 1
[user_team_id] => 11
[user_id] => 4
[price] => 10.00
)
[1] => Array
(
[player_id] => 151
[trnmnt_team_id] => 2
[player_type] => 1
[user_team_id] => 11
[user_id] => 4
[price] => 10.00
)
)
I tried to delete following way but it shown unexpected 'unset' (T_UNSET):
foreach ($mergeAllType as $key => $value) {
$price=$value;
$withOutPrice[]=unset($price['price']);
}
unset doesn't returns any value (it's language construct, not a function), you must do it following way:
unset($price['price']);
$withOutPrice[] = $price;
Tomas.lang's answer works fine if you know the last index's key. However if you don't know the name of the last key you could use the following:
unset(end($price));
$withOutPrice = $price;
You already got your answers regarding your foreach loop.
So, let me give you a different answer, using array_map and an anonymous function ;-)
<?php
$src = array(
array (
'player_id' => 108,
'trnmnt_team_id' => 1,
'player_type' => 1,
'user_team_id' => 11,
'user_id' => 4,
'price' => 10.00,
),
array (
'player_id' => 151,
'trnmnt_team_id' => 2,
'player_type' => 1,
'user_team_id' => 11,
'user_id' => 4,
'price' => 10.00,
),
);
$withOutPrice = array_map(
function($e) {
unset($e['price']);
return $e;
},
$src
);
var_export($withOutPrice);
If you want to unset() all off the price keys in your array you can use array_walk()
array_walk($arr, function(&$array) {
unset($array['price']);
});
Just replace $arr with whatever your arrays name is, i.e. $teams.
If you want to have two arrays, one with price and one without price you could duplicate the array before doing the above; i.e.
$teams = <DATASOURCE>
$teamsWithoutPrice = $teams;
array_walk($teamsWithoutPrice, function(&$array) {
unset($array['price']);
});
Then if you print out your $teamsWithoutPrice array you'll have your array with the price key removed.
Hope it helps.
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];
});
}