Counting an eliminating duplicate associative values in an array - php

I have the following issue, I have an array with the name $data
Within this array I have something like
[6] => Array
(
[code] => 642
[total] => 1708
)
[7] => Array
(
[code] => 642
[total] => 53
)
[8] => Array
(
[code] => 642
[total] => 1421
)
In some elements the code value is the same, now what I want to do is merge all the elements with the same code value together, and adding the totals together. I tried doing this in a foreach loop, but does not seem to work.
I do something like this
$old_lc = null;
$old_lcv = 0;
$count = 0;
$dd = null;
foreach($data as $d){
if($d['code'] == $old_lc){
$d['total'] = $d['total'] + $old_lcv;
$count--;
$dd[$count]['code'] = $d['code'];
$dd[$count]['total'] = $d['total'];
}else{
$dd[$count]['code'] = $d['code'];
$dd[$count]['total'] = $d['total'];
$count++;
}
$old_lc = $d['code'];
$old_lcv = $d['total'];
}
$data = $dd;
But this does not seem to work. Also I need the $data array to keep the keys, and should remain in the same format

$result = array();
foreach($ary as $elem) {
$code = $elem['code'];
$total = $elem['total'];
if(!isset($result[$code]))
$result[$code] = 0;
$result[$code] += $total;
}

This code translates the above array into an array of code => total.
$out = array();
foreach ($data as $k => $v) {
$out[$v['code']] += $v['total'];
}
It is worth noting that on certain settings this will generate a warning about undefined indexes. If this bothers you, you can use this alternate version:
$out = array();
foreach ($data as $k => $v) {
if (array_key_exists($v['code'], $out)) {
$out[$v['code']] += $v['total'];
} else {
$out[$v['code']] = $v['code'];
}
}
This turns it back into something like the original, if that's what you want:
$output = array();
foreach ($out as $code => $total) {
$output[] = array('code' => $code, 'total' => $total);
}
Note: the original keys of $data aren't maintained but it wasn't stated that this was a requirement. If it is, it needs to be specified how to reconstruct multiple elements that have the same code.

[6] => Array
(
[code] => 642
[total] => 1708
)
[7] => Array
(
[code] => 642
[total] => 53
)
[8] => Array
(
[code] => 642
[total] => 1421
)
$data_rec = array();
$data = array();
foreach($data_rec as $key=>$rec)
{
$data[$key]+= $rec[$key];
}
print_r($data);

Related

Dynamic associative Array - list, count, sum, min, max

I've got an array with about 40 keys. I'd like to have a small function that returns a summary array.
Right now I've got the following that works:
foreach ($all_data as $value){
$new_array[ $value['location'] ][ $value['manufacturer'] ][ $value['model'] ] += 1;
}
This returns an array with everything I need. However, the location, manufacturer and model could be changed up for a bunch of other values.
what I am trying to do is have something simple as:
$new_array = summarize($all_data,array('location','manufacturer','model','count'),array('list','list','list','count') );}
where this summarize function would build the call. I think I just need a bit of help on how to get it to run the string as code for this array. Otherwise I get
$current_selection = "[ $row_item['location'] ][ $row_item['manufacturer'] ][ $row_item['model'] ]"
$return_array{$current_selection} += 1;
Where the end goal is to have a function like:
function summarize($data_array, $fields_array, $process_array){
//data_array = associative multi-dimensional data array
//fields = values to pull from the data_array
//process = array specifying whether to list, sum, count, average, max, min
$return_array = array();
$current_selection = "";
foreach($fields_array as $field){
$current_selection .= '[ $row_item[\'' . $field . '\'] ]';
}
foreach ($data_array as $row_item){
//dynamic = DOES NOT WORK
$return_array[$current_selection] += 1;//eval? create function? abstract?
//another attempt
${'return_array' . $current_selection} += 1;
//Manual = Does work
//$return_array[ $row_item['location'] ][ $row_item['manufacturer'] ][ $row_item['model'] ] += 1;
}
}
Thanks for any help on how to do an indirect reference.
JC
RESOLUTION
The final version that managed to resolve this looks like the following, thanks to user: check, for getting me on the correct path.
function summarize($data_array, $fields_array, $process_array){
$return_array = array();
$i = 0;
foreach ($data_array as $row){
$ii = 0;
$temp = array();
$temp2 = array();
foreach($fields_array as $key=>$field){
if($process_array[$ii] == 'list') $temp[$ii] = $row[$field];
if($process_array[$ii] == 'count') $temp2[$ii] = 1;
if($process_array[$ii] == 'sum') $temp2[$ii] = $row[$field];
$ii++;
}
$unique = true;
$ii = 0;
foreach($return_array as $row2){
if(array_intersect_key($row2,$temp) == $temp){//$row2 == $temp){
$unique = false;
break;
}
$ii++;
}
if($unique){
$return_array[$i] = $temp;
if(!empty($temp2)) $return_array[$i] = array_merge($temp,$temp2);
$i++;
}else{
if(!empty($temp2)){
foreach($temp2 as $key => $value){
if($process_array[$key] == 'sum') $temp2[$key] = $return_array[$ii][$key] + $value;
if($process_array[$key] == 'count') $temp2[$key] = $return_array[$ii][$key] + 1;
if($process_array[$key] == 'max') $temp2[$key] = ($return_array[$ii][$key] < $value) ? $value : $return_array[$ii][$key];
if($process_array[$key] == 'min') $temp2[$key] = ($return_array[$ii][$key] > $value) ? $value : $return_array[$ii][$key];
//TODO:(JC) 'average' - need to create a count field if not present (or always despite and assume overhead of extra computations).
// - then just calculate the 'sum' and divide by the counter as a last step before returning the array.
}
$return_array[$ii] = array_merge($temp,$temp2);
}
}
}
print_r($return_array);
return $return_array;
}
Which gives the following result:
/*
CALL: summarize($data,array('location','manufacturer','model','model','volume','colourvolume'),array('list','list','list','count','sum','sum') );
[0] = location
[1] = manufacturer
[2] = model
[3] = model count
[4] = mono volume sum
[5] = colour volume sum
*/
Array
(
[0] => Array
(
[0] =>
[1] => HP
[2] => LaserJet 4000
[3] => 3
[4] => 3000
[5] => 0
)
...
[17] => Array
(
[0] => Room 114
[1] => CANON
[2] => iR3235
[3] => 1
[4] => 4012
[5] => 0
)
[18] => Array
(
[0] => Room 115
[1] => LEXMARK
[2] => T652
[3] => 1
[4] => 20
[5] => 0
)
)
alternatively, if I assume that's $field_array contains sequentially key fields from root to sub key, you can loop your $field_array within $data_array loop
function summarize($data_array, $fields_array, $process_array){
$return_array = array();
foreach ($data_array as $row){
$temp = array();
foreach($fields_array as $key=>$field){
$temp = $key==0?$row[$field]:$temp[$field];
}
if(!empty($temp)) $return_array[] = $temp;
}
return $return_array;
}
and this is my array, will summarize with these function
$array = array(
array("multi"=>array("dimensional"=>array("array"=>"foo1"))),
array("multi"=>array("dimensional"=>array("array"=>"foo2"))),
array("multi"=>array("dimensional"=>array("array"=>"foo3"))),
array("multi"=>array("dimensional"=>array("array"=>"foo4"))),
array("multi"=>array("dimensional"=>array("array"=>"foo5"))),
array("multi"=>array("dimensional"=>array("array"=>"foo6"))),
array("multi"=>array("dimensional"=>array("array"=>"foo7"))),
array("multi"=>array("dimensional"=>array("array"=>"foo8"))),
array("multi"=>array("dimensional"=>array("array"=>"foo9")))
);
print_r(summarize($array,array("multi","dimensional","array"),NULL));
Ouput
Array ( [0] => foo1 [1] => foo2 [2] => foo3 [3] => foo4 [4] => foo5 [5] => foo6 [6] => foo7 [7] => foo8 [8] => foo9 )

PHP Count Duplicate Total Link

how can i count the total duplicate link in the array?
its similar question here: count of duplicate elements in an array in php
but im not sure how to implement the code on my case.
my server PHP version 5.4
Array
(
[0] => Array
(
[link] => http://myexample.com
[total] => 3
)
[1] => Array
(
[link] => http://myexampledomain.com
[total] => 2
)
[2] => Array
(
[link] => http://myexample.com
[total] => 1
)
)
I am expecting the result to be:
http://myexample.com: 4
http://myotherdomain.com: 2
You can simply use
$result = [];
array_walk($arr, function($v, $k)use(&$result) {
if (isset($result[$v['link']])) {
$result[$v['link']] += $v['total'];
}else{
$result[$v['link']] = $v['total'];
}
});
print_r($result);
Demo
Try below code:
<?php
$array = array(array("link" => "http://myexample.com", "total" => 3), array("link" => "http://myexampledomain.com", "total" => 2), array("link" => "http://myexample.com", "total" => 1));
$res = array();
foreach ($array as $vals) {
if (array_key_exists($vals['link'], $res)) {
$res[$vals['link']]+=$vals['total'];
} else {
$res[$vals['link']]=$vals['total'];
}
}
print_r($res);
?>
You can use this simple logic :
$tempArray = array();
foreach ($array as $value) {
if (!array_key_exists($value['link'],$tempArray) {
$tempArray[$value['link']] = 1;
} else {
$tempArray[$value['link']] = $tempArray['link'] + 1;
}
}
print_r($tempArray);

Associative index array to associative associative array

Problem
I have an array which is returned from PHPExcel via the following
<?php
require_once 'PHPExcel/Classes/PHPExcel/IOFactory.php';
$excelFile = "excel/1240.xlsx";
$objReader = PHPExcel_IOFactory::createReader('Excel2007');
$objPHPExcel = $objReader->load($excelFile);
foreach ($objPHPExcel->getWorksheetIterator() as $worksheet) {
$arrayData[$worksheet->getTitle()] = $worksheet->toArray();
}
print_r($arrayData);
?>
This returns:
Array
(
[Films] => Array
(
[0] => Array
(
[0] => Name
[1] => Rating
)
[1] => Array
(
[0] => Shawshank Redemption
[1] => 39
)
[2] => Array
(
[0] => A Clockwork Orange
[1] => 39
)
)
[Games] => Array
(
[0] => Array
(
[0] => Name
[1] => Rating
)
[1] => Array
(
[0] => F.E.A.R
[1] => 4
)
[2] => Array
(
[0] => World of Warcraft
[1] => 6
)
)
)
What I would like to have is
Array
(
[Films] => Array
(
[0] => Array
(
[Name] => Shawshank Redemption
[Rating] => 39
)
[1] => Array
(
[Name] => A Clockwork Orange
[Rating] => 39
)
)
[Games] => Array
(
[0] => Array
(
[Name] => F.E.A.R
[Rating] => 4
)
[1] => Array
(
[Name] => World of Warcraft
[Rating] => 6
)
)
)
The arrays names (Films, Games) are taken from the sheet name so the amount can be variable. The first sub-array will always contain the key names e.g. Films[0] and Games[0] and the amount of these can be varible. I (think I) know I will need to do something like below but I'm at a loss.
foreach ($arrayData as $value) {
foreach ($value as $rowKey => $rowValue) {
for ($i=0; $i <count($value) ; $i++) {
# code to add NAME[n] as keys
}
}
}
I have searched extensively here and else where if it is a duplicate I will remove it.
Thanks for any input
Try
$result= array();
foreach($arr as $key=>$value){
$keys = array_slice($value,0,1);
$values = array_slice($value,1);
foreach($values as $val){
$result[$key][] = array_combine($keys[0],$val);
}
}
See demo here
You may use nested array_map calls. Somehow like this:
$result = array_map(
function ($subarr) {
$names = array_shift($subarr);
return array_map(
function ($el) use ($names) {
return array_combine($names, $el);
},
$subarr
);
},
$array
);
Demo
Something like this should work:
$newArray = array();
foreach ($arrayData as $section => $list) {
$newArray[$section] = array();
$count = count($list);
for ($x = 1; $x < $count; $x++) {
$newArray[$section][] = array_combine($list[0], $list[$x]);
}
}
unset($arrayData, $section, $x);
Demo: http://ideone.com/ZmnFMM
Probably a little late answer, but it looks more like your tried solution
//Films,Games // Row Data
foreach ($arrayData as $type => $value)
{
$key1 = $value[0][0]; // Get the Name Key
$key2 = $value[0][1]; // Get the Rating Key
$count = count($value) - 1;
for ($i = 0; $i < $count; $i++)
{
/* Get the values from the i+1 row and put it in the ith row, with a set key */
$arrayData[$type][$i] = array(
$key1 => $value[$i + 1][0],
$key2 => $value[$i + 1][1],
);
}
unset($arrayData[$type][$count]); // Unset the last row since this will be repeated data
}
I think this will do:
foreach($arrayData as $key => $array){
for($i=0; $i<count($array[0]); $i++){
$indexes[$i]=$array[0][$i];
}
for($i=1; $i<count($array); $i++){
for($j=0; $j<count($array[$i]); $j++){
$temp_array[$indexes[$j]]=$array[$i][$j];
}
$new_array[$key][]=$temp_array;
}
}
print_r($new_array);
EDIT: tested and updated the code, works...

Calculating average value for array with PHP?

My head is exploding with this. I can't seem to create a working solution.
I have a file in this format:
99895|35378|0.01
99895|813|-0.97
99895|771|0.29
442|833|-1.06
442|485|-0.61
442|367|-0.14
442|478|0.77
442|947|-0.07
7977|987|0.76
7977|819|0.37
7977|819|0.36
7977|653|1.16
7977|1653|1.15
I want to calculate average values from third column for each id from the first column.
This seems so easy but I can't get this to work. How do you get averages for any said id from first column?
EDIT:
Some sample code I've written before:
$file = file_get_contents("results.txt");
$file = explode("
", $file);
$howMany = count($file);
for($a = 0;$a<$howMany;$a++)
{
$row = explode("|", $file[$a]);
$id = $row[0];
$howManyAlready = count($bigTable[$id]);
$bigTable[$id][$howManyAlready] = $row[2];
}
I've added the code. So far it gets the results into an array ( with offset corresponding to its id ) But I am having trouble with how to get those results and calculate average for each id and then present it on the screen.
Something like this should definitely work..
<?php
$arr=array();
$arrv=array_filter(file('myfile.txt'),'strlen');
foreach($arrv as $v)
{
array_push($arr,#array_pop(explode('|',$v)));
}
echo $avg = array_sum($arr)/count($arr);
You can try doing this :
$file = file_get_contents("results.txt");
$file = explode("
", $file);
$valuesPerID = Array();
foreach($file as $row)
{
$row_array = explode("|", $row);
$id = $row_array[0];
if(!array_key_exists($id, $valuesPerID))
{
$valuesPerID[$id] = Array();
}
$valuesPerID[$id][] = $row_array[2];
}
Now in the $valuesPerID array, you'll have all your ID as keys, and for each ID, all the values associated with the said ID. They you can easily calculate the average of these values !
You can use array mapping to assign value and id.
For example (assume that you have handled the text):
<?php
$data = array("99895|35378|0.01",
"99895|813|-0.97",
"99895|771|0.29",
"442|833|-1.06",
"442|485|-0.61",
"442|367|-0.14",
"442|478|0.77",
"442|947|-0.07",
"7977|987|0.76",
"7977|819|0.37",
"7977|819|0.36",
"7977|653|1.16",
"7977|1653|1.15");
$bucket = array();
$count = array();
foreach($data as $line) {
list($id, $what_s_this, $number) = explode("|", $line);
$count[$id]++;
$bucket[$id]+= (float)$number;
}
foreach($bucket as $id => $sum) {
echo "id:". $id. ", average". $sum / $count[$id]. "\n";
}
This should put you on the right track.
<?php
$values = array();
foreach (file('file.txt') as $line) {
list($id, $thingymabob, $value) = explode('|', $line);
if ( ! array_key_exists($id, $values)) {
$values[ $id ] = array();
}
array_push($values[ $id ], $value);
}
foreach ($values as $id => $value) {
printf(
"%d has an average of %f\n",
$id,
array_sum($value) / count($value)
);
}
Here some something I've just written.
In my example it takes it from a string.
<?php
$test1 = "";
$test2 = "";
$count1 = 0;
$count2 = 0;
$string = "99895|35378|0.01
99895|813|-0.97
99895|771|0.29
442|833|-1.06
442|485|-0.61
442|367|-0.14
442|478|0.77
442|947|-0.07
7977|987|0.76
7977|819|0.37
7977|819|0.36
7977|653|1.16
7977|1653|1.15";
$d = explode("\n", $string);
foreach ($d as $k => $v)
{
$d2 = explode("|", $v);
if ($d2[0] == '99895'){
$count1++;
$test1 += $d2[2];
}
if ($d2[0] == '442'){
$count2++;
$test2 += $d2[2];
}
}
$result1 = $test1 / $count1;
$result2 = $test2 / $count2;
echo $result1. " <br> ". $result2;
I don't know how well this will work as I don't know if the values are set or not.
If You try below code
<?php
$file_content = array();
$handle = fopen("test.txt", "r");
if ($handle) {
while (($line = fgets($handle)) !== false) {
// process the line read.
$line_ex = explode("|",$line);
array_push($file_content,$line_ex);
}
} else {
// error opening the file.
}
echo "<pre>";
print_r($file_content);
echo "<pre>";
?>
then You will get below output
Array
(
[0] => Array
(
[0] => 99895
[1] => 35378
[2] => 0.01
)
[1] => Array
(
[0] => 99895
[1] => 813
[2] => -0.97
)
[2] => Array
(
[0] => 99895
[1] => 771
[2] => 0.29
)
[3] => Array
(
[0] => 442
[1] => 833
[2] => -1.06
)
[4] => Array
(
[0] => 442
[1] => 485
[2] => -0.61
)
[5] => Array
(
[0] => 442
[1] => 367
[2] => -0.14
)
[6] => Array
(
[0] => 442
[1] => 478
[2] => 0.77
)
[7] => Array
(
[0] => 442
[1] => 947
[2] => -0.07
)
[8] => Array
(
[0] => 7977
[1] => 987
[2] => 0.76
)
[9] => Array
(
[0] => 7977
[1] => 819
[2] => 0.37
)
[10] => Array
(
[0] => 7977
[1] => 819
[2] => 0.36
)
[11] => Array
(
[0] => 7977
[1] => 653
[2] => 1.16
)
[12] => Array
(
[0] => 7977
[1] => 1653
[2] => 1.15
)
)
For determining average value from third column of corresponding first column - I am researching on it. When I will be done I'll put it here.
Try this:
$filename = 'results.txt';
$result = $counter = $values = array();
$file = fopen($filename, 'r') or die("Couldn't open $filename");
while ($line = fgets($file)) {
$content = explode('|', $line);
if (empty($content[0]) or empty($content[2]))
continue;
$values[$content[0]][] = (float) $content[2];
++$counter[$content[0]];
}
foreach ($values as $key => $value) {
$result[$key] = array_sum($value) / $counter[$key];
}
fclose($file);

Compare a multi-dimensional array with a simple array and extract the difference

I've a $_POST that sends an array. And i've a prevoious array with contains a key that could contain or not one of the values from teh $_POST.
For Example:
$_post: Array ( [0] => 13 [1] => 10 [2] => 52)
Previous: Array ( [0] => Array ( [collection_id] => 13 [artwork_id] => 21 )
[1] => Array ( [collection_id] => 11 [artwork_id] => 21 ) )
So i need to check if the $_POST itms already exists on the previuos array ([collection_id] key) and extract the new ones (in this case [1] => 10 [2] => 52) to ve added to the database and also get those which has changed that need to be removed from the database (replaced) by the new values.
This my current code but not working well...
$new_nodes = array();
$i = 0;
foreach($old_nodes as $node){
foreach ($collections as $collection) {
$new = array('collection_id' => $collection, 'artwork_id' => $artwork['id']);
if(array_diff($node, $new)){
if($collection > 0){
array_push($new_nodes, $new);
}
}
else{
unset($old_nodes[$i]);
}
}
$i++;
}
foreach($new_nodes as $node){
for ($i = 0; $i <= count($new_nodes); $i++) {
if(isset($new_nodes[$i])){
if(!array_diff($node, $new_nodes[$i])){
unset($new_nodes[$i]);
}
}
}
}
NOTE: old_nodes is "Previous" and $collections is "$_POST"
Try something like this:
$old_nodes = array();
$new_nodes = array();
$del_nodes = array();
foreach ($collections as $collection) {
array_push($old_nodes, $collection['collection_id']);
}
$new_nodes = array_diff($collections, $old_nodes);
$del_nodes = array_diff($old_nodes, $collections);

Categories