I have arrays like this: array('id'=>value,'id'=>value)
$arrays=array(
[0] => Array ( [3] => 1, [102] => -1, [15] => 1,)
[1] => Array ( [5] => 1, [80] => -1 )
[2] => Array ( [99] => -1, [3] => -1,[5] => 1 )
)
I need to get the total result of a given key. In the above example, if ask for id of 3, the sum is 0, if ask for id of 5, the sum is 2. I can only think of something like this:
foreach($arrays as $array){
foreach( $array as $id=>$v){
if( $id == $asked )
$total = $total + $v;
}
}
Somehow I guess there has to be an efficient way to do the job. I would like to learn. Thanks!
Using array_reduce:
$key = 3;
$sum = array_reduce($arrays, function(&$memo, $item) use($key){
array_key_exists($key, $item) && $memo += $item[$key];
return $memo;
});
foreach($arrays as $array) {
$total += $array[$id];
}
$prec_array=end($arrays);
foreach($arrays as $array){
foreach($array as $id=>$v){
if(array_key_exists($id, $prec_array) )
$total[$id] += $v + $prec_array[$id] ;
$prec_array = $array;
}
}
Related
Array
(
[0] => Array( [0] => Array( [value] => 25 ) )
[1] => Array( [0] => Array( [value] => 75 ) )
[2] => Array( [0] => Array( [value] => 10 ) )
[3] => Array( [0] => Array( [value] => 10 ) )
)
I am working on a custom module in drupal and need to sum up the [value],
However I tried different approaches using array_column, array_sum, but didn't get the solution.
Any help would be appreciated. Thanks.
Code
$contributionDetails = $node->get('field_contributions')->getValue();
foreach ( $contributionDetails as $element ) {
$p = Paragraph::load( $element['target_id'] );
$text[] = $p->field_contribution_percentage->getValue();
}
You could make use of array_map here instead of an accumulator:
$arraySum = array_map(function ($v) {
return reset($v)['value'];
}, $text);
print_r(array_sum($arraySum)); // 120
Edit, as a full example:
$values = [
[['value' => 25]],
[['value' => 75]],
[['value' => 10]],
[['value' => 10]],
];
echo array_sum(array_map(function ($v) {
return reset($v)['value'];
}, $values)); // 120
A couple of loops and an accumulator is one way to achieve this
$tot = 0;
foreach ($array as $a){
foreach ($a as $b){
$tot += $b['value'];
}
}
echo $tot;
Or if you are sure there will always only be one occurance of the inner array.
$tot = 0;
foreach ($array as $a){
$tot += $a[0]['value'];
}
echo $tot;
Or using the code you just posted
$contributionDetails = $node->get('field_contributions')->getValue();
$tot = 0;
foreach ( $contributionDetails as $element ) {
$p = Paragraph::load( $element['target_id'] );
$text[] = $p->field_contribution_percentage->getValue();
$tot += $p->field_contribution_percentage->getValue();
}
echo $tot;
So you have an array containing 2 arrays which have the index 'value', you just need to loop each array using nested foreach and a variable $sum which sum up the value on each iteration.
Try this code:
<?php
$sum = 0;
foreach($array as $value) {
foreach ($value as $v){
$sum += $v['value'];
}
}
echo $sum;
This will output 120
In order to optimize the output I recently ran into a situation where I have to get the all the combinations of array keys inside an array. I looked into several places (including StackOverflow) but could not find the solution since most are related to permutation rather than combination.
Given this input
$input = ['jack' => 11, 'moe' => 12, 'shane' => 12];
Output should be something like this (the order inside an array does not matter).
$output = [
['jack' => 11],
['jack' => 11, 'moe' => 12]
['jack' => 11, 'moe' => 12, 'shane' => 12]
['moe' => 12],
['moe' => 12, 'shane' => 12]
['shane' => 12],
['shane' => 12, 'jack' => 11]
];
I tried this but after third iteration it does not work.
function combination(array $inputs, array $temp, &$collect) {
if (!empty($temp)) {
$collect[] = $temp;
}
for ($i = 0; $i < sizeof($inputs); $i++) {
$inputCopy = $inputs;
$elem = array_splice($inputCopy, $i, 1);
if (count($inputCopy) > 0) {
$temp[array_keys($elem)[0]] = array_values($elem)[0];
combination($inputCopy, $temp, $collect);
} else {
$temp[array_keys($elem)[0]] = array_values($elem)[0];
$collect[] = $temp;
$temp = [];
}
$i++;
}
}
Though I need this in PHP even Python (without using itertools combination), Java, Javascript will work for me.
I have found a way of doing what you want, but definitely, this is not a "fancy" solution. I would suggest you to work a little bit with it to find something better, but at least this gives you the result.
Here you go :
<?php
$baseArray = [
"joe" => 11,
"molly" => 12,
"sam" => 13,
];
function getAllPermutations($array = []) {
if (empty($array)) {
return [];
}
$result = [];
foreach ($array as $key => $value) {
unset($array[$key]);
$subPermutations = getAllPermutations($array);
$result[] = [$key => $value];
foreach ($subPermutations as $sub) {
$result[] = array_merge([$key => $value] , $sub);
}
}
return $result;
}
print_r(getAllPermutations($baseArray));
Output being :
Array
(
[0] => Array
(
[joe] => 11
)
[1] => Array
(
[joe] => 11
[molly] => 12
)
[2] => Array
(
[joe] => 11
[molly] => 12
[sam] => 13
)
[3] => Array
(
[joe] => 11
[sam] => 13
)
[4] => Array
(
[molly] => 12
)
[5] => Array
(
[molly] => 12
[sam] => 13
)
[6] => Array
(
[sam] => 13
)
) }
Hope this helped.
You read about really clever non-recursive algorithm here: PHP: Find every combination of an Array. You can adopt it (mostly copy and paste) to write generator function:
function keyCombinations($array)
{
$keys = array_keys($array);
$num = count($keys);
$total = pow(2, $num);
for ($i = 1; $i < $total; $i++) {
$combination = [];
for ($j = 0; $j < $num; $j++) {
if (pow(2, $j) & $i) {
$key = $keys[$j];
$combination[$key] = $array[$key];
}
}
yield $combination;
}
}
One important point here. In the original article $i initialized with 0, we initialize it with 1 to exclude empty array from the result.
Having this function you can get all combinations:
foreach (keyCombinations($input) as $combination) {
print_r($combination);
}
Here is working demo.
If, in your final combination, you include the empty set, your problem is equivalent to enumerating a binary number of "n" bits. Where "n" is the number of elements in your set.
You need a recursive algorithm like this one:
def comb(initialSet, results=[], currentIndex=0, currentResult=[]):
if currentIndex >= len(initialSet):
results.append( currentResult[:] )
else:
currentResult.append( initialSet[currentIndex] )
comb(initialSet, results, currentIndex + 1, currentResult)
currentResult.pop()
comb(initialSet, results, currentIndex + 1, currentResult)
return results
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 )
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);
I need to recursively reverse a HUGE array that has many levels of sub arrays, and I need to preserve all of the keys (which some are int keys, and some are string keys), can someone please help me? Perhaps an example using array_reverse somehow? Also, is using array_reverse the only/best method of doing this?
Thanks :)
Try this:
function array_reverse_recursive($arr) {
foreach ($arr as $key => $val) {
if (is_array($val))
$arr[$key] = array_reverse_recursive($val);
}
return array_reverse($arr);
}
Recursively:
<?php
$a = array(1,3,5,7,9);
print_r($a);
function rev($a) {
if (count($a) == 1)
return $a;
return array_merge(rev(array_slice($a, 1, count($a) - 1)), array_slice($a, 0, 1));
}
$a = rev($a);
print_r($a);
?>
output:
Array
(
[0] => 1
[1] => 3
[2] => 5
[3] => 7
[4] => 9
)
Array
(
[0] => 9
[1] => 7
[2] => 5
[3] => 3
[4] => 1
)
Reversing a HUGE php array in situ (but not recursively):
function arrayReverse(&$arr){
if (!is_array($arr) || empty($arr)) {
return;
}
$rev = array();
while ( false !== ( $val = end($arr) ) ){
$rev[ key($arr) ] = $val;
unset( $arr[ key($arr) ] );
}
$arr = $rev;
}
//usage
$test = array(5, 'c'=>100, 10, 15, 20);
arrayReverse($test);
var_export($test);
// result: array ( 3 => 20, 2 => 15, 1 => 10, 'c' => 100, 0 => 5, )