PHP; Iterate through an assoc. array and add together all values - php

I have an array that I need to 'merge' the values of, and then flatten the entire thing to not be associative. I have this working, but I was hoping to find a better way.
Here's, in essence, the array:
array (
[label] => array(
[0] => array(
key => val
)
[1] => array(
key => val
)
)
[label2] => array(
[0] => array(
key => val
)
)
What I do with this is to add all values from [0] and [1] per assoc. array and return 1 array, where the output is something like:
array (
[label] => array(
[0] => array(
key => SUM(val1+val2)
)
)
[label2] => array(
[0] => array(
key => val
)
)
I do this by:
$i = array();
foreach ($array AS $key => $val) {
$i[$key] = NULL;
foreach ($val AS $r) foreach ($r AS $k => $v) {
if (count($array[$key]) > 1) { // Add value.
$i[$key][$k] += $v;
} else { // Leave alone.
$i[$key][$k] = $v;
}
}
}
Then I flatten it into one big array by using:
$array = array();
$r = new RecursiveIteratorIterator(
new RecursiveArrayIterator($array)
);
foreach ($r as $key => $val)
$array[$key] = $val;
return $array
I think this is ugly and could be done in a much more efficient way. I just can't figure it out, and SPL confuses me; but I want to learn.
Can someone help?
I think I figured it out:
$data = array();
$RII = new RecursiveIteratorIterator(
new RecursiveArrayIterator($it)
);
foreach($RII AS $key => $val) {
$data[$RII->key()] += $RII->current();
}
$this->fullData = $data;
Did everything I needed to in less code. Does this look right?

$data = array();
$RII = new RecursiveIteratorIterator(
new RecursiveArrayIterator($it)
);
foreach($RII AS $key => $val) {
$data[$RII->key()] += $RII->current();
}
$this->fullData = $data;
Replaces both functions above. It goes through the multidimensional array without question and allows me to do what I needed to do.

Related

How can I compare two Arrays and detect if the values are incorrect or missing?

I have to arrays I would like to compare:
$original and $duplicate.
for example here is my original file:
print_r($original);
Array ( [0] => cat423 [1] => dog456 [2] => horse872 [3] => duck082 )
and here is my duplicate:
print_r($dublicate);
Array ( [0] => cat423 [1] => dug356 )
I compare them with array_diff:
$result = array_diff($original, $dublicate);
My result:
Array ( [1] => dog456 [2] => horse872 [3] => duck082 )
So far so good, but I need to make a difference between the values which are incorrect and the values which are completely missing. Is this possible?
A way would be to crawl the entire original array, afterwards you will have two arrays, missings and duplicates.
$original = array("cat423", "dog456", "horse872", "duck082");
$duplicate = array("cat423", "dug356");
$missings = $duplicates = array();
foreach ($original as $val) {
if (in_array($val, $duplicate))
$duplicates[] = $val;
else
$missings[] = $val;
}
If you need the keys as well, you would have to alter the foreach loop like so:
foreach ($original as $key=>$val) {
if (in_array($val, $duplicate))
$duplicates[] = array("key" => $key, "value" => $val);
else
$missings[] = array("key" => $key, "value" => $val);
}
use in_array function
$original = array("cat423", "dog456", "horse872", "duck082");
$duplicate = array("cat423", "dug356");
foreach ($original as $item) {
if(in_array($item, $duplicate))
{
$dup[] = $item;
}
else
{
$miss[] = $item;
}
}
print_r($miss); #Array ( [0] => dog456 [1] => horse872 [2] => duck082 )
print_r($dup); #Array ( [0] => cat423 )
Working Preview

Don't want Array ito combine values

I Have an array in PHP that looks like:
Array ( [2099:360] => 6-3.25 [2130:361] => 4-2.5 [2099:362] => 14-8.75 )
Notice there is Two Keys that are 2099 and one that is 2130. I Have a foreach to remove the everything after the colon. the $drop is my array
$a = array();
foreach ($drop as $part=>$drop_a){
$ex_part = explode(":", $part);
$a[$ex_part[0]] = $drop_a;
}
print_r($a);
but when I print $a it displays only the recent value of the 2099?
Array ( [2099] => 14-8.75 [2130] => 4-2.5 )
Any Successions? How can I get it to display all of the values?
Thank You for Your Help
One solution is to use a multi-dimensional array to store this strategy:
$a = array();
foreach ($drop as $part=>$drop_a){
$ex_part = explode(":", $part);
if (isset($a[$ex_part[0]])) {
$a[$ex_part[0]][] = $drop_a;
} else {
$a[$ex_part[0]] = array($drop_a);
}
}
Your resulting data-set will however be different:
Array ( [2099] => Array ( [0] => 6-3.25 [1] => 14-8.75) [2130] => Array ( [0] => 4-2.5 ) )
It may be beneficial to you to preserve the second portion after the colon :
$a = array();
foreach ($drop as $part=>$drop_a){
$ex_part = explode(":", $part);
if (isset($a[$ex_part[0]])) {
$a[$ex_part[0]][$ex_part[1]] = $drop_a;
} else {
$a[$ex_part[0]] = array($ex_part[1] => $drop_a);
}
}
Now your result is a little more meaningful:
Array ( [2099] => Array ( [360] => 6-3.25 [362] => 14-8.75) [2130] => Array ( [361] => 4-2.5 ) )
Finally you can use alternative key-naming strategy if one is already occupied:
$a = array();
foreach ($drop as $part=>$drop_a){
$ex_part = explode(":", $part);
if (isset($a[$ex_part[0]])) {
$a[altName($ex_part[0], $a)] = $drop_a;
} else {
$a[$ex_part[0]] = $drop_a;
}
}
function altName($key, $array) {
$key++; // Or however you want to do an alternative naming strategy
if (isset($array[$key])) {
return altName($key, $array); // This will eventually resolve - but be careful with the recursion
}
return $key;
}
Returns:
Array
(
[2099] => 6-3.25
[2130] => 4-2.5
[2100] => 14-8.75
)
You basically have a key and a sub key for each entry, so just put them in a multidimensional array:
$a = array();
foreach ($drop as $key => $val) {
list($key, $subKey) = explode(':', $key);
$a[$key][$subKey] = $val;
}
Gives you:
Array
(
[2099] => Array
(
[360] => 6-3.25
[362] => 14-8.75
)
[2130] => Array
(
[361] => 4-2.5
)
)
You can traverse multidimensional arrays by nesting loops:
foreach ($a as $key => $subKeys) {
foreach ($subKeys as $subKey => $val) {
echo "$key contains $subKey (value of $val) <br>";
}
}

Replace key of array with the value of another array while looping through

I have two multidimensional arrays. First one $properties contains english names and their values. My second array contains the translations. An example
$properties[] = array(array("Floor"=>"5qm"));
$properties[] = array(array("Height"=>"10m"));
$translations[] = array(array("Floor"=>"Boden"));
$translations[] = array(array("Height"=>"Höhe"));
(They are multidimensional because the contains more elements, but they shouldn't matter now)
Now I want to translate this Array, so that I its at the end like this:
$properties[] = array(array("Boden"=>"5qm"));
$properties[] = array(array("Höhe"=>"10m"));
I have managed to build the foreach construct to loop through these arrays, but at the end it is not translated, the problem is, how I tell the array to replace the key with the value.
What I have done is this:
//Translate Array
foreach ($properties as $PropertyArray) {
//need second foreach because multidimensional array
foreach ($PropertyArray as $P_KiviPropertyNameKey => $P_PropertyValue) {
foreach ($translations as $TranslationArray) {
//same as above
foreach ($TranslationArray as $T_KiviTranslationPropertyKey => $T_KiviTranslationValue) {
if ($P_KiviPropertyNameKey == $T_KiviTranslationPropertyKey) {
//Name found, save new array key
$P_KiviPropertyNameKey = $T_KiviTranslationValue;
}
}
}
}
}
The problem is with the line where to save the new key:
$P_KiviPropertyNameKey = $T_KiviTranslationValue;
I know this part is executed correctly and contains the correct variables, but I believe this is the false way to assing the new key.
This is the way it should be done:
$properties[$oldkey] = $translations[$newkey];
So I tried this one:
$PropertyArray[$P_KiviPropertyNameKey] = $TranslationArray[$T_KiviTranslationPropertyKey];
As far as I understood, the above line should change the P_KiviPropertyNameKey of the PropertyArray into the value of Translation Array but I do not receive any error nor is the name translated. How should this be done correctly?
Thank you for any help!
Additional info
This is a live example of the properties array
Array
(
[0] => Array
(
[country_id] => 4402
)
[1] => Array
(
[iv_person_phone] => 03-11
)
[2] => Array
(
[companyperson_lastname] => Kallio
)
[3] => Array
(
[rc_lot_area_m2] => 2412.7
)
[56] => Array
(
[floors] => 3
)
[57] => Array
(
[total_area_m2] => 97.0
)
[58] => Array
(
[igglo_silentsale_realty_flag] => false
)
[59] => Array
(
[possession_partition_flag] => false
)
[60] => Array
(
[charges_parkingspace] => 10
)
[61] => Array
(
[0] => Array
(
[image_realtyimagetype_id] => yleiskuva
)
[1] => Array
(
[image_itemimagetype_name] => kivirealty-original
)
[2] => Array
(
[image_desc] => makuuhuone
)
)
)
And this is a live example of the translations array
Array
(
[0] => Array
(
[addr_region_area_id] => Maakunta
[group] => Kohde
)
[1] => Array
(
[addr_town_area] => Kunta
[group] => Kohde
)
[2] => Array
(
[arable_no_flag] => Ei peltoa
[group] => Kohde
)
[3] => Array
(
[arableland] => Pellon kuvaus
[group] => Kohde
)
)
I can build the translations array in another way. I did this like this, because in the second step I have to check, which group the keys belong to...
Try this :
$properties = array();
$translations = array();
$properties[] = array("Floor"=>"5qm");
$properties[] = array("Height"=>"10m");
$translations[] = array("Floor"=>"Boden");
$translations[] = array("Height"=>"Höhe");
$temp = call_user_func_array('array_merge_recursive', $translations);
$result = array();
foreach($properties as $key=>$val){
foreach($val as $k=>$v){
$result[$key][$temp[$k]] = $v;
}
}
echo "<pre>";
print_r($result);
output:
Array
(
[0] => Array
(
[Boden] => 5qm
)
[1] => Array
(
[Höhe] => 10m
)
)
Please note : I changed the array to $properties[] = array("Floor"=>"5qm");, Removed a level of array, I guess this is how you need to structure your array.
According to the structure of $properties and $translations, you somehow know how these are connected. It's a bit vague how the indices of the array match eachother, meaning the values in $properties at index 0 is the equivalent for the translation in $translations at index 0.
I'm just wondering why the $translations array need to have the same structure (in nesting) as the $properties array. To my opinion the word Height can only mean Höhe in German. Representing it as an array would suggest there are multiple translations possible.
So if you could narrow down the $translations array to an one dimensional array as in:
$translation = array(
"Height"=>"Höhe",
"Floor"=>"Boden"
);
A possible loop would be
$result = array();
foreach($properties as $i => $array2) {
foreach($array2 as $i2 => $array3) {
foreach($array3 as $key => $value) {
$translatedKey = array_key_exists($key, $translations) ?
$translations[$key]:
$key;
$result[$i][$i2][$translatedKey] = $value;
}
}
}
(I see every body posting 2 loops, it's an array,array,array structure, not array,array ..)
If you cannot narrow down the translation array to a one dimensional array, then I'm just wondering if each index in the $properties array matches the same index in the $translations array, if so it's the same trick by adding the indices (location):
$translatedKey = $translations[$i][$i2][$key];
I've used array_key_exists because I'm not sure a translation key is always present. You have to create the logic for each case scenario yourself on what to check or not.
This is a fully recursive way to do it.
/* input */
$properties[] = array(array("Floor"=>"5qm", array("Test"=>"123")));
$properties[] = array(array("Height"=>"10m"));
$translations[] = array(array("Floor"=>"Boden", array("Test"=>"Foo")));
$translations[] = array(array("Height"=>"Höhe"));
function array_flip_recursive($arr) {
foreach ($arr as $key => $val) {
if (is_array($val)) {
$arr[$key] = array_flip_recursive($val);
}
else {
$arr = #array_flip($arr);
}
}
return $arr;
}
function array_merge_it($arr) {
foreach ($arr as $key => $val) {
if (is_array($val)) {
$arr[$key] = array_merge_it($val);
} else {
if(isset($arr[$key]) && !empty($arr[$key])) {
#$arr[$key] = $arr[$val];
}
}
}
return $arr;
}
function array_delete_empty($arr) {
foreach ($arr as $key => $val) {
if (is_array($val)) {
$arr[$key] = array_delete_empty($val);
}
else {
if(empty($arr[$key])) {
unset($arr[$key]);
}
}
}
return $arr;
}
$arr = array_replace_recursive($properties, $translations);
$arr = array_flip_recursive($arr);
$arr = array_replace_recursive($arr, $properties);
$arr = array_merge_it($arr);
$arr = array_delete_empty($arr);
print_r($arr);
http://sandbox.onlinephpfunctions.com/code/d2f92605b609b9739964ece9a4d8f389be4a7b81
You have to do the for loop in this way. If i understood you right (i.e) in associative array first key is same (some index).
foreach($properties as $key => $values) {
foreach($values as $key1 => $value1) {
$propertyResult[] = array($translations[$key][$key1][$value1] => $properties[$key][$key1][$value1]);
}
}
print_r($propertyResult);

How to setup a PHP multidimensional array and declare the array keys?

I need some help setting up a PHP array. I get a little lost with multidimensional arrays.
Right now, I have an array with multiple products as follows:
If I do: print_r($products['1']); I get:
Array ( [0] => size:large [1] => color:blue [2] => material:cotton )
I can do print_r($products['2']); , etc and it will show a similar array as above.
I am trying to get it where I can do this:
echo $products['1']['color']; // the color of product 1
...and echo "blue";
I tried exploding the string and adding it to the array as follows:
$step_two = explode(":", $products['1']);
foreach( $step_two as $key => $value){
$products['1'][$key] = $value;
}
I know I'm obviously doing the explode / foreach way wrong but I wanted to post my code anyway. I hope this is enough information to help sort this out.
Try this:
foreach ($products as &$product)
{
foreach ($product as $key => $value)
{
list($attribute, $val) = explode(':',$value);
$product[$attribute] = $val;
// optional:
unset($product[$key]);
}
}
?>
Here goes a sample that will convert from your first form to your desired form (output goes below)
<?php
$a = array( '1' => array('color:blue','size:large','price:cheap'));
print_r($a);
foreach ($a as $key => $inner_array) {
foreach ($inner_array as $key2 => $attribute) {
$parts = explode(":",$attribute);
$a[$key][$parts[0]] = $parts[1];
//Optional, to remove the old values
unset($a[$key][$key2]);
}
}
print_r($a);
?>
root#xxx:/home/vinko/is# php a.php
Array
(
[1] => Array
(
[0] => color:blue
[1] => size:large
[2] => price:cheap
)
)
Array
(
[1] => Array
(
[color] => blue
[size] => large
[price] => cheap
)
)
You would be better of to build the array the right way, but to solve your problem you need to explode in the loop, something like:
foreach( $products['1'] as $value){
$step_two = explode(":", $value);
$products['1'][$step_two[0]] = $step_two[1];
}
You can wrap another foreach around it to loop over your whole $products array.
And you'd also better build a new array to avoid having both the old and the new values in your $products array.
You are right: you got the "foreach" and "explode" the wrong way around. Try something like this:
foreach($products['1'] as $param => $value) {
$kv = explode(":", $value);
if(count($kv) == 2) {
$products[$kv[0]] = $kv[1];
unset($products['1'][$param]);
}
}
This code first loops over the sub-elements of your first element, then splits each one by the colon and, if there are two parts, sets the key-value back into the array.
Note the unset line - it removes array elements like $products['1'][1] after setting products['1']['color'] to blue.
If you already have $products structured in that way, you can modifty its structure like this:
$products = array(
'1' => array(
0 => 'size:large', 1 => 'color:blue', 2 => 'material:cotton'
),
'2' => array(
0 => 'size:small', 1 => 'color:red', 2 => 'material:silk'
),
);
foreach ($products as &$product) {
$newArray = array();
foreach ($product as $item) {
list($key, $value) = explode(':', $item);
$newArray[$key] = $value;
}
$product = $newArray;
}
print_r($products);
If you don't want to overwrite original $products array, just append $newArray to another array.
<?php
$products = array();
$new_product = array();
$new_product['color'] = "blue";
$new_product['size'] = "large";
$new_product['material'] = "cotton";
$products[] = $new_product;
echo $products[0]['color'];
//print_r($products);

Simplify a nested array into a single level array [duplicate]

This question already has answers here:
Closed 12 years ago.
Possible Duplicate:
How to Flatten a Multidimensional Array?
Let's say I have an array like this:
array (
1 =>
array (
2 =>
array (
16 =>
array (
18 =>
array (
),
),
17 =>
array (
),
),
),
14 =>
array (
15 =>
array (
),
),
)
How would I go about tranforming it into array like this?
array(1,2,16,18,17,14,15);
Sorry for the closevote. Didnt pay proper attention about you wanting the keys. Solution below:
$iterator = new RecursiveIteratorIterator(
new RecursiveArrayIterator($arr),
RecursiveIteratorIterator::SELF_FIRST);
$keys = array();
and then either
$keys = array();
foreach($iterator as $key => $val) {
$keys[] = $key;
}
or with the iterator instance directly
$keys = array();
for($iterator->rewind(); $iterator->valid(); $iterator->next()) {
$keys[] = $iterator->key();
}
or more complicated than necessary
iterator_apply($iterator, function(Iterator $iterator) use (&$keys) {
$keys[] = $iterator->key();
return TRUE;
}, array($iterator));
gives
Array
(
[0] => 1
[1] => 2
[2] => 16
[3] => 18
[4] => 17
[5] => 14
[6] => 15
)
how about some recursion
$result = array();
function walkthrough($arr){
$keys = array_keys($arr);
array_push($result, $keys);
foreach ($keys as $key)
{
if (is_array($arr[$key]))
walkthrough($arr[$key]);
else
array_push($result,$arr[$key]);
}
return $result;
}
walkthrouth($your_arr);
P.S.:Code can be bugged, but you've got an idea :)
function flattenArray($array) {
$arrayValues = array();
foreach (new RecursiveIteratorIterator( new RecursiveArrayIterator($array)) as $val) {
$arrayValues[] = $val;
}
return $arrayValues;
} // function flattenArrayIndexed()
If we consider the nested array as a tree structure, you can apply depth first traversal to convert it into a list. That is, into a single array you desire.
I have searched all similar questions and it seems there is no way without a recursion that would keep the keys order intact.
So I just went with classic recursion:
function getArrayKeysRecursive(array $theArray)
{
$aArrayKeys = array();
foreach ($theArray as $k=>$v) {
if (is_array($v)) {
$aArrayKeys = array_merge($aArrayKeys, array($k), getArrayKeysRecursive($v));
} else {
$aArrayKeys = array_merge($aArrayKeys, array($k));
}
}
return $aArrayKeys;
}

Categories