Combination of arrays - php

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.

Related

Group and merge subarray data based on one column value

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.

Sort array values based on parent/child relationship

I am trying to sort an array to ensure that the parent of any item always exists before it in the array. For example:
Array
(
[0] => Array
(
[0] => 207306
[1] => Bob
[2] =>
)
[1] => Array
(
[0] => 199730
[1] => Sam
[2] => 199714
)
[2] => Array
(
[0] => 199728
[1] => Simon
[2] => 207306
)
[3] => Array
(
[0] => 199714
[1] => John
[2] => 207306
)
[4] => Array
(
[0] => 199716
[1] => Tom
[2] => 199718
)
[5] => Array
(
[0] => 199718
[1] => Phillip
[2] => 207306
)
[6] => Array
(
[0] => 199720
[1] => James
[2] => 207306
)
)
In the above array this "fails" as [1][2] (Sam) does not yet exist and nor does [4][2] (Tom).
The correct output would be as, in this case, as both Sam and Tom's parents already exist before they appear in the array:
Array
(
[0] => Array
(
[0] => 207306
[1] => Bob
[2] =>
)
[1] => Array
(
[0] => 199714
[1] => John
[2] => 207306
)
[2] => Array
(
[0] => 199730
[1] => Sam
[2] => 199714
)
[3] => Array
(
[0] => 199728
[1] => Simon
[2] => 207306
)
[4] => Array
(
[0] => 199718
[1] => Phillip
[2] => 207306
)
[5] => Array
(
[0] => 199716
[1] => Tom
[2] => 199718
)
[6] => Array
(
[0] => 199720
[1] => James
[2] => 207306
)
)
I found an answer https://stackoverflow.com/a/12961400/1278201 which was very close but it only seems to go one level deep (i.e. there is only ever one parent) whereas in my case there could be 1 or 10 levels deep in the hierarchy.
How do I sort the array so no value can appear unless its parent already exists before it?
This will trivially order the array (in O(n)) putting first all those with no parent, then these whose parent is already in the array, iteratively, until there's no children having the current element as parent.
# map the children by parent
$parents = ['' => []];
foreach ($array as $val) {
$parents[$val[2]][] = $val;
}
# start with those with no parent
$sorted = $parents[''];
# add the children the current nodes are parent of until the array is empty
foreach ($sorted as &$val) {
if (isset($parents[$val[0]])) {
foreach ($parents[$val[0]] as $next) {
$sorted[] = $next;
}
}
}
This code requires PHP 7, it may not work in some cases under PHP 5. - for PHP 5 compatibility you will have to swap the foreach ($sorted as &$val) with for ($val = reset($sorted); $val; $val = next($sorted)):
# a bit slower loop which works in all versions
for ($val = reset($sorted); $val; $val = next($sorted)) {
if (isset($parents[$val[0]])) {
foreach ($parents[$val[0]] as $next) {
$sorted[] = $next;
}
}
}
Live demo: https://3v4l.org/Uk6Gs
I have two different version for you.
a) Using a "walk the tree" approach with recursion and references to minimize memory consumption
$data = [
[207306,'Bob',''], [199730,'Sam',199714],
[199728,'Simon',207306], [199714,'John',207306],
[199716, 'Tom',199718], [199718,'Phillip',207306],
[199720,'James',207306]
];
$list = [];
generateList($data, '', $list);
var_dump($list);
function generateList($data, $id, &$list) {
foreach($data as $d) {
if($d[2] == $id) {
$list[] = $d; // Child found, add it to list
generateList($data, $d[0], $list); // Now search for childs of this child
}
}
}
b) Using phps built in uusort()function (seems only to work up to php 5.x and not with php7+)
$data = [
[207306,'Bob',''], [199730,'Sam',199714],
[199728,'Simon',207306], [199714,'John',207306],
[199716, 'Tom',199718], [199718,'Phillip',207306],
[199720,'James',207306]
];
usort($data, 'cmp');
var_dump($data);
function cmp($a, $b) {
if($a[2] == '' || $a[0] == $b[2]) return -1; //$a is root element or $b is child of $a
if($b[2] == '' || $b[0] == $a[2]) return 1; //$b is root element or $a is child of $b
return 0; // both elements have no direct relation
}
I checked this works in PHP 5.6 and PHP 7
Sample array:
$array = Array(0 => Array(
0 => 207306,
1 => 'Bob',
2 => '',
),
1 => Array
(
0 => 199730,
1 => 'Sam',
2 => 199714,
),
2 => Array
(
0 => 199728,
1 => 'Simon',
2 => 207306,
),
3 => Array
(
0 => 199714,
1 => 'John',
2 => 207306,
),
4 => Array
(
0 => 199716,
1 => 'Tom',
2 => 199718,
),
5 => Array
(
0 => 199718,
1 => 'Phillip',
2 => 207306,
),
6 => Array
(
0 => 199720,
1 => 'James',
2 => 207306,
),
);
echo "<pre>";
$emp = array();
//form the array with parent and child
foreach ($array as $val) {
$manager = ($val[2] == '') ? 0 : $val[2];
$exist = array_search_key($val[2], $emp);
if ($exist)
$emp[$exist[0]][$val[0]] = $val;
else
//print_R(array_search_key(199714,$emp));
$emp[$manager][$val[0]] = $val;
}
$u_emp = $emp[0];
unset($emp[0]);
//associate the correct child/emp after the manager
foreach ($emp as $k => $val) {
$exist = array_search_key($k, $u_emp);
$pos = array_search($k, array_keys($u_emp));
$u_emp = array_slice($u_emp, 0, $pos+1, true) +
$val +
array_slice($u_emp, $pos-1, count($u_emp) - 1, true);
}
print_R($u_emp); //print the final result
// key search function from the array
function array_search_key($needle_key, $array, $parent = array())
{
foreach ($array AS $key => $value) {
$parent = array();
if ($key == $needle_key)
return $parent;
if (is_array($value)) {
array_push($parent, $key);
if (($result = array_search_key($needle_key, $value, $parent)) !== false)
return $parent;
}
}
return false;
}
Find the below code that might be helpful.So, your output is stored in $sortedarray.
$a=array(array(207306,'Bob',''),
array (199730,'Sam',199714),
array(199728,'Simon',207306),
array(199714,'John',207306),
array(199716,'Tom',199718),
array(199718,'Phillip',207306),
array(199720,'James',207306));
$sortedarray=$a;
foreach($a as $key=>$value){
$checkvalue=$value[2];
$checkkey=$key;
foreach($a as $key2=>$value2){
if($key<$key2){
if ($value2[0]===$checkvalue){
$sortedarray[$key]=$value2;
$sortedarray[$key2]=$value;
}else{
}
}
}
}
print_r($sortedarray);
What about this approach:
Create an empty array result.
Loop over your array and only take the items out of it where [2] is empty and insert them into result.
When this Loop is done you use a foreach-Loop inside a while-loop. With the foreach-Loop you take every item out of your array where [2] is already part of result. And you do this as long as your array contains anything.
$result = array();
$result[''] = 'root';
while(!empty($yourArray)){
foreach($yourArray as $i=>$value){
if(isset($result[$value[2]])){
// use the next line only to show old order
$value['oldIndex'] = $i;
$result[$value[0]] = $value;
unset($yourArray[$i]);
}
}
}
unset($result['']);
PS: You may run into trouble by removing parts of an array while walking over it. If you do so ... try to solve this :)
PPS: Think about a break condition if your array have an unsolved loop or a child without an parent.
you can use your array in variable $arr and use this code it will give you required output.
function check($a, $b) {
return ($a[0] == $b[2]) ? -1 : 1;
}
uasort($arr, 'check');
echo '<pre>';
print_r(array_values($arr));
echo '</pre>';

Pushing a sub array into the same array

I am trying to put content of one array into the same array. Here I have an array $mclass with values such as
Array
(
[0] => stdClass Object
(
[room_id] => 1,3,5
[day] => 1
[class_teacher] => TEA-2014-2
[final_exam_date] => 2015-09-21
)
)
You can see I have room_id index with 1,3,5 value. Now, I want to explode the room_id and get duplicate of same array index data with change of room_id and push into the array. and finally delete the current array index such as [0]. Here I want the final result as.
Array
(
[0] => stdClass Object
(
[room_id] => 1
[day] => 1
[class_teacher] => TEA-2014-2
[final_exam_date] => 2015-09-21
)
[1] => stdClass Object
(
[room_id] => 3
[day] => 1
[class_teacher] => TEA-2014-2
[final_exam_date] => 2015-09-21
)
[2] => stdClass Object
(
[room_id] => 5
[day] => 1
[class_teacher] => TEA-2014-2
[final_exam_date] => 2015-09-21
)
)
Here is my code for the same:
if(count($mclass)>0)
{
foreach($mclass as $mclasskey=>$mclass_row)
{
/* Room ID Calculation */
if(isset($mclass[$mclasskey]))
{
$temp_room_id = explode(',',$mclass_row->room_id);
if(count($temp_room_id)>1)
{
foreach($temp_room_id as $trkey=>$tr)
{
if(!in_array($temp_room_id[$trkey], $morning_class_semester))
{
array_push($morning_class_semester,$temp_room_id[$trkey]);
}
}
if(count($morning_class_semester)>0)
{
foreach($morning_class_semester as $mcskey=>$mcs)
{
$index_count = count($new_test);
$test[$index_count] = $mclass[$mclasskey];
$test[$index_count]->room_id = $morning_class_semester[$mcskey];
array_push($new_test,$test[$index_count]);
}
unset($mclass[$mclasskey]);
}
}
}
}
}
The code below does what you're looking for using only arrays. So you'll have to change the array access operators to -> since you're accessing an object. I'd do so, but it would break the example, so I'll leave that up to you.
Code Explained:
Loop through array selecting each subarray (object in your case), explode on the $item('room_id') ... ($item->room_id in your case) ... and create sub arrays, via loop, from that using the data from the original using each key. Remove the original item (which has the combined room_ids) and combine the placeholder and original array.
<?php
//Establish some data to work with
$array = array(
array(
"room_id" => "1,3,5",
"day" => 1,
"class_teacher" => "TEA-2014-2",
"final_exam_date" => "2015-09-21",
));
foreach ($array as $key => $item) {
$placeholder = array();
$ids = explode(',',$item['room_id']);
if (count($ids) > 1) {
foreach ($ids as $id) {
$push = array(
'room_id' => $id,
'day' => $item['day'],
'class_teacher' => $item['class_teacher'],
'final_exam_date' => $item['final_exam_date']
);
array_push($placeholder, $push);
}
$array = array_merge($array, $placeholder);
unset($array[$key]);
}
}
var_dump($array);
?>

Problem with Building Arrays in Different Coding Styles

I'm having a strange problem while building arrays. I start off with an array that looks like this:
Array (
[0] => Array (
[tag_id] => 19
[tag_translation_id] => 12
[fk_language_id] => 1
[fk_tag_id] => 19
[tag_name] => test
)
[1] => Array (
[tag_id] => 20
[tag_translation_id] => 14
[fk_language_id] => 1
[fk_tag_id] => 20
[tag_name] => testa
)
[2] => Array (
[tag_id] => 20
[tag_translation_id] => 15
[fk_language_id] => 3
[fk_tag_id] => 20
[tag_name] => fdfda
)
)
What I want to do is merge each result with the same tag_id into a single array. This works:
$tags = array();
foreach($results->as_array() as $key=>$result)
{
if(!in_array($result['tag_id'], $tags))
{
$tags[$result['tag_id']] = array();
}
}
foreach($results->as_array() as $result)
{
array_push($tags[$result['tag_id']], array($result['fk_language_id'] , $result['tag_name']));
}
Here is the intended result:
Array (
[19] => Array (
[0] => Array (
[0] => 1
[1] => test
)
)
[20] => Array (
[0] => Array (
[0] => 1
[1] => testa
)
[1] => Array (
[0] => 3
[1] => fdfda
)
)
)
However, I've got two loops here, and I know this isn't ideal. Why do THESE not work??
$tags = array();
foreach($results->as_array() as $key=>$result)
{
$tags[$result['tag_id']] .= array($result['fk_language_id'] , $result['tag_name']);
}
With this example I get two empty arrays...
Array ( [19] => Array [20] => ArrayArray )
Or even...
$tags = array();
foreach($results->as_array() as $key=>$result)
{
if(!in_array($result['tag_id'], $tags))
{
$tags[$result['tag_id']] = array();
}
array_push($tags[$result['tag_id']], array($result['fk_language_id'] , $result['tag_name']));
}
Which for some reason overwrites the first value of the second array with the second value of the second array.
Array (
[19] => Array (
[0] => Array (
[0] => 1
[1] => test
)
)
[20] => Array (
[0] => Array (
[0] => 3
[1] => fdfda
)
)
)
What am I doing wrong in the second 2 examples?
To answer your question, your second method fails because you're using the incorrect .= operator. Your third method fails because your !in_array check is always false (it checks whether the value is in the array, not whether the key is set) and overwrites the array each iteration. You only really need this (as mentioned by others, in pseudo-code):
$result = array();
foreach ($array as $values) {
$result[$values['key']][] = array($values['foo'], $values['bar']);
}
The .= operator is string concatenation. Arrays are merged with +=.
If I understand the issue correctly, the code should go like this:
$tags = array();
foreach ($results as $result)
$tags[$result['tag_id']][] = array($result['fk_language_id'], $result['tag_name']);
$tags = array();
foreach($results->as_array() as $key=>$result)
{
$tags[$result['tag_id']] .= array($result['fk_language_id'] , $result['tag_name']);
}
you cannot add a value to an array with the .= (dot equal) operator.
why are you doing $results->as_array() ????
do simply:
foreach($results as $key=>$result) {
Instead of using .= try using []
$tags = array();
foreach ($results as $result)
{
if(!isset($tags[$result['tag_id']]))
$tags[$result['tag_id']] = array();
$tags[$result['tag_id']][] = array($result['fk_language_id'], result['tag_name']);
}
.= is to concatinate a string
+= is to concatinate a number
[] is to concatinate to an array
Hope this helps?
Edit: Noticed that it "might" fail if the tag_id doesn't already exist in the array, so it might be worth just checking first and setting it to an array just in case.

How can I create multidimensional arrays from a string in PHP?

So My problem is:
I want to create nested array from string as reference.
My String is "res[0]['links'][0]"
So I want to create array $res['0']['links']['0']
I tried:
$result = "res[0]['links'][0]";
$$result = array("id"=>'1',"class"=>'3');
$result = "res[0]['links'][1]";
$$result = array("id"=>'3',"class"=>'9');
when print_r($res)
I see:
<b>Notice</b>: Undefined variable: res in <b>/home/fanbase/domains/fanbase.sportbase.pl/public_html/index.php</b> on line <b>45</b>
I need to see:
Array
(
[0] => Array
(
[links] => Array
(
[0] => Array
(
[id] => 1
[class] => 3
)
)
)
[1] => Array
(
[links] => Array
(
[0] => Array
(
[id] => 3
[class] => 9
)
)
)
)
Thanks for any help.
So you have a description of an array structure, and something to fill it with. That's doable with something like:
function array_create(&$target, $desc, $fill) {
preg_match_all("/[^\[\]']+/", $desc, $uu);
// unoptimized, always uses strings
foreach ($uu[0] as $sub) {
if (! isset($target[$sub])) {
$target[$sub] = array();
}
$target = & $target[$sub];
}
$target = $fill;
}
array_create( $res, "[0]['links'][0]", array("id"=>'1',"class"=>'3') );
array_create( $res, "[0]['links'][1]", array("id"=>'3',"class"=>'9') );
Note how the array name itself is not part of the structure descriptor. But you could theoretically keep it. Instead call the array_create() function with a $tmp variable, and afterwards extract() it to achieve the desired effect:
array_create($tmp, "res[0][links][0]", array(1,2,3,4,5));
extract($tmp);
Another lazy solution would be to use str_parse after a loop combining the array description with the data array as URL-encoded string.
I have a very stupid way for this, you can try this :-)
Suppose your string is "res[0]['links'][0]" first append $ in this and then put in eval command and it will really rock you. Follow the following example
$tmp = '$'.'res[0]['links'][0]'.'= array()';
eval($tmp);
Now you can use your array $res
100% work around and :-)
`
$res = array();
$res[0]['links'][0] = array("id"=>'1',"class"=>'3');
$res[0]['links'][0] = array("id"=>'3',"class"=>'9');
print_r($res);
but read the comments first and learn about arrays first.
In addition to mario's answer, I used another function from php.net comments, together, to make input array (output from jquery form serializeArray) like this:
[2] => Array
(
[name] => apple[color]
[value] => red
)
[3] => Array
(
[name] => appleSeeds[27][genome]
[value] => 201
)
[4] => Array
(
[name] => appleSeeds[27][age]
[value] => 2 weeks
)
[5] => Array
(
[name] => apple[age]
[value] => 3 weeks
)
[6] => Array
(
[name] => appleSeeds[29][genome]
[value] => 103
)
[7] => Array
(
[name] => appleSeeds[29][age]
[value] => 2.2 weeks
)
into
Array
(
[apple] => Array
(
[color] => red
[age] => 3 weeks
)
[appleSeeds] => Array
(
[27] => Array
(
[genome] => 201
[age] => 2 weeks
)
[29] => Array
(
[genome] => 103
[age] => 2.2 weeks
)
)
)
This allowed to maintain numeric keys, without incremental appending of array_merge. So, I used sequence like this:
function MergeArrays($Arr1, $Arr2) {
foreach($Arr2 as $key => $Value) {
if(array_key_exists($key, $Arr1) && is_array($Value)) {
$Arr1[$key] = MergeArrays($Arr1[$key], $Arr2[$key]);
}
else { $Arr1[$key] = $Value; }
}
return $Arr1;
}
function array_create(&$target, $desc, $fill) {
preg_match_all("/[^\[\]']+/", $desc, $uu);
foreach ($uu[0] as $sub) {
if (! isset($target[$sub])) {
$target[$sub] = array();
}
$target = & $target[$sub];
}
$target = $fill;
}
$input = $_POST['formData'];
$result = array();
foreach ($input as $k => $v) {
$sub = array();
array_create($sub, $v['name'], $v['value']);
$result = MergeArrays($result, $sub);
}

Categories