output of php array in a particular format - php

am trying to get output of following array in one format. its not getting
<?php
$distance_covered = array( '1_JAN_2017' => array('DRIVER_1' => array(2, 5, 3),'DRIVER_2' => array(3, 2, 6, 9)),
'2_JAN_2017' => array('DRIVER_1' => array(3, 9), 'DRIVER_3' => array(1, 4, 8)),
'3_JAN_2017' => array('DRIVER_4' => array(9), 'DRIVER_1' => array(2, 7, 5, 2)),
'4_JAN_2017' => array('DRIVER_1' => array(5, 3, 3, 2), 'DRIVER_4' => array(4, 9, 8, 5)),
'5_JAN_2017' => array('DRIVER_2' => array(8, 5), 'DRIVER_5' => array(3, 9, 7)),
'6_JAN_2017' => array('DRIVER_5' => array(2, 1, 7, 5), 'DRIVER_4' => array(1, 9, 6)),
'7_JAN_2017' => array('DRIVER_4' => array(5, 2, 9), 'DRIVER_3' => array(4, 1, 6)), );
The above is my array
i want output in the following format
Output: Array ( [DRIVER_1] => 51, [DRIVER_2] => 33, [DRIVER_3] => 24, [DRIVER_4] => 67, [DRIVER_5] => 34 )
this is the sum of distance travelled by each driver in all trips
i tried code like this,anybody knows please help
$res = array();
foreach($distance_covered as $value) {
foreach($value as $key => $number) {
(!isset($res[$key])) ?
$res[$key] = $number :
$res[$key] += $number;
}
}
print_r($res);
?>

This one works for me
$res = array();
foreach($distance_covered as $value)//the array which you have given us
{
foreach($value as $key => $number) //loop over array of date
{
if(!isset($res[$key]))//check if the key exist in over defined array if no then run this
{
$res[$key] = array_sum($number);// Sum all distances of that driver
continue;//set the key and continue the foreach...
}
$res[$key] += array_sum($number);// Sum all distances of that driver
}
}
print_r($res);
die;
And the Output is
Array
(
[DRIVER_1] => 51
[DRIVER_2] => 33
[DRIVER_3] => 24
[DRIVER_4] => 67
[DRIVER_5] => 34
)

This should work:
$res = array();
foreach($distance_covered as $value) {
foreach($value as $key => $number) {
foreach ($number as $n) {
if (isset($res[$key])) {
$res[$key] += $n;
} else {
$res[$key] = $n;
}
}
}
}
print_r($res);

Just traverse through array of arrays.
$distance_covered = array(
'1_JAN_2017' => array('DRIVER_1' => array(2, 5, 3),'DRIVER_2' => array(3, 2, 6, 9)),
'2_JAN_2017' => array('DRIVER_1' => array(3, 9), 'DRIVER_3' => array(1, 4, 8)),
'3_JAN_2017' => array('DRIVER_4' => array(9), 'DRIVER_1' => array(2, 7, 5, 2)),
'4_JAN_2017' => array('DRIVER_1' => array(5, 3, 3, 2), 'DRIVER_4' => array(4, 9, 8, 5)),
'5_JAN_2017' => array('DRIVER_2' => array(8, 5), 'DRIVER_5' => array(3, 9, 7)),
'6_JAN_2017' => array('DRIVER_5' => array(2, 1, 7, 5), 'DRIVER_4' => array(1, 9, 6)),
'7_JAN_2017' => array('DRIVER_4' => array(5, 2, 9), 'DRIVER_3' => array(4, 1, 6)), );
// Counting.
$merged = [];
foreach ($distance_covered as $day => $stats) {
foreach ($stats as $driver => $distances) {
if (!isset($merged[$driver])) {
$merged[$driver] = 0;
}
$merged[$driver] += array_sum($distances);
}
}
// Display.
echo "<pre>";
print_r($merged);
echo "</pre>";

You are close, but...
$res = array ();
foreach ( $distance_covered as $value ) {
foreach ( $value as $key=> $driver ) {
if ( isset($res[$key]) == false ){
$res[$key]=0;
}
$res[$key] += array_sum($driver);
}
}
print_r($res);
The first foreach simply splits the data down to the days.
The second one returns elements like $key = 'DRIVER_1' and $driver = array(3, 9).
If this is the first time you've encountered this driver, then you need to ensure that the element in $res exists, so set it to 0.
Once you know there is an element there, you can add in the sum of the values ( 3 & 9 in this case ) using the += array_sum($driver) bit. The += is simply adding to rather than having to say a=a+b, you can say a+=b.

[sarcastic voice] I can't believe everybody overlooked this convoluted function-based one-liner...
Code: (Demo)
var_export(array_map('array_sum', array_merge_recursive(...array_values($distance_covered))));
Output:
array (
'DRIVER_1' => 51,
'DRIVER_2' => 33,
'DRIVER_3' => 24,
'DRIVER_4' => 67,
'DRIVER_5' => 34,
)
*this is virtually guaranteed to process slower than any other posted answer.
Remove the first level associative keys (date strings) with array_values()
Unpack the array of arrays with the "splat operator" (...) and feed to array_merge_recursive() to group values
Sum the subarray values by calling array_sum() on each subarray with array_map()
(This is merely an exercise of thinking outside the box.)
Beyond that no one suggested using a null coalescing operator, so I'll post what that can look like:
$driver_totals = [];
foreach ($distance_covered as $daily_log) {
foreach ($daily_log as $driver => $distances) {
$driver_totals[$driver] = ($driver_totals[$driver] ?? 0) + array_sum($distances);
}
}
var_export($driver_totals);
And if you have a special scenario where you only need to know the distance for a single specific driver, you can call upon array_column() like this:
$target_driver = 'DRIVER_4';
$total_distance = 0;
foreach (array_column($distance_covered, $target_driver) as $distances) {
$total_distance += array_sum($distances);
}
echo "{$target_driver} drove for a distance of {$total_distance}";
*Notice that the order of the drivers within each date array is inconsequential because array_column() is smart enough to find the desired distance subarray.
Finally, if you declare a whitelist array of all possible drivers, you can:
control the order of the drivers in the output
avoid the iterated isset() conditions
ensure that drivers without any distance records are included in the output
Code:
$roster = ['DRIVER_6', 'DRIVER_5', 'DRIVER_4', 'DRIVER_3', 'DRIVER_2', 'DRIVER_1'];
$driver_totals = array_fill_keys($roster, 0);
foreach ($distance_covered as $daily_log) {
foreach ($daily_log as $driver => $distances) {
$driver_totals[$driver] += array_sum($distances);
}
}
var_export($driver_totals);

Related

How to assign all input values into an array based on key availability without conflict?

I am looking for a slot filling technique. I have 8 "slots" represented as a flat array. I also have a multidimensional array where keys are subjects and values are subarrays containing indexed elements (slots).
The multidimensional array ($emp) may contain, for example, the subject Tamil which is available at slots 1 through 5, and/or English which is only available during slots 4, 5, or 6. All subjects on offer will have an array of available slots -- even if only one slot is available.
Subject Availability:
$emp = array(
"tamil" => array(1, 2, 3, 4, 5),
"english" => array(4, 5, 6),
"maths" => array(1, 5, 8),
"social" => array(1, 2, 5),
"pt" => array(1),
"hindi" => array(3, 4, 7)
);
I need to assign the following subjects the exact number of times -- while obeying subject availability AND without encountering a "slot conflict" -- in my output array ($sort):
Tamil 2 times
PT 1 time
Maths 2 times
Social 1 time
Hindi 1 time
English 1 time
All 8 slots must be filled. All subjects must occur only once with exception to Tamil and Math which must occur exactly twice.
Output may be:
$slot[3] = 'tamil',
$slot[7] = 'Hindi',
$slot[6] = 'English',
$slot[1] = 'Pt',
$slot[5] = 'Maths',
$slot[8] = 'Maths',
$slot[4] = 'Tamil',
$slot[2] = 'Social'.
I have tried to code this myself, but I was unsuccessful.
for ($i = 1; $i < 9; $i++) {
$var = $subarray[$i];
if (count($var) <= 1) {
$filledslots[$i] = $var[0];
} else {
$empty[$i] = '';
}
}
$subjects = array_flat($subarray);
$count_values = array();
$subjects = array_diff($subjects, $filledslots);
foreach ($subjects as $value) {
$count_values[$value] = 0;
foreach ($empty as $key => $val) {
$res = $subarray[$key];
if (in_array($value, $res)) {
$count_values[$value] = $count_values[$value] + 1;
}
}
if ($count_values[$value] == 1) {
//$filledslots[1] = $count_values[$value];
foreach ($empty as $key => $val) {
$res = $subarray[$key];
if (in_array($value, $res)) {
$filledslots[$key] = $value;
}
}
}
}
print_r(($filledslots));
Here is a working recursive technique that will return the first qualifying data set.
It works by removing elements from the "required subjects" array and the "available slots" array while adding elements to the "filled slots" array.
The use of array_replace() to push qualifying values into the 3rd parameter being delivered in the recursive call prevents disrupting the state of the $filledSlots variable that will continue to be used by the foreach loops.
The function: (Demo)
function fillSlots($requiredSubjects, $availableSlots, $filledSlots = []) {
if (!$requiredSubjects) {
ksort($filledSlots);
return $filledSlots;
}
foreach ($requiredSubjects as $rIndex => $subject) {
foreach ($availableSlots[$subject] as $sIndex => $slot) {
if (!isset($filledSlots[$slot])) {
unset($requiredSubjects[$rIndex], $availableSlots[$subject][$sIndex]);
$result = fillSlots(
$requiredSubjects,
$availableSlots,
array_replace($filledSlots, [$slot => $subject])
);
if ($result) {
return $result;
}
}
}
}
}
The input variables:
$subjectSlots = [
"tamil" => [1, 2, 3, 4, 5],
"english" => [4, 5, 6],
"maths" => [1, 5, 8],
"social" => [1, 2, 5],
"pt" => [1],
"hindi" => [3, 4, 7]
];
$requiredSubjects = ['tamil', 'tamil', 'pt', 'maths', 'maths', 'social', 'hindi', 'english'];
To allow the function to perform thousands of times faster (I benchmarked because I was curious), prepare the input data so that subjects with fewer slots are iterated first.
Pre-execution sorting: (See the effect)
usort($requiredSubjects, function($a, $b) use ($subjectSlots) {
return $subjectSlots[$a] <=> $subjectSlots[$b]; // sort by length, then by values
});
The initial call:
var_export(fillSlots($requiredSubjects, $subjectSlots));
Output:
array (
1 => 'pt',
2 => 'social',
3 => 'tamil',
4 => 'tamil',
5 => 'maths',
6 => 'english',
7 => 'hindi',
8 => 'maths',
)

Count element in multidimensional array

I have one problem with PHP array. I have the following array:
$arr = array(
1 => array(1, 2),
2 => array(1,2,3),
3 => array(4,array(4,4,4))
);
I want to know how many element in total.
Ex:
echo count($arr); // result: 3
but I want: 7
I want to do this without loop.
Do any one know, please help?
Take one of this
$arr = array(
1 => array(1, 2),
2 => array(1, 2, 3),
3 => array(4, array(4, 4, 4))
);
// iterate over values to find out their size/
var_dump(array_reduce($arr, function($count, $inner_array)
{ return $count + sizeof($inner_array); }, 0));
// merge all value to one big array
var_dump(count(call_user_func_array('array_merge', $arr)));
// create new array with counts of items
var_dump(array_sum(array_map('sizeof', $arr)));
<?php
$arr = array(
1 => array(1, 2),
2 => array(1,2,3),
3 => array(4,array(4,4,4))
);
$sum = 0;
foreach($arr as $a => $b) {
$sum += count($b);
}
echo $sum;
?>
$arr = array(
1 => array(1, 2),
2 => array(1,2,3),
3 => array(4,array(4,4,4))
);
$count = 0;
foreach ($arr as $level) {
$count+= count($level);
}
echo $count;
If your array as follows you can use another method for get 7
$arr = array(
1 => array(1, 2),
2 => array(1,2,3),
3 => array(4,8)
);
echo (count($arr, COUNT_RECURSIVE) - count($arr));

remove elements in php array that occur more than twice

I am looking for a function in php,where the function must delete values in the array that shows up three times or more? For example, if you give the function array(2, 4, 6, 3, 7, 7, 7, 4, 2, 0) the funciton will return array(2, 4, 6, 3, 4, 2, 0)
You can use array_count_values() to get frequencies. Then use a foreach to get values that has frequency less than 3...
$array = array(2, 4, 6, 3, 7, 7, 7, 4, 2, 0);
$frq = array_count_values($array);
$result = array();
foreach ($frq as $key=>$value){
if ($value < 3){
$result[] = $key;
}
}
function FilterMyArray(array &$array){
$array_count=array_count_values($array);
foreach($array_count as $key => $value){
if($value > 2){
foreach (array_keys($array, $key, true) as $unsetKey) {
unset($array[$unsetKey]);
}
}
}
}
$array=array(1, 3, 5, 2, 6, 6, 6, 3, 1, 9);
FilterMyArray($array);
print_r($array);
Output
Array ( [0] => 1 [1] => 3 [2] => 5 [3] => 2 [7] => 3 [8] => 1 [9] => 9 )
`
This will remove all duplicates, but you'd have to add to it to count the number of each of the values.
$a = array(2, 4, 6, 3, 7, 7, 7, 4, 2, 0);
$b = array();
for ($a as $key=>$value) {
if (!in_array($value, $b)) {
$b[] = $value;
}
}
// array $b has all the values with no duplicates.

Merge two flat arrays and omit values from one array when the other array has more occurrences of the same value

I want to merge every element of two arrays, BUT if a value is in both arrays, then only add the values from the array which has the biggest amount of that element. The result array does not need to be sorted in any special way, but I did it here for readability.
Sample input:
$array1 = [1, 4, 7, 3, 3, 3];
$array2 = [4, 0, 3, 4, 9, 9];
Desired result:
[0, 1, 3, 3, 3, 4, 4, 7, 9, 9]
//a2 a1 a1 a1 a1 a2 a2 a1 a2 a2
Note, this will be used on big arrays, with unknown integer values. Is there a good way to do this that doesn't require too much time/processing power?
Try this:
<?php
$array1 = [1, 4, 7, 3, 3, 3];
$array2 = [4, 0, 3, 4, 9, 9];
function min_merge($arr1, $arr2) {
$arr1 = array_count_values($arr1);
$arr2 = array_count_values($arr2);
foreach ($arr2 as $index => $arr)
if (!isset($arr1[$index]) || $arr > $arr1[$index])
$arr1[$index] = $arr;
foreach ($arr1 as $index => $arr)
for ($i = 0; $i < $arr; $i++)
$final[] = $index;
return $final;
}
print_r(min_merge($array1, $array2));
Output:
Array (
[0] => 1
[1] => 4
[2] => 4
[3] => 7
[4] => 3
[5] => 3
[6] => 3
[7] => 0
[8] => 9
[9] => 9
)
Unsorted, but it contains all the numbers from [0, 1, 3, 3, 3, 4, 4, 7, 9, 9].
$count[0] = array_count_values($arr1);
$count[1] = array_count_values($arr2);
$out = array();
array_map(function($e) use(&$out, $count){
$n1 = (isset($count[0][$e])) ? $count[0][$e] : 0;
$n2 = (isset($count[1][$e])) ? $count[1][$e] : 0;
$next = ($n2 > $n1) ? array_fill(0, $n2, $e) : array_fill(0, $n1, $e);
$out = array_merge($out, $next);
}, array_keys($count[0] + $count[1]));
print_r($out);
My modernized rewrite of #DaveChen's answer using PSR-12 coding standards and eliminating single-use declarations. This approach uses one loop to determine the greater count for numbers shared by both value-count arrays, then a second loop to populate the result array. (Demo)
$counts1 = array_count_values($array1);
foreach (array_count_values($array2) as $number => $count) {
if ($count > ($counts1[$number] ?? 0)) {
$counts1[$number] = $count;
}
}
$result = [];
foreach ($counts1 as $number => $count) {
array_push($result, ...array_fill(0, $count, $number));
}
var_export($result);
My modernized rewrite of #Expedito's answer which does not abuse the array_map() (when array_map()'s return value is not used, use array_walk() for functional style programming), uses a foreach() loop to eliminate variable scope issues, and generally implements D.R.Y. techniques. (Demo)
$counts1 = array_count_values($array1);
$counts2 = array_count_values($array2);
$result = [];
foreach ($counts1 + $counts2 as $num => $cnt) {
array_push(
$result,
...array_fill(
0,
max($counts1[$num] ?? 0, $counts2[$num] ?? 0),
$num
)
);
}
var_export($result);
And I wanted to add a new approach of my own, despite the fact that it may or may not perform better than the other two snippets. The script makes one pass over the first value count arrays to populate a temporary array which demands which numbers from the first array should be represented in the result array. Then it isolates value intersections from the first array, value differences from the second array, then merges them. (Demo)
$counts1 = array_count_values($array1);
$counts2 = array_count_values($array2);
$keepFrom1 = array_keys(
array_filter(
$counts1,
fn($count, $number) => ($counts2[$number] ?? 0) <= $count,
ARRAY_FILTER_USE_BOTH
)
);
var_export(
array_merge(
array_intersect($array1, $keepFrom1),
array_diff($array2, $keepFrom1)
)
);
probably not the most optimized but
<?php
$one=[1, 4, 7, 3, 3, 3];
$two=[4, 0, 3, 4, 9, 9];
sort($one);
sort($two);
foreach($one as $el)
{
$combined[]=$el;
if (array_search($el,$two))
{
unset($two[array_search($el,$two)]);
}
}
foreach($two as $el)
{
$combined[]=$el;
}
sort($combined);
print_r($combined);
?>

Count level 3 of an array

Is it possible without iterating the array?
$arr = array(
'section1' => array(
5 => array(1, 2, 3),
25 => array(4, 5),
34 => array(10, 12),
),
'section2' => array(
45 => array(1, 42, 3),
64 => array(10, 2, 5, 95),
),
'section3' => array(
5 => array(1, 2, 3, 5, 2),
25 => array(4, 5, 14),
34 => array(17),
),
);
$count = 0;
foreach($arr as $section)
foreach($section as $subsection)
foreach($subsection as $entries)
$count++;
echo $count; // 23
It works but I dont want to iterate trough the entire array just to count some elements...
You can use count().
If you need a total of all elements from all levels:
count($arr, COUNT_RECURSIVE);
If you only need to count the ones on the third level:
foreach($arr as $section)
foreach($section as $subsection)
$count += count($subsection);
Anything's possible right? ;-)
I'd see two ways you could do this without iterating and one would be to evaluate the print_r($main_array) value perhaps counting the "(" to reach the desired depth.
--
The other way would be store the data as JSON, so you can "walk" the tree, plus it's native in javascript so very efficient with dot notation.
"somefield":["anotherfield":["yetanother":value], "woohoo":["yahoo":value]]] (excuse me if not well-formed just on the fly)
Then you parse JSON and reference like: myval = somefield.anotherfield.yetanother; // myval = value
Here's my aproach to this conundrum!
<?php
$arr = array(
'section1' => array(
5 => array(1, 2, 3),
25 => array(4, 5),
34 => array(10, 12),
),
'section2' => array(
45 => array(1, 42, 3),
64 => array(10, 2, 5, 95),
),
'section3' => array(
5 => array(1, 2, 3, 5, 2),
25 => array(4, 5, 14),
34 => array(17),
),
);
function count_all($array)
{
$count = 0;
foreach ($array as $k => $v)
{
if (is_array($v))
{
$count += count_all($v);
}
else {
$count++;
}
}
return $count;
}
echo count_all($arr);

Categories