need efficient restructuring of a complicated PHP assoc array [closed] - php

This question is unlikely to help any future visitors; it is only relevant to a small geographic area, a specific moment in time, or an extraordinarily narrow situation that is not generally applicable to the worldwide audience of the internet. For help making this question more broadly applicable, visit the help center.
Closed 10 years ago.
In my data mining project, I'm given a complicated, huge multidemensional array of arrays that contains all the info I require, except that I have to perform a "fix" on it before I can process it. I've written some code that takes care of the issue, but it's taking way too long for the huge amount of data I have to "fix," and I'm hoping someone can help me find a more efficient solution.
Essentially, the type of array I'm working with is first indexed by an integer, as any run-of-the-mill array would, i.e. $x[0], $x[1], $x[2], except that each element is an associative array that contains key-pair values that I need (such as $x[0]['item'], $x[0]['price']), however one key is stored a bit deeper, the ID.
An ID number exists in the array as $x[0]['#attributes']['id'], and I would like to simplify the structure by duplicating this info along with the other key pairs, like $x[0]['id'].
The data set I'm working with is large, but here is a simplified example of my situation:
$attrib1 = array('id'=>'101');
$item1 = array('#attributes'=>$attrib1, 'item'=>'milk', 'price'=>'3.50');
$attrib2 = array('id'=>'102');
$item2 = array('#attributes'=>$attrib2, 'item'=>'butter', 'price'=>'2.45');
$attrib3 = array('id'=>'103');
$item3 = array('#attributes'=>$attrib3, 'item'=>'bread', 'price'=>'1.19');
$items = array($item1, $item2, $item3);
echo "Starting data - items using itemid as attribute:\n";
print_r($items);
# set item numbers by key instead of attribute
$i=0;
while(isset($items[$i]['#attributes']['id'])) {
$items[$i]['itemid'] = $items[$i]['#attributes']['id'];
#unset($items[$i]['#attributes']);
$i++;
} # while
echo "\nDesired result - items using itemid as key:\n";
print_r($items);
Here is the output from that above example:
Starting data - items using itemid as attribute:
Array
(
[0] => Array
(
[#attributes] => Array
(
[id] => 101
)
[item] => milk
[price] => 3.50
)
[1] => Array
(
[#attributes] => Array
(
[id] => 102
)
[item] => butter
[price] => 2.45
)
[2] => Array
(
[#attributes] => Array
(
[id] => 103
)
[item] => bread
[price] => 1.19
)
)
Desired result - items using itemid as key:
Array
(
[0] => Array
(
[#attributes] => Array
(
[id] => 101
)
[item] => milk
[price] => 3.50
[itemid] => 101
)
[1] => Array
(
[#attributes] => Array
(
[id] => 102
)
[item] => butter
[price] => 2.45
[itemid] => 102
)
[2] => Array
(
[#attributes] => Array
(
[id] => 103
)
[item] => bread
[price] => 1.19
[itemid] => 103
)
)
Note the added [itemid] key-value pair in the desired result. Is there a faster / more elegant way of accomplishing this? I've looked at some of PHP's fancy array functions, but I can't wrap my head around this more complicated situation to make use of them. Any ideas?

Memory Efficiency
PHP DOC Comments : Memory footprint of splFixedArray is about 37% of a regular "array" of the same size.
splFixedArray also implements Iterator which means it encapsulate the list and expose visibility to one element at a time making them far more efficient.
The foreach loop makes a copy of any array passed to it. If you are processing a large amount of data, using it directly with our array can be a performance issue
Also see How big are PHP arrays (and values) really? (Hint: BIG!)
You can try
$it = SplFixedArray::fromArray($items);
foreach ( $it as $value ) {
// Play with big array
}
Speed
Here is a simple benchmark
set_time_limit(0);
echo "<pre>";
$total = 10000;
$item = array("milk","butter","bread");
$items = array();
// Generating Random Data
for($i = 0; $i < $total; $i ++) {
$att = array('id' => $i);
$items[] = array('#attributes' => $att,'item' => $item[$i % 3],'price' => mt_rand(100, 5000) / 100);
}
// Pure array no copy
function m1($array) {
foreach ( $array as $k => $v ) {
isset($v['#attributes']) and $array[$k]['id'] = $v['#attributes']['id'];
unset($array[$k]['#attributes']);
}
return $array;
}
// Array clean copy
function m2($array) {
$items = array();
foreach ( $array as $k => $v ) {
isset($v['#attributes']) and $items[$k]['id'] = $v['#attributes']['id'];
$items[$k]['item'] = $v['item'];
$items[$k]['price'] = $v['price'];
}
return $items;
}
// Array Iterator
function m3($array) {
$it = new ArrayIterator($array);
$items = array();
foreach ( $it as $k => $v ) {
isset($v['#attributes']) and $items[$k]['id'] = $v['#attributes']['id'];
$items[$k]['item'] = $v['item'];
$items[$k]['price'] = $v['price'];
}
return $items;
}
// SplFixedArray Array
function m4($array) {
$it = SplFixedArray::fromArray($array);
$items = array();
foreach ( $it as $k => $v ) {
isset($v['#attributes']) and $items[$k]['id'] = $v['#attributes']['id'];
$items[$k]['item'] = $v['item'];
$items[$k]['price'] = $v['price'];
}
return $items;
}
// Array Map
function m5($array) {
$items = array_map(function ($v) {
isset($v['#attributes']) and $v['id'] = $v['#attributes']['id'];
unset($v['#attributes']);
return $v;
}, $array);
return $items;
}
// Array Walk
function m6($array) {
array_walk($array, function (&$v, $k) {
isset($v['#attributes']) and $v['id'] = $v['#attributes']['id'];
unset($v['#attributes']);
return $v;
});
return $array;
}
$result = array('m1' => 0,'m2' => 0,'m3' => 0,'m4' => 0,'m5' => 0,'m6' => 0);
for($i = 0; $i < 1; ++ $i) {
foreach ( array_keys($result) as $key ) {
$alpha = microtime(true);
$key($items);
$result[$key] += microtime(true) - $alpha;
}
}
echo '<pre>';
echo "Single Run\n";
print_r($result);
echo '</pre>';
$result = array('m1' => 0,'m2' => 0,'m3' => 0,'m4' => 0,'m5' => 0,'m6' => 0);
for($i = 0; $i < 2; ++ $i) {
foreach ( array_keys($result) as $key ) {
$alpha = microtime(true);
$key($items);
$result[$key] += microtime(true) - $alpha;
}
}
echo '<pre>';
echo "Dual Run\n";
print_r($result);
echo '</pre>';
It has a very Interesting results
PHP 5.3.10
Single Run
Array
(
[m1] => 0.029280185699463 <--------------- fastest
[m2] => 0.038463115692139
[m3] => 0.049274921417236
[m4] => 0.03856086730957
[m5] => 0.032699823379517
[m6] => 0.032186985015869
)
Dual Run
Array
(
[m1] => 0.068470001220703
[m2] => 0.077174663543701
[m3] => 0.085768938064575
[m4] => 0.07695198059082
[m5] => 0.073209047317505
[m6] => 0.065080165863037 <--------------- Fastest after in 2 loops
)
PHP 5.4.1
Single Run
Array
(
[m1] => 0.029529094696045
[m2] => 0.035377979278564
[m3] => 0.03830099105835
[m4] => 0.034613132476807
[m5] => 0.031363010406494
[m6] => 0.028403043746948 <---------- fastest
)
Dual Run
Array
(
[m1] => 0.072367191314697
[m2] => 0.071731090545654
[m3] => 0.078131914138794
[m4] => 0.075049877166748
[m5] => 0.065959930419922
[m6] => 0.060923099517822 <---------- Fastest
)

That looks like it's coming from XML, so i would add that it's possible for #attributes to have more than just ID in it.. but assuming that won't happen you could try using a foreach instead, though I'm not sure about speed gains.
There may be an impact because you are modifying the same array you are looping (I can't find evidence for this though, so experiment required)
$cleanedArray = array();
foreach($bigArray as $subArray)
{
if(isset($subArray['#attributes']))
{
$subArray['itemid'] = $subArray['#attributes']['id'];
unset($subArray['#attributes']); //Optional
$cleanedArray[] = $subArray;
}
}
Apologies if that ends up slower
Edit: Missing index added

This isn't an answer so much as it is a comparison of the approaches provided:
I used this script to average out the times the algorithms took:
<?php
//base data
$attrib1 = array('id'=>'101');
$item1 = array('#attributes'=>$attrib1, 'item'=>'milk', 'price'=>'3.50');
$attrib2 = array('id'=>'102');
$item2 = array('#attributes'=>$attrib2, 'item'=>'butter', 'price'=>'2.45');
$attrib3 = array('id'=>'103');
$item3 = array('#attributes'=>$attrib3, 'item'=>'bread', 'price'=>'1.19');
$results = array('test1'=>array(),'test2'=>array(),'test3'=>array());
//set trials
$trials=1000;
//test 1
for($count=0;$count<$trials;$count++){
unset($items);
$items = array($item1, $item2, $item3);
$timer1=microtime();
$i=0;
while(isset($items[$i]['#attributes']['id'])) {
$items[$i]['itemid'] = $items[$i]['#attributes']['id'];
$i++;
}
$timer1=microtime()-$timer1;
$results['test1'][$count]=$timer1;
}
//test 2
for($count=0;$count<$trials;$count++){
unset($items);
unset($cleanedArray);
$items = array($item1, $item2, $item3);
$cleanedArray = array();
$timer2=microtime();
foreach($items as $subArray)
{
if(isset($subArray['#attributes']))
{
unset($subArray['#attributes']);
$cleanedArray[] = $subArray;
}
}
$timer2=microtime()-$timer2;
$results['test2'][$count]=$timer2;
}
//test 3
for($count=0;$count<$trials;$count++){
unset($items);
unset($it);
$items = array($item1, $item2, $item3);
$it = SplFixedArray::fromArray($items);
$timer3=microtime();
foreach($it as $subArray)
{
if(isset($subArray['#attributes']))
{
unset($subArray['#attributes']);
$cleanedArray[] = $subArray;
}
}
$timer3=microtime()-$timer3;
$results['test3'][$count]=$timer3;
}
//results
$factor=pow(10,-6);
echo "Test 1 averaged " . round(array_sum($results['test1']) / count($results['test1'])/$factor,1) . " µs, with range: " . round((max($results['test1'])-min($results['test1']))/$factor,1) . " µs - (min: " . (min($results['test1'])/$factor) . ", max: " . (max($results['test1'])/$factor) . ")<br/>";
echo "Test 2 averaged " . round(array_sum($results['test2']) / count($results['test2'])/$factor,1) . " µs, with range: " . round((max($results['test2'])-min($results['test2']))/$factor,1) . " µs - (min: " . (min($results['test2'])/$factor) . ", max: " . (max($results['test2'])/$factor) . ")<br/>";
echo "Test 3 averaged " . round(array_sum($results['test3']) / count($results['test3'])/$factor,1) . " µs, with range: " . round((max($results['test3'])-min($results['test3']))/$factor,1) . " µs - (min: " . (min($results['test3'])/$factor) . ", max: " . (max($results['test3'])/$factor) . ")<br/>";
echo "<pre>";
var_dump($results);
echo "</pre>";
The results here are extremely variable at low numbers of trials, but should become more skewed if the base array is larger and larger numbers of trials are run.

Related

Creating an associative array from one-dimension array

Was not really sure on what question's title should be here...
Sample .csv:
tennis,soccer,sports
car,plane,things
jeans,shirt,things
My final, ideal, outcome should be an array that looks like this:
Array
(
[sports] => Array
(
[0] => tennis
[1] => soccer
)
[things] => Array
(
[0] => car
[1] => plane
[2] => jeans
[3] => shirt
)
)
Here is my most recent attempt to achieve the outcome above (after many tries):
<?php
$f_name = 'test.csv';
// Stores all csv data
$csv_data = array_map('str_getcsv', file($f_name));
$c = count($csv_data);
$tmp = array();
$data_for_email = array();
for ($i = 0; $i < $c; $i++) {
// Remove last element and make it a key
$le = array_pop($csv_data[$i]);
$tmp[$le] = $csv_data[$i];
$data_for_email = array_merge_recursive($data_for_email, $tmp); // MEMORY ERROR
}
print_r($data_for_email);
?>
This is what I get as a result:
Array
(
[sports] => Array
(
[0] => tennis
[1] => soccer
[2] => tennis
[3] => soccer
[4] => tennis
[5] => soccer
)
[things] => Array
(
[0] => car
[1] => plane
[2] => jeans
[3] => shirt
)
)
As you can see, I get duplicates of .csv's line 1 in [sports] array.
More detailed description of my requirement:
Each line has 3 fields.
3rd field becomes a key in a new associative array.
Two remaining fields (1st and 2nd) become values for that key.
Because multiple lines may (and do) contain identical 3rd field (while combination of 1st and 2nd fields are always different), I need to then merge all these duplicate keys' values into 1.
P.S. I could parse that array (to remove duplicate values) afterwards, but the real .csv file is large and it becomes too slow to process it, and I receive the following error at the line which I marked with // MEMORY ERROR:
Fatal Error: Allowed Memory Size of 134217728 Bytes Exhausted
I tried increasing the memory limit but I'd prefer to avoid this if possible.
Should be a little easier. No need for array_merge_recursive:
foreach($csv_data as $row) {
$key = array_pop($row);
if(!isset($data_for_email[$key])) {
$data_for_email[$key] = [];
}
$data_for_email[$key] = array_merge($data_for_email[$key], $row);
}
More memory efficient would be:
Not reading the whole file in memory. fgetcsv reads one line at a time
Avoiding a recursive merge
Code:
$handle = fopen($f_name, 'r');
if (!$handle) {
// Your error-handling
die("Couldn't open file");
}
$data_for_email = array();
while($csvLine = fgetcsv($handle)) {
// Remove last element and make it a key
$le = array_pop($csvLine);
if (isset($data_for_email[$le])) {
$data_for_email[$le] = array_merge($data_for_email[$le], $csvLine);
} else {
$data_for_email[$le] = $csvLine;
}
}
fclose($handle);
You just need to initialize $tmp in every loop which will resolve your problem. Check below code:
for ($i = 0; $i < $c; $i++) {
// Remove last element and make it a key
$le = array_pop($csv_data[$i]);
$tmp = []; //Reset here
$tmp[$le] = $csv_data[$i];
$data_for_email = array_merge_recursive($data_for_email, $tmp); // MEMORY ERROR
}
Hope it helps you.
Use the name for the key to get a unique list. It is cheaper than merge if there is a lot of data.:
$handle = fopen('test.csv', 'r');
$res = [];
while ($data = fgetcsv($handle)) {
list($first, $second, $type) = $data;
$res[$type] = ($res[$type] ?? []);
array_map(function($e)use(&$res, $type) {
$res[$type][$e] = $e;
}, [$first, $second]);
}
output:
Array
(
[sports] => Array
(
[tennis] => tennis
[soccer] => soccer
)
[things] => Array
(
[car] => car
[plane] => plane
[jeans] => jeans
[shirt] => shirt
)
)
i made something, too, but now the others were faster. :D
I've made it oop, it doesn't quite come out what you wanted but maybe it helps you further.
I have not come any further now, unfortunately, wanted to show it to you anyway :)
Here is your index.php ( or whatever the file is called. )
<?php
include "Data.php";
$f_name = 'in.csv';
// Stores all csv data
$csv_data = array_map('str_getcsv', file($f_name));
$c = count($csv_data);
$tmp = array();
$data_for_email = array();
foreach ($csv_data as $data){
$key = array_pop($data);
array_push($data_for_email,new Data($data,$key));
}
foreach ($data_for_email as $data){
array_push($tmp,$data->getValue());
}
foreach ($tmp as $value){
print_r($value);
echo "<br>";
}
and here the class Data:
<?php
class Data
{
private $value = [];
public function __construct($data, $key)
{
$this->value[$key]=$data;
}
/**
* #return array
*/
public function getValue()
{
return $this->value;
}
}
as output you bekome something like that:
Array ( [sports] => Array ( [0] => tennis [1] => soccer ) )
Array ( [things] => Array ( [0] => car [1] => plane ) )
Array ( [things] => Array ( [0] => jeans [1] => shirt ) )
ps:
surely there is another function that summarizes the same keys, but somehow i don't find anything now...
I hope it helps :)

Add up the values of multiple occurrences of multiple strings in a multidimensional array in PHP

I've got a multidimensional array.
I need a way to tally up the total value when both the 1st and second strings in the array occur multiple times.
So for instance :
Gold Metallic = 22
Black Toscano = 26
etc...
Any ideas?
[0] => Array
(
[0] => Array
(
[0] => Black
[1] => Toscano
[2] => 14
)
[1] => Array
(
[0] => Gold
[1] => Metallic
[2] => 10
)
)
[1] => Array
(
[0] => Array
(
[0] => Gold
[1] => Metallic
[2] => 12
)
[1] => Array
(
[0] => Black
[1] => Toscano
[2] => 12
)
)
This just solves the problem for your data structure so you have to make sure that, in practice, every two items you will get a number. Hope you can learn something from this :)
$products = array(
array(
array("Black", "Toscano", 14),
array("Gold", "Metallic", 10)
),
array(
array("Black", "Toscano", 12),
array("Gold", "Metallic", 12)
),
);
$accumulated = array();
$key = "";
$callback = function($item, $index) use(&$key, &$accumulated) {
if($index != 2) {
$key .= $item;
} else {
if(!array_key_exists($key, $accumulated)) {
$accumulated[$key] = 0;
}
$accumulated[$key] += $item;
$key = "";
}
};
array_walk_recursive($products, $callback);
var_dump($accumulated);
Should be a simple case of looping over the data and storing an array of sums. This is one possibility using a hash with keys as the pairs concatenated with a separator sentinel value.
$separator = "||"; //take care to choose something that doesn't pop up in your data here
//$data = example data;
$pairs = array();
foreach ($data as $val) {
foreach ($val as $pair) {
$str = $pair[0] . $separator . $pair[1];
if (array_key_exists($str, $pairs))
$pairs[$str] += $pair[2];
else
$pairs[$str] = $pair[2];
}
}
print_r($pairs);
output:
["Black||Toscano"] => 26,
["Gold||Metallic"] => 22
The data can be easily retrieved at this point
foreach ($pairs as $str => $sum) {
$str = explode($separator, $str);
echo $str[0] . ", " . $str[1] . ": " . $sum;
}

Iterating a Multidimensional Array

I'm having trouble correctly iterating a multi-dimension array I am trying to retrieve the values for each well..value.
My Issue is I seem to have an array within an array which has an array for each key/pair value, I'm unsure how to loop through these and add the values to the database for each array.
Eg, if I have one form on my page the array return is below and further below that is what is returned with two forms etc
Array
(
[0] => Array
(
[0] => Array
(
[name] => sl_propid
[value] => 21
)
[1] => Array
(
[name] => sl_date
[value] => 04/01/2014
)
[2] => Array
(
[name] => sl_ref
[value] => Form1
)
[3] => Array
(
[name] => sl_nom_id
[value] => 12
)
[4] => Array
(
[name] => sl_desc
[value] => Form1
)
[5] => Array
(
[name] => sl_vat
[value] => 60
)
[6] => Array
(
[name] => sl_net
[value] => 999
)
)
)
My question is how do I iterate through the returned array no matter it's size and pull back each value?
I have tried nesting foreach loops, which did give me results, but only for one key/value pair which leads me to believe I'm doing the looping wrong, I can retrieve the values if I statically access them, which is of course no use normally.
foreach ($result as $array) {
print_r($array);
}
the above foreach returns the above arrays, adding another foreach removes the out "container" array but adding another foreach loop, returns only one key/value pair, which sort makes sense because the first index is an array, too, hope I haven't confused everyone else as much as already have myself D:.
Thank you for reading
Any help appreciated.
EDIT Using the below array walk recursive I get the output
$result = $this->input->post();
function test_print($item, $key)
{
echo "$key holds $item\n";
//$this->SalesLedgerModel->addInvoiceToLedger($key, $key, $key, $key, $key, $key, $key);
}
array_walk_recursive($result, 'test_print');
}
Which is almost what I want but how do I take each individual value and add it to my ModelFunction (to actually input the data to DB)
The function takes 7 parameters but I am unsure how to make sure the right info goes to the correct parameter
$this->SalesLedgerModel->addInvoiceToLedger($propid, $date, $ref, $nomid, $desc, $vat, $net);
My Controller function
function addInvoiceToLedger(){
$this->load->model('SalesLedgerModel');
// $propid = $this->input->post('propid');
// $date = $this->input->post('date');
// $ref = $this->input->post('ref');
// $nomid = $this->input->post('id');
// $desc = $this->input->post('desc');
// $vat = $this->input->post('vat');
// $net = $this->input->post('sl_net');
$results = $this->input->post();
//var_dump($results);
$size1 = sizeof($results)-1;
for($i=0; $i<=$size1; $i++)
{
$size2 = sizeof($results[$i])-1;
for($j=0; $j<=$size2; $j++)
{
$name = $results[$i][$j]['name'];
$value = $results[$i][$j]['value'];
echo $value . "\n" ;
$this->SalesLedgerModel->addInvoiceToLedger($value, $value, $value, $value, $value, $value, $value);
}
}
My Model function
function addInvoiceToLedger($propid, $date, $ref, $nomid, $desc, $vat, $net){
$data = array('sl_prop_id' => $propid, 'sl_date' => $date,
'sl_ref' => $ref, 'sl_nominal_sub' => $nomid, 'sl_invoice_desc' => $desc, 'sl_vat' => $vat, 'sl_amount' => $net);
$this->db->insert('salesledger', $data);
}
You can either write some recursive code to step through the array and call itself again if an element turns into an array, or write a very simple function and call it via array walk recursive which will then let you do whatever you like with the value:
<?php
$sweet = array('a' => 'apple', 'b' => 'banana');
$fruits = array('sweet' => $sweet, 'sour' => 'lemon');
function test_print($item, $key)
{
echo "$key holds $item\n";
}
array_walk_recursive($fruits, 'test_print');
?>
Output:
a holds apple
b holds banana
sour holds lemon
Try this. It'll be much faster. Since 3 foreach loops is much costlier than 2 for loops (for loops are faster than foreach loops) -
$size1 = sizeof($results)-1;
if($size1 > 0)
{
for($i=0; $i<=$size1; $i++)
{
$size2 = sizeof($results[$i])-1;
if($size2 > 0)
{
for($j=0; $j<=$size2; $j++)
{
$name = $results[$i][$j]['name'];
$value = $results[$i][$j]['value'];
$insert = $this->your_model->insert($name, $value);
}
}
}
}
foreach ($result as $array) {
foreach($array as $arr){
foreach($arr as $a){
echo $a[value];
}
}
}

Getting multi dimensional array to create new arrays based on index value

I am having a terrible time getting this to work I have been struggling with it for a couple hours now. Can someone please help me? I have included a fiddle.
I believe my problem is in this string:
$$salesAndOwner[$i]["$salesAndOwner[$i]".$l] = $salesAndOwner[$i.$l][$param] = $values[$l];
Basically I have the following multidimensional array:
[sales] => Array
(
[FirstName] => Array
(
[0] => salesFirst1
[1] => salesFirst2
)
[LastName] => Array
(
[0] => salesLast1
[1] => salesLast2
)
)
[decisionmaker] => Array
(
[FirstName] => Array
(
[0] => dmFirst1
[1] => dmFirst2
)
[LastName] => Array
(
[0] => dmLast1
[1] => dmLast2
)
)
)
I need this to be reorganized like I did with the following array:
Array
(
[additionallocations0] => Array
(
[Address] => Address1
[State] => State1
)
[additionallocations1] => Array
(
[Address] => Address2
[State] => State2
)
)
Here is the original:
Array
(
[additionallocations] => Array
(
[Address] => Array
(
[0] => Address1
[1] => Address2
)
[State] => Array
(
[0] => State1
[1] => State2
)
)
This is how I reorganize the above array:
if(isset($_POST['additionallocations'])) {
$qty = count($_POST['additionallocations']["Address"]);
for ($l=0; $l<$qty; $l++)
{
foreach($_POST['additionallocations'] as $param => $values)
{
$additional['additionallocations'.$l][$param] = $values[$l];
}
}
And this is what I am using for the sales and decisionmaker array. If you notice I have an array that contains sales and decisionmaker in it. I would like to be able to sort any future arrays by just adding its primary arrays name. I feel I am close to solving my problem but I can not get it to produce right.
$salesAndOwner = array(0 => "sales", 1 => "decisionmaker");
for($i = 0; $i < 2; $i++){
$qty = count($_POST[$salesAndOwner[$i]]["FirstName"]);
for ($l=0; $l<$qty; $l++)
{
foreach($_POST[$salesAndOwner[$i]] as $param => $values)
{
$$salesAndOwner[$i]["$salesAndOwner[$i]".$l] = $salesAndOwner[$i.$l][$param] = $values[$l];
}
}
}
In the above code I hard coded 'sales' into the variable I need it to make a variable name dynamically that contains the sales0 decisionmaker0 and sales1 decisionmaker1 arrays so $sales and $decisionmaker
I hope this makes sense please let me know if you need any more info
Let's break it down. Using friendly variable names and spacing will make your code a lot easier to read.
Remember. The syntax is for you to read and understand easily. (Not even just you, but maybe future developers after you!)
So you have an array of groups. Each group contains an array of attributes. Each attribute row contains a number of attribute values.
PHP's foreach is a fantastic way to iterate through this, because you will need to iterate through (and use) the index names of the arrays:
<?php
$new_array = array();
// For each group:
foreach($original_array as $group_name => $group) {
// $group_name = e.g 'sales'
// For each attribute in this group:
foreach($group as $attribute_name => $attributes) {
// $attribute_name = e.g. 'FirstName'
// For each attribute value in this attribute set.
foreach($attributes as $row_number => $attribute) {
// E.g. sales0
$row_key = $group_name . $row_number;
// if this is the first iteration, we need to declare the array.
if(!isset($new_array[$row_key])) {
$new_array[$row_key] = array();
}
// e.g. Array[sales0][FirstName]
$new_array[$row_key][$attribute_name] = $attribute;
}
}
}
?>
With this said, this sort of conversion may cause unexpected results without sufficient validation.
Make sure the input array is valid (e.g. each attribute group has the same number of rows per group) and you should be okay.
$salesAndOwner = array("sales", "decisionmaker");
$result = array();
foreach ($salesAndOwner as $key) {
$group = $_POST[$key];
$subkeys = array_keys($group);
$first_key = $subkeys[0];
foreach ($group[$first_key] as $i => $val) {
$prefix = $key . $i;
foreach ($subkeys as $subkey) {
if (!isset($result[$prefix])) {
$result[$prefix] = array();
}
$result[$prefix][$subkey] = $val;
}
}
}
DEMO
Try
$result =array();
foreach($arr as $key=>$val){
foreach($val as $key1=>$val1){
foreach($val1 as $key2=>$val2){
$result[$key.$key2][$key1] = $val2;
}
}
}
See demo here

Group array by keys value

I have searched around and I am at my wits end so I will make this easy. This is what I have in a print_r:
Array
(
[0] => Array
(
[name] => client interaction
[y] => 2.7
)
[1] => Array
(
[name] => client interaction
[y] => 0.1
)
[2] => Array
(
[name] => project planning
[y] => 0.1
)
[3] => Array
(
[name] => client interaction
[y] => 5.9
)
)
And this is what I want it to be:
Array
(
[0] => Array
(
[name] => client interaction
[y] => 8.7
)
[1] => Array
(
[name] => project planning
[y] => 0.1
)
)
Is it absolutely necessary that your desired array use numeric indeces? If I were to do this I would do it this way (not the same as your desired array though)
$newArray = array();
foreach($array as $item)
{
if(!isset($newArray[$item["name"]]))
$newArray[$item["name"]] = 0;
$newArray[$item["name"]] += $item["y"];
}
This will give you an array of this structure:
Array
(
[client interaction] => 8.7
[project planning] => 0.1
)
To get the keys back you simply use the second form of the foreach loop
foreach($newArray as $name => $y)
$name will contain the name and $y the y in your original array.
$hash = array();
foreach ($sourceArray as $key=>$value) {
$y = 0;
if (isset($hash{$value{'name'}})) {
$y = $hash{$value{'name'}};
}
$hash{$value{'name'}} = $y + $value{'y'};
}
$result = array();
foreach ($hash as $key => $value) {
$result[] = array( 'name' => $key, 'value' => $value );
}
print_r($result);
The last loop is just to get $hash into the exact format you specified.
Explanation:
$hash
Is a temporary structure used to compute the sums for each unique name.
foreach ($sourceArray as $key=>$value) {
This goes through your original array ($sourceArray) and pulls out each element.
$y = 0;
Initializes a variable to store the current sum that belongs with that name.
if (isset($hash{$value{'name'}})) {
Checks to see if a value has already been stored in $hash for the given name.
$y = $hash{$value{'name'}};
}
Sets $y to the previously calculated sum for the given name, if there was one.
$hash{$value{'name'}} = $y + $value{'y'};
}
Stores the sum for the given name into our temporary structure $hash.
$result = array();
foreach ($hash as $key => $value) {
$result[] = array( 'name' => $key, 'value' => $value );
}
converts $hash to the format you desired.
The empy []'s in $result[] = ... add the right hand side of the expression to the end of the $result array.
$mixed = array(); // Should contain your array shown above
$groups = array();
$newArray = array(); // Will contain your new array
$counter = 0;
foreach( $mixed as $mix )
{
if ( isset($groups[$mix['name']]) )
{
$newArray[$groups[$mix['name']]]['y'] += $mix['y'];
}
else
{
$groups[$mix['name']] = $counter;
$newArray[] = $mix;
$counter++;
}
}
http://codepad.org/EjdHxgvt

Categories