I have an array with common product code & product name.
For each product_code can have two types of cha_sty_id i.e push or pull.
This is an array structure I have.
$array = [
0 => [
"product_code" => "67021687",
"product_name" => "Spaces",
"cha_sty_id" => "PUSH",
"chs_name" => "WF"
],
1 => [
"product_code" => "67021687",
"product_name" => "Spaces",
"cha_sty_id" => "PUSH",
"chs_name" => "WFR"
],
2 => [
"product_code" => "67021687",
"product_name" => "Spaces",
"cha_sty_id" => "PUSH",
"chs_name" => "STK Food"
],
3 => [
"product_code" => "67021687",
"product_name" => "Spaces",
"cha_sty_id" => "PULL",
"chs_name" => "4 Stars"
],
4 => [
"product_code" => "67021687",
"product_name" => "Spaces",
"cha_sty_id" => "PULL",
"chs_name" => "5 Stars"
],
5 => [
"product_code" => "67021687",
"product_name" => "Spaces",
"cha_sty_id" => "PULL",
"chs_name" => "Modern Thai"
],
6 => [
"product_code" => "67021687",
"product_name" => "Spaces",
"cha_sty_id" => "PULL",
"chs_name" => "BBQ Buffet"
],
7 => [
"product_code" => "67021687",
"product_name" => "Spaces",
"cha_sty_id" => "PULL",
"chs_name" => "Chinese"
]
];
Now I want result something like:
0 => [
'product_code' => 67021687,
'product_name' => 'Spaces.
'push => array(....ALL chs_name for push),
'pull' => array with chs_name for pull
]
I have tried some code
$list = array();
foreach ($records as $data) {
$list[$data['product_code']][] = $data;
if($data['cha_sty_id'] == 'PUSH') {
$list[$data['product_code']]['push'] = $data['chs_name'];
} else {
$list[$data['product_code']]['pull'] = $data['chs_name'];
}
}
But I could not solve it.
Can anybody pls help me.
Thank You.
How about this modify your foreach loop to this:
$list = array();
foreach ($records as $data) {
$code = $data['product_code']; // as key
if (!isset($list[$code])) { // set new array if not exist
$list[$code] = array("product_code" => $code, "product_name" => $data['product_name'], "push" => [], "pull" => []);
}
$subKey = strtolower($data['cha_sty_id']); // get push / pull as new subkey
$list[$code][$subKey][] = $data['chs_name']; // append to the array
}
You can use array_values to remove the code keys from $list after the loop if not needed
You can use array_walk,array_push
$res = [];
array_walk($array, function($v, $k) use (&$res){
if(in_array($v['product_code'], array_column($res, 'product_code'))){
array_push($res[$v['product_code']]["push"], $v['chs_name']);
array_push($res[$v['product_code']]["pull"], $v['chs_name']);
}else{
$res[$v['product_code']] = [
"product_code" => $v['product_code'],
"product_name" => $v['product_name'],
"push" => [$v['chs_name']],
"pull" => [$v['chs_name']]
];
}
});
echo '<pre>';
print_r(array_values($res));
DEMO HERE
There is no need for any conditional expressions while partially pivoting your data into groups. Use the product_code values as temporary first level keys and use the cha_sty_id values as dynamic second level keys. Re-index the result array after the loop finishes with array_values().
One approach uses a body-less foreach as explained here.
Code: (Demo)
$result = [];
foreach (
$array
as
[
'product_code' => $productCode,
'cha_sty_id' => $id,
'product_code' => $result[$code]['product_code'],
'product_name' => $result[$code]['product_name'],
'chs_name' => $result[$code][strtolower($id)][]
]
);
var_export(array_values($result));
A more traditional style is to group and pivot inside the body of the loop.
Code: (Demo)
$result = [];
foreach ($array as $row) {
$result[$row['product_code']]['product_code'] = $row['product_code'];
$result[$row['product_code']]['product_name'] = $row['product_name'];
$result[$row['product_code']][strtolower($row['cha_sty_id'])][] = $row['chs_name'];
}
var_export(array_values($result));
Due to the fact that the group logic is possibly going to return an array size that differs from the input array, array_reduce() is the most appropriate functional iterator for this task.
Code: (Demo)
var_export(
array_values(
array_reduce(
$array,
function($result, $row) {
$result[$row['product_code']]['product_code'] = $row['product_code'];
$result[$row['product_code']]['product_name'] = $row['product_name'];
$result[$row['product_code']][strtolower($row['cha_sty_id'])][] = $row['chs_name'];
return $result;
},
[]
)
)
);
All techniques above produce the exact same result.
Related
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
)
)
[
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);
I have an array that looks like this
"name" => array:3 [
1 => "Hello"
4 => "Test"
21 => "Test2"
]
"runkm" => array:3 [
1 => "100.00"
4 => "1000.00"
21 => "2000.00"
]
"active" => array:3 [
1 => "1"
4 => "0"
21 => "0"
]
Can i somehow combine the matching keys with a PHP function so that the array would look like this instead
1 => array:3 [
name => "Hello"
runkm => "100.00"
active => "1"
]
4 => array:3 [
name => "Test"
runkm => "1000.00"
active => "0"
]
21 => array:3 [
name => "Test2"
runkm => "2000.00"
active => "0"
]
EDIT: Thanks for all the answers guys. What i was really looking for was a PHP built in function for this, which i probably should have been more clear about.
$newArr=array();
foreach($array1 as $key => $value){
$newArr[$key]=>array(
'name' =>$value[$key];
'runkm' =>$array2[$key];
'active'=>$array3[$key];
);
}
this is how you make a new array and then print the $newArr and check you get what you want or not? Good Luck!
<?php
$resultarr = array();
for($i=0;$i<count($sourcearr['name']);$i++) {
$resultarr[] = array('name'=>$sourcearr['name'][$i], 'runkm'=>$sourcearr['runkm'][$i], 'active'=>$sourcearr['active'][$i]);
}
This works well. And also, doesn't use hard coded keys.
<?php
$arr = [
"name" => [
1 => "Hello",
4 => "Test",
21 => "Test2"
],
"runkm" => [
1 => "100.00",
4 => "1000.00",
21 => "2000.00"
],
"active" => [
1 => "1",
4 => "0",
21 => "0"
]
];
// Pass the array to this function
function extractData($arr){
$newarr = array();
foreach ($arr as $key => $value) {
foreach($value as $k => $v) {
if(!isset($newarr[$k]))
$newarr[$k] = array();
$newarr[$k][$key] = $v;
}
}
return $newarr;
}
print_r(extractData($arr));
?>
I'm not sure if there's a function that does that in PHP but maybe you can try this
$arr1 = array(
"name" => array(
1 => "hello",
4 => "test",
21 => "test2",
),
"runKm" => array(
1 => "100",
4 => "200",
21 => "300",
),
"active" => array(
1 => "1",
4 => "0",
21 => "0",
),
);
// declare another that will hold the new structure of the array
$nArr = array();
foreach($arr1 as $key => $val) {
foreach($val as $sub_key => $sub_val) {
$nArr[$sub_key][$key] = $sub_val;
}
}
what this does is simply loop thru each array and its values and assign it to another array which is the $nArr. I hope it helps.
I have a flat associative array which may contain duplicate values.
Array (
[for-juniors] => product_category
[for-men] => product_category
[coats] => product_category
[for-women] => product_category
[7-diamonds] => brand
)
I need to restructure the data to store the original values as new keys and the original keys pushed into subarrays associated with the new keys.
array(
'product_category' => array(
'for-juniors',
'for-men',
'coats',
'for-women'
),
'brand' => array(
'7-diamonds'
)
);
$grouped = array();
foreach ($input as $choice => $group) {
$grouped[$group][] = $choice;
}
var_dump($grouped);
Because within a foreach() loop, the values are declared BEFORE the keys, you can actually populate the new data structure with a body-less foreach() loop.
Code: (Demo)
$array = [
'for-juniors' => 'product_category',
'for-men' => 'product_category',
'coats' => 'product_category',
'for-women' => 'product_category',
'7-diamonds' => 'brand'
];
$grouped = [];
foreach ($array as $grouped[$group][] => $group);
var_export($grouped);
Output:
array (
'product_category' =>
array (
0 => 'for-juniors',
1 => 'for-men',
2 => 'coats',
3 => 'for-women',
),
'brand' =>
array (
0 => '7-diamonds',
),
)
This'll do:
function array_flip_safe(array $array) : array
{
return array_reduce(array_keys($array), function ($carry, $key) use (&$array) {
$carry[$array[$key]] ??= []; // PHP 7.0 - ^7.3: $carry[$array[$key]] = $carry[$array[$key]] ?? [];
$carry[$array[$key]][] = $key;
return $carry;
}, []);
}
The callback creates an empty array if the array doesn't already exist. Then it appends current iteration's $key ($value of array_keys($array)) to that array.
Here's an example for better understanding:
$businessHours = [
'mo' => '13:00 - 16:00',
'tu' => '8:00 - 12:00',
'we' => '13:00 - 16:00',
'th' => '8:00 - 12:00',
'fr' => '13:00 - 16:00',
'sa' => '',
'su' => '',
];
$flipped = array_flip_safe($businessHours);
ray($flipped); (or var_dump, var_export, etc.) outputs:
array:3 [▼
"13:00 - 16:00" => array:3 [▼
0 => "mo"
1 => "we"
2 => "fr"
]
"8:00 - 12:00" => array:2 [▼
0 => "tu"
1 => "th"
]
"" => array:2 [▼
0 => "sa"
1 => "su"
]
]
Note that the order of inner arrays' values is the same as the order of original array's keys.