PHP: How to separate dot notation keys into array with key prefix - php

Hello I want to convert this type of array
[
"Continent.0.name" => "Europe",
"Continent.0.value" => 25,
"Continent.1.name" => "Asia",
"Continent.1.value" => 4.17,
"Total" => 190
]
into
[
'continent' => [
'Europe' => 25
'Asia' => 4.17
],
'Total => 190
]
'name' after dot should be assigned as key and 'value' after dot shoudl be assigned as value.
Any idea?

Try this
EDIT:
<?php
$arr = [
"Continent.0.name" => "Europe",
"Continent.0.value" => 25,
"Continent.1.name" => "Asia",
"Continent.1.value" => 4.17,
"Total" => 190
];
$return = array();
$continentIndex = array();
foreach ($arr as $key => $currCell)
{
$name = explode('.', $key);
if(isset($name[2]) && $name[2] === 'name')
{
$return[$name[0]][$currCell] = array();
$continentIndex[$name[1]] = $currCell;
}
else if(isset($name[2]) && $name[2] === 'value')
$return[$name[0]][$continentIndex[$name[1]]] = $currCell;
if(!isset($name[1]))
$return[$key] = $currCell;
}
var_dump($return);
?>
return
array (size=2)
'Continent' =>
array (size=2)
'Europe' => int 25
'Asia' => float 4.17
'Total' => int 190

Related

Merge arrays in multidimensional array based on multiple values

[
0 => [
'qty' => 10
'section' => 'VK7B'
'time_window' => 1
]
1 => [
'qty' => 1
'section' => 'STIC'
'time_window' => 1
]
2 => [
'qty' => 1
'section' => 'STIC'
'time_window' => 1
]
]
I have this multidimensional array where I want to merge the array's if both the section and the time_window are the same, summing the qty for that array. What is an elegant way to do this?
I have tried this ($sections being the multidimensional arry), but this changes the keys and only checks for one value:
$new = []
foreach ($sections as $s) {
if (isset($new[$s['section']])) {
$new[$s['section']]['qty'] += $s['qty'];
$new[$s['section']]['time_window'] = $s['time_window'];
} else {
$new[$s['section']] = $s;
}
}
[
'VK7B' => [
'qty' => 10
'section' => 'VK7B'
'time_window' => 1
]
'STIC' => [
'qty' => 2
'section' => 'STIC'
'time_window' => 1
]
]
As pointed by #RiggsFolly in the comment you are not checking time_window are the same.
You can do it with this code:
$new = []
foreach ($sections as $s) {
// you need to save both values (section and time_window) to check both of them
if (isset($new[$s['section'].$s['time_window']])) {
$new[$s['section'].$s['time_window']]['qty'] += $s['qty'];
$new[$s['section'].$s['time_window']]['time_window'] = $s['time_window'];
} else {
$new[$s['section'].$s['time_window']] = $s;
}
}
// Now $new is an associative array => let's transform it in a normal array
$new = array_values($new);

How to sort array by subarray values with unknow index

I've got this PHP array:
<?php
$cities = [
'amsterdam' => $amsterdam,
'prague' => $prague,
'lisboa' => $lisboa
];
$amsterdam = [
65 => [
'table' => Object
'something' => false,
'data' => [
'foo' => 'boo',
'price' => 100
]
],
173 => [
'table' => Object
'something' => false,
'data' => [
'foo' => 'hoo',
'price' => 2500
]
],
...
];
$prague = [
132 => [
'table' => Object
'something' => false,
'data' => [
'foo' => 'boo',
'price' => 2100
]
],
956 => [
'table' => Object
'something' => false,
'data' => [
'foo' => 'hoo',
'price' => 2500
]
],
...
];
$lisboa = [
175 => [
'table' => Object
'something' => false,
'data' => [
'foo' => 'boo',
'price' => 6500
]
],
64 => [
'table' => Object
'something' => false,
'data' => [
'foo' => 'hoo',
'price' => 20
]
],
...
];
?>
and I need to sort it by the subarray value ['data']['price'] so the output is like this:
<?php
$cheapest_cities [
'lisboa' => $lisboa, // because 64->data->price is 20
'amsterdam' => $amsterdam, // beacuse 65->data->price is 100
'prague' => $prague // bacause 132->data->price is 2100
];
?>
I tried several usort combinations, but the problem is, that i never know what the subarray index will be (65, 173, 132, 956, 175, 64) in my example.
Do you have any idea how to sort it?
The data comes from database:
<?php
$amsterdam = $this->getTable()->where(['package_id' => [1,2,3]])->order('package_id')->fetchPairs('id');
$lisboa = $this->getTable()->where(['package_id' => [4,5]])->order('package_id')->fetchPairs('id');
$prague = $this->getTable()->where(['package_id' => [6]])->order('package_id')->fetchPairs('id');
return [
'amsterdam' => $amsterdam,
'lisboa' => $lisboa,
'prague' => $prague,
];
?>
Thank you
I would start by making a new array, which has the smallest price of every city as value
For this I use an array_map function which reduces the $items to the price with array_reduce
$map_prices = function($n) {
$reduce_smallest_price = function($carry, $item) {
return $item['data']['price'] < $carry
? $item['data']['price']
: $carry;
};
return array_reduce($n, $reduce_smallest_price, INF);
};
$cities_price = array_map($map_prices, $cities);
asort($cities_price);
I use this prices array to sort the original array with uksort
uksort($cities, function($a, $b) {
global $cities_price;
return strnatcmp($cities_price[$a], $cities_price[$b]);
});
Here is a live example on 3v4l: https://3v4l.org/8B9VN
Don't use usort as it will remove your keys. Use uasort.
Just a quick idea:
Inside the callback function of uasort you could search the minimum of your item e.g. via array_reduce.
array_reduce($city, function($carry, $item) {
return $carry === 0 ? $item['data']['price'] : min($carry, $item['data']['price']);
}, 0);
This snippet gets the minimum of a city array. Then it should be easy to compare the values.
Full example:
function getMinimumPrice($cityArray) {
return array_reduce($cityArray, function($carry, $item) {
return $carry === 0 ? $item['data']['price'] : min($carry, $item['data']['price']);
}, 0);
}
uasort($cities, function($city1, $city2) {
$priceCity1 = getMinimumPrice($city1);
$priceCity2 = getMinimumPrice($city2);
return $priceCity1 <=> $priceCity2;
});

Group subarray data by one column and form comma-separated values from the secondary value in each group [duplicate]

This question already has answers here:
Group subarrays by one column, make comma-separated values from other column within groups
(2 answers)
Closed last month.
I have a two dimensional array which needs to be restructured. Rows must be grouped by date values, and within each group, the name values should be formed into a single comma-delimited string.
My input:
$missedFridgeLog = [
[
"date" => "01/01/18",
"name" => "Medicine"
],
[
"date" => "01/01/18",
"name" => "Drugs"
],
[
"date" => "02/01/18",
"name" => "Medicine"
],
[
"date" => "02/01/18",
"name" => "Drugs"
]
];
I have tried implementing a solution from Implode or join multidimentional array with comma, but it did not work as desired.
Desired output:
[
[
'date' => '01/01/18',
'name' => 'Medicine,Drugs',
],
[
'date' => '02/01/18',
'name' => 'Medicine,Drugs',
]
]
$missedFridgeLog = [
[
"date" => "01/01/18",
"name" => "Medicine"
],[
"date" => "01/01/18",
"name" => "Drugs"
]
[
"date" => "02/01/18",
"name" => "Medicine"
],
[
"date" => "02/01/18",
"name" => "Drugs"
]
];
$byDates = [];
foreach ($missedFridgeLog as $mfg) {
$byDates[$mfg['date']][] = $mfg['name'];
}
$res = [];
foreach ($byDates as $date => $name) {
$res[] = [
'name' => join(',',$name),
'date' => $date
];
}
var_dump($res);
You need to search key, value pair everytime you make a insert or update to result array. use this function() to search associate array. If match then update with additional name info else make a new insert to result array.
function filter_array($array){
///$array your previous array data
$result = array();
foreach($array["missedFridgeLog"] as $m){
$flag = true;
foreach($result as $k=>$r) {
if (is_in_array($r, "date", $m["date"]) == "yes") {
$result[$k]["name"] = $r["name"] . ',' . $m["name"];
$flag = false;
break;
}
}
if($flag==true){
$result[] = $m;
}
}
return array("missedFridgeLog"=>$result);
}
function is_in_array($array, $key, $key_value){
$within_array = 'no';
foreach( $array as $k=>$v ){
if( is_array($v) ){
$within_array = is_in_array($v, $key, $key_value);
if( $within_array == 'yes' ){
break;
}
} else {
if( $v == $key_value && $k == $key ){
$within_array = 'yes';
break;
}
}
}
return $within_array;
}
May be this is not the best way to do this, but it will help
$arr['missedFridgeLog'] = [
[
'date' => '01/01/18',
'name' => 'Medicine1'
],
[
'date' => '02/01/18',
'name' => 'New Medicine2'
],
[
'date' => '01/01/18',
'name' => 'Drugs1'
],
[
'date' => '02/01/18',
'name' => 'Medicine2'
],
[
'date' => '01/01/18',
'name' => 'New Drugs1'
],
[
'date' => '02/01/18',
'name' => 'Drugs2'
]
];
echo "<pre>";
$new_arr = array();
$date = array();
foreach ($arr['missedFridgeLog'] as $k => $a) {
if (in_array($a['date'], $date))
continue;
$new_arr[$k]['name'] = $a['name'];
$new_arr[$k]['date'] = "";
foreach ($arr[missedFridgeLog] as $key => $val) {
if ($key != $k) {
if ($a['date'] == $val['date']) {
$date[] = $new_arr[$k]['date'] = $a['date'];
$new_arr[$k]['name'] .= ", " . $val['name'];
}
}
}
if (empty($new_arr[$k]['date']))
unset($new_arr[$k]);
}
print_r($new_arr);
You can try below :-
Input array :-
$chkArray = [
'missedFridgeLog' => [
'0' => [
'date' => '01/01/18',
'name' => 'Medicine'
],
'1' => [
'date' => '01/01/18',
'name' => 'Drugs'
],
'2' => [
'date' => '02/01/18',
'name' => 'Medicine'
],
'3' => [
'date' => '02/01/18',
'name' => 'Drugs'
],
'4' => [
'date' => '02/01/18',
'name' => 'My Drugs'
]
]
];
$i = 0;
$finalarray = array();
foreach($chkArray['missedFridgeLog'] as $key=>$value) {
$checkExist = array_search($value['date'], array_column($finalarray, 'date'), true);
if($checkExist !== false) {
$finalarray[$checkExist]['name'] = $finalarray[$checkExist]['name'].','.$value['name'];
}
else {
$finalarray[$i]['date'] = $value['date'];
$finalarray[$i]['name'] = $value['name'];
$i++;
}
}
print_r($finalarray);
OutPut :-
Array
(
[0] => Array
(
[date] => 01/01/18
[name] => Medicine,Drugs
)
[1] => Array
(
[date] => 02/01/18
[name] => Medicine,Drugs,My Drugs
)
)
Do not use:
More than one loop,
Nested loops,
in_array(), or
array_search().
You only need one loop to apply temporary grouping keys. When a date/group is encountered after the first time, append its name value to the group's name value. When finished iterating, re-index the array.
Code: (Demo)
$result = [];
foreach ($missedFridgeLog as $row) {
if (!isset($result[$row['date']])) {
$result[$row['date']] = $row;
} else {
$result[$row['date']]['name'] .= ",{$row['name']}";
}
}
var_export(array_values($result));
Output:
array (
0 =>
array (
'date' => '01/01/18',
'name' => 'Medicine,Drugs',
),
1 =>
array (
'date' => '02/01/18',
'name' => 'Medicine,Drugs',
),
)

Sum values by two matching keys in multidimensional arrays in PHP

I have a multidimensional array that has a date, name, & markup.
$in = [
[
'saledate' => '2016-02-01',
'name' => 'John Doe',
'markup' => 561
],
[
'saledate' => '2016-02-01',
'name' => 'John Doe',
'markup' => 681
],
[
'saledate' => '2016-02-02',
'name' => 'John Doe',
'markup' => 379
],
[
'saledate' => '2016-02-01',
'name' => 'Jane Doe',
'markup' => 205
],
[
'saledate' => '2016-02-02',
'name' => 'Jane Doe',
'markup' => 900
],
[
'saledate' => '2016-02-02',
'name' => 'Jane Doe',
'markup' => 787
],
[
'saledate' => '2016-02-03',
'name' => 'Jane Doe',
'markup' => 211
]
]
I'm trying to sum the values for each person by date for the desired output:
0 =>
array (size=3)
'name' => string 'John Doe' (length=8)
'2016-02-01' => float 1242
'2016-02-02' => float 379
1 =>
array (size=3)
'name' => string 'Jane Doe' (length=8)
'2016-02-01' => float 205
'2016-02-02' => float 1687
'2016-02-03' => float 211
Here is what I have but I think I'm just confusing myself...
$out = array();
foreach ($in as $row)
{
$result[$row['saledate']]['saledate'] = $row['saledate'];
$result[$row['name']]['name'] = $row['name'];
$result[$row['date']]['markup'] += $row['markup'];
}
$out = array_values($out);
Store the name as the key in your output array, it'll make grouping the results easier:
$out = array();
foreach ($in as $row) {
/* set the key using the name, eg. $out['John Doe'] */
if (! isset($out[$row['name']])) {
$out[$row['name']] = array('name' => $row['name']);
}
/* if the saledate isn't already exist, set it */
if (! isset($out[$row['name']][$row['saledate']])) {
$out[$row['name']][$row['saledate']] = 0;
}
/* add the markup */
$out[$row['name']][$row['saledate']] += $row['markup'];
}
Which would give you:
Array
(
[John Doe] => Array
(
[name] => John Doe
[2016-02-01] => 1242
[2016-02-02] => 379
)
[Jane Doe] => Array
(
[name] => Jane Doe
[2016-02-01] => 205
[2016-02-02] => 1687
[2016-02-03] => 211
)
)
If you don't want the name key, just use $out = array_values($out).
Try this code:
$result = array();
array_walk(
$in,
function ($row) use (&$result) {
$key = array_search($row['name'], array_column($result, 'name'));
if ($key === False) {
$key = array_push($result, array('name' => $row['name'])) - 1;
}
$date = $row['saledate'];
if (!isset($result[$key][$date]))
$result[$key][$date] = $row['markup'];
else
$result[$key][$date] += $row['markup'];
}
,
$result
);
print_r($result);
3v4l.org demo
After init an empty array, we pass it by reference as second arguments to array_walk: inside the called function, we check if the name and date already exists: if it is, we add the current value, otherwise we create new element(s) with current value.
See more about array_walk()
See more about array_column() PHP > 5.5
See more about passing by reference
Assigning temporary first level keys to the result array can be avoided by pushing reference variables into the result array then manipulating only the references as needed.
Code: (Demo)
$result = [];
foreach ($in as ['saledate' => $s, 'name' => $n, 'markup' => $m]) {
if (!isset($ref[$n])) {
$ref[$n] = ['name' => $n, $s => $m];
$result[] = &$ref[$n];
} else {
$ref[$n][$s] = ($ref[$n][$s] ?? 0) + $m;
}
}
var_export($result);

How to add array if key value is same

Hi i having difficulty to trace an multi dimensional array.
[
0 => array:7 [
"date" => "2016-01-19"
"placement_id" => 1
"requests" => 18
"revenue" => 1
],
1 => array:7 [
"date" => "2016-01-19"
"placement_id" => 1
"requests" => 2
"revenue" => 0.2
]
];
if placement_id are same i want resulted array:
1 => array:7 [
"date" => "2016-01-19"
"placement_id" => 1
"requests" => 20
"revenue" => 1.2
]
The requirement is to produce an output array that has:
Items with the same 'placement_id' having the 'requests' and revenue summed.
The key of the entry in the output array will be be the 'placement_id'.
That means that the output array will be smaller that the input array.
I decided to use the array_reduce function. There is no special reason, foreach loops work fine. It isn't any more efficient. It is just different.
The important point about array_reduce is that the $carry (accumulator) can be an array...
Working example at Eval.in
The code:
$outArray = array();
$outArray = array_reduce($src,
function($carry, $item) { // accumulate values if possible
$carryKey = $item['placement_id']; // array key
if (isset($carry[$carryKey])) { // accumulate values
$carry[$carryKey]['requests'] += $item['requests'];
$carry[$carryKey]['revenue'] += $item['revenue'];
} else { // is new - add to the output...
$carry[$carryKey] = $item;
}
return $carry;
},
array() /* accumulator ($carry) is an internal variable */);
Output Array:
array (2) [
'1' => array (4) [
'date' => string (10) "2016-01-19"
'placement_id' => integer 1
'requests' => integer 20
'revenue' => float 1.2
]
'666' => array (4) [
'date' => string (10) "2016-04-01"
'placement_id' => integer 666
'requests' => integer 266
'revenue' => float 666.20000000000005
]
]
Test Data:
$src = array(
0 => array(
"date" => "2016-01-19",
"placement_id" => 1,
"requests" => 18,
"revenue" => 1,
),
1 => array(
"date" => "2016-04-01",
"placement_id" => 666,
"requests" => 266,
"revenue" => 666.2,
),
2 => array(
"date" => "2016-01-19",
"placement_id" => 1,
"requests" => 2,
"revenue" => 0.2,
),
);
Taking that $arr parameter is the array that you show, we could create a function like this to look for duplicates ids and aggregate them. The $output array will return the results.
public function checkArray($arr) {
$output = array();
$deleted = array();
foreach($arr as $key => $value){
if (!in_array($key, $deleted)) {
$entry = array();
$entry['date'] = $value['date'];
$entry['placement_id'] = $value['placement_id'];
$entry['requests'] = $value['requests'];
$entry['revenue'] = $value['revenue'];
foreach($arr as $key2 => $value2){
if($key != $key2 && $value['placement_id'] == $value2['placement_id']){
$entry['requests'] += $value2['requests'];
$entry['revenue'] += $value2['revenue'];
$deleted[] = $key2;
}
}
$output[] = $entry;
}
}
return $output;
}

Categories