for starters I have the following array objects (id, foo and bar are a result of a database query and should be addressed as object variables ->id)
array([0] => array([id] => 1, [foo] => 'a'), [1] => array([id] => 2, [foo] => 'b')
and
array([0] => array([id] => 1, [bar] => 'b'), [1] => array([id] => 2, [bar] => 'a')
I want to create one new array with the id column as key
array([1] => array([foo] => 'a', [bar] => 'b'), [2] => array([foo] => 'b', [bar] => 'a')
I used the following lines of code to create the desired array:
foreach($array1 as $row1) {
$newArray1[$row1->id] = $row1;
}
foreach($array2 as $row2) {
$newArray2[$row2->id] = $row2;
}
foreach($array2 as $key => row3) { //array 2 is always longer or equal to array 1
$result[$key]['bar'] = $newArray2[$key]->bar;
if (isset($newArray1[$key])) {
$result[$key]['foo'] = $newArray1[$key]->foo;
} else {
$result[$key]['bar'] = 0;
}
}
I think this could be done a lot easier. Is this the case, if so, how?
If I understood you need to merge two arrays using as index the 'id' field, which is equal to both ones.
I would do this:
$newarray = array();
for($i=0;$i<count($array1);$i++)
$newarray[$array1[$i]["id"]] = array($array1[$i]["foo"], $array2[$i]["bar"]);
instead of creating new array you can do this:
$arr1=array('0' => array('id' => 1, 'foo' => 'a'), '1' => array('id' => 2, 'foo' => 'b'));
$arr2=array('0' => array('id' => 1, 'bar' => 'b'), '1' => array('id' => 2, 'bar' => 'a'));
for($i=0;$i<count($arr1);$i++){
$arr1[$i] = array("foo"=>$arr1[$i]["foo"], "bar"=>$arr2[$i]["bar"]);
}
print_r($arr1);
Related
I have two arrays with the year's results.
array A (
[a] => '150'
[b] => '200'
[c] => '300'
[d] => '1000'
[e] => '350'
[f] => '1000'
)
array B (
[a] => '500'
[b] => '400'
[d] => '1000'
[f] => '1000'
)
I need to compare the growth results between the two building another array, to show it in a html table. Ex:
[a] => 233%
[b] => 100%
...
I have a array identifying the indexes that are not present on array b.
array c = ('c', 'e');
The thing is, I need the row C and E to still be displayed on the table. But on the iteration, how can i just jump the line with this indexes that have 0 value avoiding calculation 300 by 0 and putting a message instead?
You can iterate the first array and check the next one values:
$arrayA = [
'a' => '150',
'b' => '200',
'c' => '300',
'd' => '1000',
'e' => '350',
'f' => '1000',
];
$arrayB = [
'a' => '500',
'b' => '400',
'd' => '1000',
'f' => '1000',
];
$result = [];
foreach ($arrayA as $key => $value) {
if(isset($arrayB[$key])) {
$result[$key] = round($arrayB[$key] * 100 / $value, 2);
} else {
$result[$key] = 'some value when empty';
}
}
var_dump($result);
Output:
array(6) {
["a"]=>
float(333.33)
["b"]=>
float(200)
["c"]=>
string(21) "some value when empty"
["d"]=>
float(100)
["e"]=>
string(21) "some value when empty"
["f"]=>
float(100)
}
You could loop through array A and check if the key of array A exists in array B using array_key_exists and then calculate the growth percentage:
$arrayA = [
'a' => '150',
'b' => '200',
'c' => '300',
'd' => '1000',
'e' => '350',
'f' => '1000'
];
$arrayB = [
'a' => '500',
'b' => '400',
'd' => '1000',
'f' => '1000'
];
$arrayC = [];
foreach($arrayA as $keyA => $valueA) {
if (array_key_exists($keyA, $arrayB)) {
$arrayC[$keyA] = floor((($arrayB[$keyA] - $valueA) / $valueA ) * 100) . "%";
continue;
}
$arrayC[$keyA] = "No match";
}
Result
Array
(
[a] => 233%
[b] => 100%
[c] => No match
[d] => 0%
[e] => No match
[f] => 0%
)
Demo
If you want a more flexible solution where you can check for both values of the two arrays (i.e. do not base the comparison keys on a single array) and have the possibility to expand it for more than two arrays (it may be useful to others who do not have your same goal).
Fetch the keys of the two array with array_keys and use array_unique in order to avoid duplicate keys values.
<?php
$array_a = [
'a' => 150,
'b' => 200,
'c' => 300,
'd' => 1000,
'e' => 350,
'f' => 1000
];
$array_b = [
'a' => 500,
'b' => 400,
'd' => 1000,
'f' => 1000
];
$keys_a = array_keys($array_a);
$keys_b = array_keys($array_b);
$keys = array_unique(array_merge($keys_a, $keys_b));
$result = [];
foreach ($keys as $key)
{
if (isset($array_a[$key]) && isset($array_b[$key]))
{
$result[$key] = round((($array_b[$key] - $array_a[$key]) / $array_a[$key]) * 100);
}
else
{
$result[$key] = "missing key in one of the two arrays";
}
}
Output:
Array
(
[a] => 233
[b] => 100
[c] => missing key in one of the two arrays
[d] => 0
[e] => missing key in one of the two arrays
[f] => 0
)
I have an empty array (as an example) and a number of multidimensional arrays I would like to push onto this array. However I would like the keys of each multidimensional array to become a key of the empty array
Using
$myEmptyArray[] = $arrayOne;
$myEmptyArray[] = $arrayTwo;
$myEmptyArray[] = $arrayThree;
I get
[
0 => ['one' => ['a' => 'stuff']],
1 => ['two' => ['b' => 'stuff']],
2 => ['three' => ['c' => 'stuff']]
]
I would prefer to have
[
'one' => ['a' => 'stuff'],
'two' => ['b' => 'stuff'],
'three' => ['c' => 'stuff']
]
What is a neat and compact way (one liner or native php function) to do this without having to read the array key with a foreach and then assign this key explicitly to the empty array with the value like
foreach ($arrayOne as $key => $value) {
$myEmptyArray[$key] = $value
}
As I will want to use this in many places in my code
You can use the + (union) operator which "returns the right-hand array appended to the left-hand array; for keys that exist in both arrays, the elements from the left-hand array will be used, and the matching elements from the right-hand array will be ignored".
$array = [];
$array += ['one' => ['a' => 'stuff']];
$array += ['two' => ['b' => 'stuff']];
$array += ['three' => ['b' => 'stuff']];
var_dump($array);
/*
array(3) {
'one' =>
array(1) {
'a' =>
string(5) "stuff"
}
'two' =>
array(1) {
'b' =>
string(5) "stuff"
}
'three' =>
array(1) {
'b' =>
string(5) "stuff"
}
}
*/
You can simply use + to combine those array in the way you want:
$arrayOne = array('one' => array('a' => 'stuff'));
$arrayTwo = array('two' => array('b' => 'stuff'));
$arrayThree = array('three' => array('c' => 'stuff'));
$myEmptyArray = array();
$myEmptyArray += $arrayOne;
$myEmptyArray += $arrayTwo;
$myEmptyArray += $arrayThree;
echo "<pre>"; print_r($myEmptyArray); echo "</pre>";
OUTPUT:
Array
(
[one] => Array
(
[a] => stuff
)
[two] => Array
(
[b] => stuff
)
[three] => Array
(
[c] => stuff
)
)
Consider the following example:
function tableToTree($array, $parents)
{
$result = [];
$p = $parents;
foreach ($array as $k => $row) {
$result[$row[$p[0]]][$row[$p[1]]]= $row[$p[2]]; // **
}
return $result;
}
$foo = [
['x' => 'a', 'y' => 'n','z'=>'AA'],
['x' => 'a', 'y' => 'm','z'=>'BB'],
['x' => 'b', 'y' => 'v','z'=>'CC'],
['x' => 'b', 'y' => 'w','z'=>'DD'],
];
print_r(tableToTree($foo, ['x', 'y','z']));
Which yields:
Array
(
[a] => Array
(
[n] => AA
[m] => BB
)
[b] => Array
(
[v] => CC
[w] => DD
)
)
The above code only works when there are only two parents. How to rewrite the line denoted by ** in a way that it work with arbitrary number of parents.
function tableToTree($array, $parent)
{
$result = array();
foreach ($array as $row) {
$r = &$result; // pointer to result
$p = $parent; // temporary copy of parents
while(count($p) > 2) { // until last key and value
$i = array_shift($p); // next key
if(!isset($r[$row[$i]])) $r[$row[$i]] = null; // add level
$r = &$r[$row[$i]]; // shift pointer to new level
}
$r[$row[array_shift($p)]] = $row[array_shift($p)]; // set value
}
return $result;
}
$foo = array(
array('N' => 2, 'x' => 'a', 'y' => 'n','z'=>'AA'),
array('N' => 1, 'x' => 'a', 'y' => 'm','z'=>'BB'),
array('N' => 2, 'x' => 'b', 'y' => 'v','z'=>'CC'),
array('N' => 1, 'x' => 'b', 'y' => 'w','z'=>'DD'),
array('N' => 1, 'x' => 'c', 'y' => 'w','z'=>'DD'));
print_r(tableToTree($foo, array('N','x', 'y','z')));
result
array (
2 => array (
'a' => array ( 'n' => 'AA',),
'b' => array ( 'v' => 'CC',),
),
1 => array (
'a' => array ( 'm' => 'BB', ),
'b' => array ( 'w' => 'DD', ),
'c' => array ( 'w' => 'DD', ),
),
)
With a table on my database that stores items of a menu, where every item has an ID, a NAME, and a FATHER ID, I need to arrange it and get a tree-like structure of multiple levels. What I need is an array with the top level menus, then every element with his 'childs' array that contains the sub menus, and this sub menus with their 'childs' array containing their respective sub sub menus an so for. English is no my native language so bear with me :)
An example for better understanding.
I have the following menu in array form:
1- System
2- Profile
3- Account
4- Info
5- Security
6- Logout
With the following array:
$array = array(
array('id' => 1, 'item'=>'System', 'id_father' => null),
array('id' => 2, 'item'=>'Profile', 'id_father' => 1),
array('id' => 3, 'item'=>'Account', 'id_father' => 2),
array('id' => 4, 'item'=>'Info', 'id_father' => 3),
array('id' => 5, 'item'=>'Security', 'id_father' => 3),
array('id' => 6, 'item'=>'Logout', 'id_father' => 1)
);
How can I get the following ? :
array(
array('id' => 1, 'item'=>'System', 'id_father' => null,
'childs' => array(
array('id' => 2, 'item'=>'Profile', 'id_father' => 1),
array('id' => 3, 'item'=>'Account', 'id_father' => 2,
'childs' => array(
array('id' => 4, 'item'=>'Info', 'id_father' => 3),
array('id' => 5, 'item'=>'Security', 'id_father' => 3)
),
),
),
),
array('id' => 6, 'item'=>'Logout', 'id_father' => 1)
);
Change $array to :
$array = array(
array('id' => 1, 'item'=>'System', 'id_father' => null),
array('id' => 2, 'item'=>'Profile', 'id_father' => 1),
array('id' => 3, 'item'=>'Account', 'id_father' => 1), // set id_father = 1
array('id' => 4, 'item'=>'Info', 'id_father' => 3),
array('id' => 5, 'item'=>'Security', 'id_father' => 3),
array('id' => 6, 'item'=>'Logout', 'id_father' => null) // edited to set id_father = null
);
Do it:
function tree( $ar, $pid = null ) {
$op = array();
foreach( $ar as $item ) {
if( $item['id_father'] == $pid ) {
$op[$item['id']] = array(
'item' => $item['item'],
'id_father' => $item['id_father'],
'id' => $item['id']
);
// using recursion
$children = tree( $ar, $item['id'] );
if( $children ) {
$op[$item['id']]['childs'] = $children;
}
}
}
return $op;
}
$tree = tree($array);
echo '<pre>';
print_r( $tree);
echo '</pre>';
// OUTPUT
Array
(
[1] => Array
(
[item] => System
[id_father] =>
[id] => 1
[childs] => Array
(
[2] => Array
(
[item] => Profile
[id_father] => 1
[id] => 2
)
[3] => Array
(
[item] => Account
[id_father] => 1
[id] => 3
[childs] => Array
(
[4] => Array
(
[item] => Info
[id_father] => 3
[id] => 4
)
[5] => Array
(
[item] => Security
[id_father] => 3
[id] => 5
)
)
)
)
)
[6] => Array
(
[item] => Logout
[id_father] =>
[id] => 6
)
)
There is no need to recursion in this way :
$pool = array();
foreach ($array as $value) {
$pool[$value['id']] = $value;
$pool[$value['id']]['children'] = array();
}
foreach ($pool as $k => $v) {
if ($v['id_father']) {
$pool[$v['id_father']]['children'][] = &$pool[$k];
}
else
$parent[] = $v['id'];
}
$result = array();
foreach ($parent as $val) {
$result = $result + $pool[$val];
}
print_r($result);
I've been trying every combination of array_count_values and array_map I can think of. I'm hoping you can show me the way.
Here's a sample array:
$arr = array(
array('name' => 'foo','score' => 1),
array('name' => 'foo','score' => 2),
array('name' => 'bar','score' => 1)
);
I'd like to combine the scores of all sub values with the same name. Something like GROUP BY name in MySQL.
Array
(
[0] => Array
(
[name] => foo
[score] => 3
)
[1] => Array
(
[name] => bar
[score] => 1
)
)
I know there are other questions that sort multidimensional arrays, but I'm not able to find one that sums one of the sub values along the way.
You can use array_reduce
$arr = array(
array('name' => 'foo','score' => 1),
array('name' => 'foo','score' => 2),
array('name' => 'bar','score' => 1));
$array = array_reduce($arr, function ($a, $b) {
isset($a[$b['name']]['score']) ? $a[$b['name']]['score'] += $b['score'] : $a[$b['name']] = $b;
return $a;
});
var_dump($array);
Output
array
'foo' =>
array
'name' => string 'foo' (length=3)
'score' => int 3
'bar' =>
array
'name' => string 'bar' (length=3)
'score' => int 1