I hope you guys fine, From last 3-4 hours I try to combine year in the same array set and unset all other arrays which are duplicate (I unable to explain correctly, please check the array example below)., but so far no luck, I tried and I know this isn't the correct way, if anybody has a solution for this please share.
Can somebody tell me how to combine same year in an array and unset other arrays at the same time, I tried but failed, no luck.
Try to do that way, but faild misrably:
foreach ($class as $i=>$class_list){
echo $i;
foreach ($class_list as $key=>$value){
$e=0;
foreach ($class_list as $value2){
if ($value['name']==$value2['name']){
echo 'match';
$class['packages'][$key]['year'][$e]=$value['year'];
}
$e++;
}
}
}
Actual Array:
Array
(
[packages] => Array
(
[0] => Array
(
[name] => atif.ali
[year] => 2019
)
[1] => Array
(
[name] => atif.ali
[year] => 2018
)
[2] => Array
(
[name] => atif.ali
[year] => 2017
)
[3] => Array
(
[name] => khatija.abbas
[year] => 2017
)
)
)
Need output like this:
Array
(
[packages] => Array
(
[0] => Array
(
[name] => atif.ali
[year] => Array
(
[0] 2019
[1] 2018
[2] 2017
)
)
[1] => Array
(
[name] => khatija.abbas
[year] => 2017
)
)
)
P.S: array can be different but "year" and "name" structure always same.
It's probably easiest to just create a new array in the format you require. You can do that by looping over the values inside packages, checking for the existence of the name in the new array, and if it exists, adding the current year to that value. If it doesn't exist, just create a new entry for that name.
$new_array = array('packages' => array());
foreach ($array['packages'] as $value) {
if (($k = array_search($value['name'], array_column($new_array['packages'], 'name'))) !== false) {
$new_array['packages'][$k]['year'][] = $value['year'];
}
else {
$new_array['packages'][] = array('name' => $value['name'], 'year' => array($value['year']));
}
}
print_r($new_array);
Output:
Array
(
[packages] => Array
(
[0] => Array
(
[name] => atif.ali
[year] => Array
(
[0] 2019
[1] 2018
[2] 2017
)
)
[1] => Array
(
[name] => khatija.abbas
[year] => Array (
[0] => 2017
)
)
)
)
Demo on 3v4l.org
Update
If you really want the year field not to be an array when there is only one value, this code will do that for you; it only makes it into an array when a second or subsequent value is seen.
$new_array = array('packages' => array());
foreach ($array['packages'] as $value) {
if (($k = array_search($value['name'], array_column($new_array['packages'], 'name'))) !== false) {
if (is_array($new_array['packages'][$k]['year'])) {
$new_array['packages'][$k]['year'][] = $value['year'];
}
else {
$new_array['packages'][$k]['year'] = array($new_array['packages'][$k]['year'], $value['year']);
}
}
else {
$new_array['packages'][] = $value;
}
}
print_r($new_array);
Demo on 3v4l.org
Try this
$class = ['packages' => [['name' => 'atif.ali', 'year' => 2019], ['name' => 'atif.ali', 'year' => 2018], ['name' => 'atif.ali', 'year' => 2017], ['name' => 'khatija.abbas', 'year' => 2017]]];
$new_class = [];
foreach ($class['packages'] as $key => $class_list) {
if( ! isset($new_class[$class_list['name']])){
$new_class[$class_list['name']] = $class_list;
}else{
if(is_array($new_class[$class_list['name']]['year'])){
$new_class[$class_list['name']]['year'][] = $class_list['year'];
}else{
$prev_year = $new_class[$class_list['name']]['year'];
$new_class[$class_list['name']]['year'] = [$prev_year, $class_list['year']];
}
}
}
$class['packages'] = $new_class;
I see there are some other responses while I wrote my own. First of all here you have the piece of code:
<?php
// Input data
$input = array('packages' => array(
array('name' => 'atif.ali', 'year' => 2019),
array('name' => 'atif.ali', 'year' => 2018),
array('name' => 'atif.ali', 'year' => 2017),
array('name' => 'khatija.abbas', 'year' => 2017),
));
$output = array(); // Create new array to store the final result
foreach ($input['packages'] as $package) { // we are only interested in 'packages', let's iterate over them
$name = $package['name'];
$year = $package['year'];
if (!isset($output[$name])) { // First time we see this name?
$output[$name] = array('name' => $name, 'year' => []); // Let's create an "empty" structure.
}
if (!in_array($year, $output[$name]['year'])) { // First time we see this year for this name?
$output[$name]['year'][] = $year; // Let's add it
}
}
// Reformatting to fit your needs (nest everything under 'packages' and remove the names from resulting dictionary keys)
$output = array('packages' => array_values($output));
var_dump($output);
Let me note the key issues/concepts:
As others suggested: create a new structure for your output. Reusing the same array will probably cause you nightmares. What if you want to later use the original input? Check inmutability and stateless programming.
It is easier if you use a map/dictionary/associative-array for grouping instead of an array itself. It is easier (and faster) to check if a key exists in a map than if an element exists in an array.
All this is using basic php/programming stuff. It can also be achieved by using array_reduce. If you are curious take a look at it :)
Give the code and comments a look and if you have any doubt let me know.
Another option is to create a new result where the key packages already exists. Then use the name as the key so you can check if the key already exists.
If it does not, add a new entry. If it does already exists, index into the new $result converting what is already there to an array so that the first entry which is a string becomes an array.
$arrays = [
"packages" => [
["name" => "atif.ali", "year" => "2019"],
["name" => "atif.ali", "year" => "2018"],
["name" => "atif.ali", "year" => "2017"],
["name" => "khatija.abbas", "year" => "2019"]
]
];
$result = ["packages" => []];
foreach ($arrays["packages"] as $array) {
if(!array_key_exists($array['name'], $result["packages"])) {
$result["packages"][$array['name']] = $array;
continue;
}
$result["packages"][$array['name']]['year'] = (array)$result["packages"][$array['name']]['year'];
$result["packages"][$array['name']]['year'][] = $array['year'];
}
print_r($result);
See a php demo
If you want numerical indexes instead, you could use array_values like this example
I've written this sort of quickly -- I'll look at it again in the morning when I've hopefully had a chance to rest and rethink how to do this with one loop. This seems to work for me. NOTE I did not include the 'packages' key, but the code can be modified by adding it in front of that particular section.
Edit
Had a quick second to think about what I did, perhaps this is what you're looking for:
<?php
$raw = [
[
'name'=>'atif.ali',
'year'=>2018
],
[
'name'=>'atif.ali',
'year'=>2019
],
[
'name'=>'atif.ali',
'year'=>2017
],
[
'name'=>'kahitja.abal',
'year'=>2019
],
[
'name'=>'kahitja.abal',
'year'=>2018
],
[
'name'=>'john.smith',
'year'=>2017
],
[
'name'=>'john.smith',
'year'=>2018
],
];
$map_index = [];
$final = [];
for($i = 0; $i< count($raw); $i++) {
if(!isset($map_index[$raw[$i]['name']])){
$map_index[$raw[$i]['name']] = count($final);
$final[count($final)] = ['name'=>$raw[$i]['name'], 'years'=>[]];
}
$index = $map_index[$raw[$i]['name']];
$final[$index]['years'][]=$raw[$i]['year'];
}
echo '<pre>';
print_r($final);
?>
Here is an example, just build a new array and swap.
<?php
$data =
[
[
'name' => 'Bilbo Baggins',
'year' => 2010
],
[
'name' => 'Bilbo Baggins',
'year' => 2011
],
[
'name' => 'Frodo Baggins',
'year' => 1999
]
];
foreach($data as $item) {
$output[$item['name']]['name'] = $item['name'];
$output[$item['name']]['year'][] = $item['year'];
}
print_r($output);
Output:
Array
(
[Bilbo Baggins] => Array
(
[name] => Bilbo Baggins
[year] => Array
(
[0] => 2010
[1] => 2011
)
)
[Frodo Baggins] => Array
(
[name] => Frodo Baggins
[year] => Array
(
[0] => 1999
)
)
)
If you don't like the new keys, call array_values on the result.
Related
I have a multidimensional array and am trying to group them according to the value in a specific column.
I'm trying to group them by level, but I won't actually know the level beforehand. So, it's not like I can put it in a for loop and say while $i < 7, because I won't know that 7 is the maximum value for the level key, and frankly, I'm not sure that's how I would need to do it even if I did.
[
['cust' => 'XT8900', 'type' => 'standard', 'level' => 1],
['cust' => 'XT8944', 'type' => 'standard', 'level' => 1],
['cust' => 'XT8922', 'type' => 'premier', 'level' => 3],
['cust' => 'XT8816', 'type' => 'permier', 'level' => 3],
['cust' => 'XT7434', 'type' => 'standard', 'level' => 7],
]
Desired result:
Array (
[1] => Array (
[0] => Array (
[cust] => XT8900
[type] => standard
)
[1] => Array (
[cust] => XT8944
[type] => standard
)
)
[3] => Array (
[2] => Array (
[cust] => XT8922
[type] => premier
)
[3] => Array (
[cust] => XT8816
[type] => permier
)
)
[7] => Array (
[4] => Array (
[cust] => XT7434
[type] => standard
)
)
)
Best way, if you have control over building the initial array, is just set things up like that at the start as you add entries.
If not then build a temporary array to sort:
foreach ($input_arr as $key => &$entry) {
$level_arr[$entry['level']][$key] = $entry;
}
Leaves you with the form you wanted and everything referenced together.
Build the array like that in the first place though if at all possible.
You need to group them by level first
Use foreach to loop into array check if the level is the same with the previous item then group it with that array
$templevel=0;
$newkey=0;
$grouparr[$templevel]="";
foreach ($items as $key => $val) {
if ($templevel==$val['level']){
$grouparr[$templevel][$newkey]=$val;
} else {
$grouparr[$val['level']][$newkey]=$val;
}
$newkey++;
}
print($grouparr);
The output of print($grouparr); will display like the format you hoped for
You can also try to
print($grouparr[7]);
Will display
[7] => Array (
[4] => Array (
[cust] => XT7434
[type] => standard
)
)
Or
print($grouparr[3]);
Will display
[3] => Array (
[2] => Array (
[cust] => XT8922
[type] => premier
)
[3] => Array (
[cust] => XT8816
[type] => permier
)
)
Here is the solution I landed on for an identical problem, wrapped as a function:
function arraySort($input,$sortkey){
foreach ($input as $key=>$val) $output[$val[$sortkey]][]=$val;
return $output;
}
To sort $myarray by the key named "level" just do this:
$myArray = arraySort($myArray,'level');
Or if you didn't want it as a function, just for a one time use, this would create $myNewArray from $myArray grouped by the key 'level'
foreach ($myArray as $key=>$val) $myNewArray[$val['level']][]=$val;
function group_assoc($array, $key) {
$return = array();
foreach($array as $v) {
$return[$v[$key]][] = $v;
}
return $return;
}
//Group the requests by their account_id
$account_requests = group_assoc($requests, 'account_id');
$result = array();
foreach ($yourArrayList as $data) {
$id = $data['level'];
if (isset($result[$id])) {
$result[$id][] = $data;
} else {
$result[$id] = array($data);
}
}
Best ans.
$levels = array_unique(array_column($records, 'level'));
$data = array();
foreach($records as $key => $value){
$data[$levels[array_search($value['level'],$levels )]][] = $value ;
}
print_r($data);
To generate the question's exact desured output from the sample input, pull/pop the last value from each row, use that value as the first level grouping key. Then use the original first level index as the second level key. Then push the two remaining elements into the group's subset.
Code: (Demo)
$result = [];
foreach ($array as $key => $row) {
$result[array_pop($row)][$key] = $row;
}
var_export($result);
For functional style syntax, use array_reduce(). (Demo)
var_export(
array_reduce(
array_keys($array),
function($result, $key) use ($array) {
$result[array_pop($array[$key])][$key] = $array[$key];
return $result;
}
)
);
function _group_by($array,$key,$keyName)
{
$return = array();
foreach($array as $val) {
$return[$keyName.$val[$key]][] = $val;
}
return $return;
} //end of function
I have an array in PHP code below, and I want to convert this array to be grouped by data value. It's always hard to simplify arrays.
Original array:
Array
(
[0] => Array
(
[date] => 2017-08-22
[AAA] => 1231
)
[1] => Array
(
[date] => 2017-08-21
[AAA] => 1172
)
[2] => Array
(
[date] => 2017-08-20
[AAA] => 1125
)
[3] => Array
(
[date] => 2017-08-21
[BBB] => 251
)
[4] => Array
(
[date] => 2017-08-20
[BBB] => 21773
)
[5] => Array
(
[date] => 2017-08-22
[CCC] => 3750
)
[6] => Array
(
[date] => 2017-08-20
[CCC] => 321750
)
)
Below is my desired array:
Array
(
[2017-08-22] => Array
(
[AAA] => 1231
[CCC] => 3750
)
[2017-08-21] => Array
(
[AAA] => 1172
[BBB] => 251
)
[2017-08-20] => Array
(
[AAA] => 1125
[BBB] => 21773
[CCC] => 321750
)
)
It is also ok to have empty null value if the data doesn't exist. [BBB] => NULL for 2017-08-22.
Can anybody help? Thanks in advance...
A simple loop should do this..
$group = [];
foreach ($data as $item) {
if (!isset($group[$item['date']])) {
$group[$item['date']] = [];
}
foreach ($item as $key => $value) {
if ($key == 'date') continue;
$group[$item['date']][$key] = $value;
}
}
Here : this should do the work.
$dst_array = array();
foreach ($array as $outerval) {
foreach ($outerval as $key => $innerval) {
if ($key != 'date') {
$dst_array[$outerval['date']][$key] = $innerval;
}
}
}
It iterates through the array and then through the entries in each subarray. Any any that is not a date is assigned in the destination array in the subarray corresponding to its date and with its own current key.
I definitely wouldn't recommend any techniques that involve more than one loop -- this process can certainly be performed in a single loop.
If you like language construct iteration, use a foreach() loop: (Demo)
$result = [];
foreach ($array as $row) {
$date = $row['date'];
unset($row['date']);
$result[$date] = array_merge($result[$date] ?? [], $row);
}
var_export($result);
If you like to use functional programming and fewer global variables, use array_reduce(): (Demo)
var_export(
array_reduce(
$array,
function($accumulator, $row) {
$date = $row['date'];
unset($row['date']);
$accumulator[$date] = array_merge($accumulator[$date] ?? [], $row);
return $accumulator;
},
[]
)
);
These techniques unconditionally push data into the subarray with the key based on the date column value.
The above technique will work consistently even if the order of your subarray elements changes.
The ?? (null coalescing operator) is to ensure that array_merge() always has an array in the first parameter -- if processing the first occurrence of a given date, you simply merge the current iteration's data (what's left of it after unset() removes the date element) with an empty array.
I believe this solution will work for you:
<?php
$array = Array
(
0 => Array
(
'date' => '2017-08-22',
'AAA' => '1231',
),
1 => Array
(
'date' => '2017-08-21',
'AAA' => '1172',
),
2 => Array
(
'date' => '2017-08-20',
'AAA' => '1125'
),
3 => Array
(
'date' => '2017-08-21',
'BBB' => '251'
),
4 => Array
(
'date' => '2017-08-20',
'BBB' => '21773',
),
5 => Array
(
'date' => '2017-08-22',
'CCC' => '3750'
),
6 => Array
(
'date' => '2017-08-20',
'CCC' => '321750'
)
);
echo '<pre>';
$array1 = array('AAA' => null, 'BBB' => null, 'CCC' => null);
$array2 = array();
array_walk($array, function ($v) use (&$array2, $array1) {
$a = $v['date'];
if (!isset($array2[$a])) {
$array2[$a] = $array1;
}
unset($v['date']);
$array2[$a] = array_merge($array2[$a], $v);
});
print_r($array2);
Output
Array
(
[2017-08-22] => Array
(
[AAA] => 1231
[BBB] =>
[CCC] => 3750
)
[2017-08-21] => Array
(
[AAA] => 1172
[BBB] => 251
[CCC] =>
)
[2017-08-20] => Array
(
[AAA] => 1125
[BBB] => 21773
[CCC] => 321750
)
)
check output at: https://3v4l.org/NvLB8
Another approach (quick & dirty) making use of an arrays internal pointer:
$newArray = [];
foreach ($array as $childArray) {
$date = current($childArray);
$value = next($childArray); // this advances the internal pointer..
$key = key($childArray); // ..so that you get the correct key here
$newArray[$date][$key] = $value;
}
This of course only works with the given array structure.
Another perfect usage example for the PHP function array_reduce():
// The input array
$input = array(
0 => array(
'date' => '2017-08-22',
'AAA' => '1231',
),
// The rest of your array here...
);
$output = array_reduce(
$input,
function (array $carry, array $item) {
// Extract the date into a local variable for readability and speed
// It is used several times below
$date = $item['date'];
// Initialize the group for this date if it doesn't exist
if (! array_key_exists($date, $carry)) {
$carry[$date] = array();
}
// Remove the date from the item...
// ...and merge the rest into the group of this date
unset($item['date']);
$carry[$date] = array_merge($carry[$date], $item);
// Return the partial result
return $carry;
},
array()
);
The question is not clear. What is the expected result if one key (AAA f.e) is present on two or more dates? This answer keeps only the last value associated with it.
I have an array $report:
Array
(
[03.05.2016] => Array
(
[tasks] => Array
(
[group1] => to change
)
[start] => 8:00
[end] => 16:00
)
)
and a second array $keys:
Array
(
[0] => 03.05.2016
[1] => tasks
[2] => group1
)
and a variable $value with a value CHANGED
I'm looking for a way to change the value of
$report[03.05.2016][tasks][group1]
so that my final array will be:
(
[03.05.2016] => Array
(
[tasks] => Array
(
[group1] => CHANGED
)
[start] => 8:00
[end] => 16:00
)
)
Can someone help me?
You can work down through your $report variable, assigning by reference to each "step" in your $keys array, and then change the final level to your new value.
Edit:
The advantage of this approach is that it will work for any number of levels, although if you will always only have three steps then the answer from #zakhefron is clearer.
<?php
$report = [
'03.05.2016' => [
'tasks' => [
'group1' => 'to change'
],
'start' => 8:00
'end' => 16:00
]
];
$keys = ['03.05.2016', 'tasks', 'group1'];
$value = 'CHANGED';
// Start at the top level of $report
$target =& $report;
// Then work down through the keys
while ($key = array_shift($keys))
{
$target =& $target[$key];
}
// Finally, set the final target to the new value
$target = $value;
print_r($report);
=
Array
(
[03.05.2016] => Array
(
[tasks] => Array
(
[group1] => CHANGED
)
[start] => 8:00
[end] => 16:00
)
)
Try $report[$keys[0]][$keys[1]][$keys[2]] = $value;
Refer : https://3v4l.org/0HBUH
You can use recursive function approach here, pass the source, keys and the value to function. It will check if the keys exists in array, if found then call the same function with remaining data, keys and value.
At last keys left empty as all of them searched, now you can simply update the value, and return true, otherwise return false if not found.
$report = array(
'03.05.2016' => array(
'tasks' => Array(
'group1' => 'to change'
),
'start' => '8:00',
'end' => '16:00'
));
$keys = array(
'03.05.2016',
'tasks',
'group1'
);
$value = 'CHANGED';
function updateValue(&$source, $keys, $value) {
$keysCount = count($keys);
if(empty($keys)) {
$source = $value;
return true;
}
foreach($keys as $key) {
if(isset($source[$key])) {
array_shift($keys);
return updateValue($source[$key], $keys, $value);
}
else return false;
}
}
updateValue($report, $keys, $value);
print_r($report);
See it working: https://eval.in/589461
I need your help with my problem. My problem is I have 2 arrays the first one is the main array. The second is the array for my new data.
Let's say I have these arrays.
This is the main array:
Array
(
0 => Array
(
'id' => 1,
'name' => 'Apple',
'age' => 12
)
1 => Array
(
'id' => 2,
'name' => May,
'age' => 13
)
)
This is the second array:
Array
(
1 => Array
(
'gender' => 'Male'
)
2 => Array
(
'gender' => 'Female'
)
)
And I have this loop in PHP
foreach($main_array as &$main){
//this is the loop inside the first array
// how can I add the second array with it?
}
This is the sample output:
[0] => Array
(
[id] => 1
[name] => Apple
[age] => 12
[gender] => Female
)
[1] => Array
(
[id] => 2
[name] => May
[age] => 13
[gender] => Female
)
How can I do that? Any suggestions? That's all thanks.
for($i=0; $i<count($main_array); $i++){
for($j=0; $j<count($second_array); $j++){
if($main_array[$i]['id'] == $j){
$main_array[$i]['gender'] = $second_array[$j]['gender']
}
}
}
I fixed your example code, it wont run otherwise.
<?php
// Test data:
$main_array = Array(
0 => Array(
'id' => 1,
'name' => 'Apple',
'age' => 12
),
1 => Array (
'id' => 2,
'name' => 'May',
'age' => 13
)
);
$lookup = Array(
1 => Array(
'gender' => 'Male'
),
2 => Array(
'gender' => 'Female'
)
);
// Your answer:
foreach ($main_array as &$main) {
if (array_key_exists($main['id'],$lookup)) {
$main['gender'] = $lookup[$main['id']]['gender']; // <-- sets gender value
}
}
// Output it to browser:
echo '<pre>$main_array = '.print_r($main_array,true).'</pre>';
The array_key_exists() check is there to avoid errors such as PHP Notice: Undefined offset: 123 when the $lookup data is incomplete.
If you want to merge all of the data from both arrays:
PHP tools:
The exact behaviors of these functions needs to be studied and tested before usage, to make sure it fits your intent.
// array merge recursive doesn't merge numeric keys
$main_array = array_merge_recursive($main_array, $secondary_array);
// array replace recursive has a downside of replacing stuff
$main_array = array_replace_recursive($main_array, $secondary_array);
Rolling your own:
foreach($main_array as $i => &$main){
if(isset($secondary_array[$i])) {
foreach($secondary_array[$i] AS $key => $value) {
$main[$key] = $value;
}
}
}
Both of the above solutions only apply if the array-indexes of $main_array and $secondary_array match.
In your example your arrays don't match:
- $secondary_array[0] doesn't exist so $main_array[0] will not be populated with a 'gender' value;
- $main_array[2] doesn't exist so $main_array[2] will be created and it will only have a 'gender' value same as $secondary_array[2]['gender']
If you want to only merge some bits and pieces of the arrays:
Rolling your own:
foreach($main_array as $i => &$main) {
if(isset($secondary_array[$i])) and isset($secondary_array[$i]['gender'])) {
$main['gender'] = $secondary_array[$i]['gender'];
}
}
foreach($main_array as &$main){//this is the loop inside the first array
foreach($second_array as &$second){ //this is the loop inside the second array
}
}
foreach($arr1 as $k => $arr1Item) {
$arr1[$k]['gender'] = $arr2[$k]['gender'];
}
I have tried to get the below code to work for a good couple of hours, but just don't succeed.
I have this date array:
Array ( [0] => Array ( [0] => 2007 )
[1] => Array ( [0] => 2008 )
[2] => Array ( [0] => 2009 )
...
)
and this plusMinus one:
Array ( [0] => Array ( [plus] => 2 [date] => 2007 )
[1] => Array ( [minus] => 1 [date] => 2008 )
[2] => Array ( [minus] => 1 [date] => )
[3] => Array ( [plus] => 1 [date] => 2010 [minus] => 1 )
)
I have been trying to combine them into this:
Array ( [0] => Array ( [date] => 2007 [plus]=> 2)
[1] => Array ( [date] => 2008 [minus]=> 1)
[2] => Array ( [date] => 2009 [plusMinus]=> 0)
[3] => Array ( [date] => 2010 [plus] => 1 [minus]=>1 )
...
)
So basically I want to check if a value of the date array exists in the plusMinus array. If true the date and values from the plusMinus array shall replace the entry in the date array.
If false, the original date array entry is complemented by a [plusMinus] => 0 key-value pair.
The way I have tried to do it is this:
foreach ($filler as $key1 => $value1)
{
foreach ($plusMinus as $key2 => $value2)
{
if ($value1['0'] !== $value2['date'])
{
$value1['plusMinus'] = '0';
$result2[$key1][] = $value1;
}
elseif ($value1['0'] == $value2['date'])
{
if (array_key_exists('plus',$value2))
{
$value1['plus'] = $value2['plus'];
$result2[$key1][]=$value1;
}
elseif(array_key_exists('minus',$value2))
{
$value1['minus'] = $value2['minus'];
$result2[$key1][]=$value1;
}
elseif(array_key_exists('minus',$value2) &&
array_key_exists('plus',$value2))
{
}
}
}
}
$valuesComplete = array();
foreach ($result2 as $value) {
$result2 = $value['0'];
array_push($valuesIncomplete, $result2);
}
return $valuesComplete;
Instead of the desired outcome described above I get this:
Array ( [0] => Array
( [0] => 2007 [plus] => 2 )
[1] => Array ( [0] => 2008 [plusMinus => 0 )
[2] => Array ( [0] => 2009 [plusMinus] => 0 )
[3] => Array ( [0] => 2010 [plusMinus] => 0 )
[4] => Array ( [0] => 2011 [plusMinus] => 0 )
[5] => Array ( [0] => 2012 [plusMinus] => 0 )
[6] => Array ( [0] => 2013 [plusMinus] => 0 )
)
What am I missing? Thanks for any help!
Unfortunately, because of the input data format, I can't see any way to do this that doesn't involve an O(n + m + p) operation. But no matter, you gotta do what you gotta do.
Firstly I would start by filtering the useless elements from the PlusMinus array. Since it's already fairly close to the desired output format, it makes sense to use this as the base of the result.
$temp = array();
foreach ($plusMinus as $item) {
if (!empty($item['date'])) {
$temp[$item['date']] = $item;
}
}
Notice that I used the date as the index of the temporary array we're using to build the result. This is to allow you to easily ensure that the result array is in the correct order, and to quickly check whether an item needs to be added from the Filler array.
Next, we need to add any missing elements from the Filler array:
foreach ($filler as $item) {
if (!isset($temp[$item[0]])) {
$temp[$item[0]] = array(
'date' => $item[0],
'plusMinus' => 0
);
}
}
Now all the data is in the array in the correct format, we just need to sort it:
ksort($temp);
...and get convert it back to an indexed array:
return array_values($temp);
No need for the performance killing nested loops or complex flow control.
See it working
As I understood you need to add years that not in second array but in first?
In that case you can do:
foreach ($filler as $key1 => $value1)
{
$ok = false;
foreach ($plusMinus as $key2 => $value2)
{
if($value2['date']==$value1[0])
{
$ok = true;
break;
}
}
if(!$ok)
{
$plusMinus[$value1[0]]=array('date'=>$value1[0], 'plusMinus'=>0);
}
}
<?php
$a1 = array(array( 2007 ),
array( 2008 )
);
$a2 = array(array('plus'=>1, 'date'=>2007),
array('minus'=>1,'date'=>2008),
array('plus'=>1, 'minus'=>1, 'date'=>2008)
);
$r = array();
foreach($a1 as $k1=>$d1) {
$year = $d1[0];
foreach( $a2 as $k2=>$d2 ) {
if( $d2['date'] == $year ) {
$r[$year]['date'] = $year;
if(isset($d2['plus'])) {
$r[$year]['plus'] = $d2['plus'];
}
if(isset($d2['minus'])) {
$r[$year]['minus'] = $d2['minus'];
}
}
}
}
print_r($r);
and result
Array
(
[2007] => Array
(
[date] => 2007
[plus] => 1
)
[2008] => Array
(
[date] => 2008
[minus] => 1
[plus] => 1
)
)
$ar1 = array( array(2007), array(2008), array(2009), array(2010) );
$ar2 = array(
array("date"=>2007, "plus"=>2),
array("date"=>2008, "minus"=>1),
array("date"=>"", "minus"=>1),
array("date"=>2010, "plus"=>1, "minus"=>1)
);
foreach($ar2 as $key=>$val){
if(isset($ar1[$key][0]))
$val["date"] = $ar1[$key][0];
$ar2[$key] = $val;
}
I am not sure if I understand you correctly but this works fine...
It will work only if you are sure that your both arrays "date" equals one to other..
This is what I came up with:
To not create the product of both arrays (foreach inside foreach), I first index the $plusMinus array with the date. That will allow to test quickly if a year exists or not:
$years = array_combine(array_column($plusMinus, 'date'), $plusMinus);
This uses the array_column() function of PHP 5.5, if you don't have it you can easily create it your own.
After doing that it is exactly how you wrote it in your own words:
foreach($date as &$entry)
{
list($year) = $entry;
$entry = array('date' => $year);
// check if a value of the date array exists in the plusMinus array.
if (isset($years[$year])) {
// If true the date and values from the plusMinus array shall replace the entry in the date array
$entry += $years[$year];
} else {
// If false, the original date array entry is complemented by a [plusMinus] => 0 key-value pair.
$entry += array('plusMinus' => 0);
}
}
unset($entry);
See it i action.
This will work just fine.
I did not at all understand your question, but if i got it this is the way:
First make your $datearray more understandable like this:
$dateArray = array(2007,2008,2009,2010);
$plusMinus = array(
array( 'plus' => 2 ,'date' => 2007),
array( 'minus' => 1 ,'date' => 2008),
array ( 'minus' => 1 , 'date' => '' ),
array ( 'plus' => 1 , 'date' => 2010 , 'minus' => 1 )
);
You can make it multidimensional later;
After that:
foreach($dateArray as $k=>$v)
{
if(in_array($v,$plusMinus[$k]))
{
$filler[$k] = $plusMinus[$k];
}
else{
if(empty($plusMinus[$k]['date']))
{
$filler[$k]['date']= $v;
$filler[$k]['plusMinus'] = 0;
}
}
}
This is simple and clean, understandable way with very little code if your arrays will always have the structure you described, meaning the plusMinus values for 2007 are in the cell [0] and the 2007 in the dateArrays is also in the cell [0] like you have shown. I hope i could help.