php, some effective algorithms - php

I have an array in php
$arr = array(
array('id' => 1, 'par' => 5),
array('id' => 2, 'par' => 5),
array('id' => 3, 'par' => 5),
array('id' => 4, 'par' => 7),
array('id' => 5, 'par' => 7),
array('id' => 6, 'par' => 7),
array('id' => 7, 'par' => 9),
array('id' => 8, 'par' => 9),
...
);
Can anybody know an effective algorithm to get a first indeks of an element which has property
$arr[x]['par'] == 7. How to get the first x from the array containing 2000 elements?
Thank you

I'm not sure if using an iterator is any faster than doing it by "hand", but you could use a RecursiveArrayIterator - http://php.net/manual/en/class.recursivearrayiterator.php
$arr = array(
array('id' => 1, 'par' => 5),
array('id' => 2, 'par' => 5),
array('id' => 3, 'par' => 5),
array('id' => 4, 'par' => 7),
array('id' => 5, 'par' => 7),
array('id' => 6, 'par' => 7),
array('id' => 7, 'par' => 9),
array('id' => 8, 'par' => 9),
);
$arrayIterator = new RecursiveIteratorIterator(new RecursiveArrayIterator($arr));
foreach ($arrayIterator as $subKey=>$subValue) {
if ($subKey == 'par' && $subValue == 9) {
$validArray = iterator_to_array($arrayIterator->getSubIterator());
$id = $validArray['id']; // This is your return array
break;
}
}
But, to be honest, doing it by hand would probably be a lot easier to understand and debug, and for 2000 records - why bother with anything more complex than:
foreach($arr as $subArray) {
if ($subArray['par'] == 9) {
$id = $subArray['id'];
break;
}
}
If you were handling more records, or had the popularity of Facebook, then start to get serious. But sometimes keeping it simple is the best way.

I used a binary search
$par = 7;
$a = 0;$i = -1;
$b = count($arr);
while(true) {
if($par == $arr[$a]['par']) { $i = $a; break; }
if($par == $arr[$m]['par']) { $i = $m; break; }
if($par == $arr[$b]['par']) { $i = $b; break; }
if($a == $m || $m == $b) break;
if($arr[$a]['par'] < $par && $par < $arr[$m]['par']) {
$b = $m; $m = floor(($a+$b)/2);
}
if($arr[$m]['par'] < $parent && $parent < $arr[$b]['par']) {
$a = $m; $m = floor(($a+$b)/2);
}
}
That example was more slow, than a $i=0;while($i < $n && $arr[$i]['par'] != $par) $i++; Can be used the array_search instead?

Related

output of php array in a particular format

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);

How can I combine two arrays in into one single array?

I am having to add more functionality in my codeigniter project. Here is the jsfiddle demo. I have an array like this:
$faculty = array(2, 3, 4);
and
$message = array('test1', 'test2', 'test3');
I'm also having an last insert id from another database:
$last_inserted_id = 1;
I want to combine the data to form an array like this:
$array = array(array('faculty' => 2, 'message' => 'test1', 'id' => 1),
array('faculty' => 3, 'message' => 'test2', 'id' => 1),
array('faculty' => 4, 'message' => 'test3', 'id' => 1));
Thanks for everyone for your suggestions and time.
I hope this will you:
$array = [];
$faculty = array(2, 3, 4);
$message = array('test1', 'test2', 'test3');
$id = 1;
for ($key = 0; $key < count($faculty); $key++) {
$array[$key]['faculty'] = $faculty[$key];
$array[$key]['message'] = $message[$key];
$array[$key]['id'] = $id;
}
print_r($array);

how to search min and max values in 2D array

am trying to find out min x and min y values in whole array , i tried with min and max function but no success so far
i have xy values of board in 2d array
$xydata = array(
array('x' => 17.0, 'y' => 2.83),
array('x' => 20.83, 'y' => 65.37 ),
array('x' => 17.85,'y' => 3.57 ),
array('x' => 17.13, 'y' => 41.33 ),
array('x' => 24.27, 'y' => 53.48 ),
array('x' => 13.1, 'y' => 16.35),
array('x' => 13.1, 'y' => 66.855 )
);
i want to find corners of board
globally i have min x/y max x/y which i got through min() and max () functions
what i want is to get min y against min x
like if through $xydata i search with min x which is 13.1 i should get min y 16.35 because the other min x 13.1 y value is 66.855 is higher .... so any idea how it could be done
Sample code:
$xydata = array(
array('x' => 17.0, 'y' => 2.83),
array('x' => 20.83, 'y' => 65.37 ),
array('x' => 17.85,'y' => 3.57 ),
array('x' => 17.13, 'y' => 41.33 ),
array('x' => 24.27, 'y' => 53.48 ),
array('x' => 13.1, 'y' => 66.855 ),
array('x' => 13.1, 'y' => 16.35),
);
$min = $xydata[0];
foreach ($xydata as $d) {
if ($d['x'] < $min['x'] || ($d['x'] == $min['x'] && $d['y'] < $min['y'])) {
$min = $d;
}
}
echo'<pre>',print_r($min),'</pre>'; // TODO
Try this, best solution is use shorting of array
$xydata = array(
array('x' => 17.0, 'y' => 2.83),
array('x' => 20.83, 'y' => 65.37 ),
array('x' => 17.85,'y' => 3.57 ),
array('x' => 17.13, 'y' => 41.33 ),
array('x' => 24.27, 'y' => 53.48 ),
array('x' => 13.1, 'y' => 16.35),
array('x' => 13.1, 'y' => 66.855 )
);
$count = 0;
foreach ($xydata as $type) {
$count++;
}
$count--;
function sortByOrder($a, $b) {
return $a['x'] - $b['x'];
}
usort($xydata, 'sortByOrder');
echo "min of x => ".$xydata [0]['x'];
echo "max of x => ".$xydata [$count]['x'];
function sortByOrdery($a, $b) {
return $a['y'] - $b['y'];
}
usort($xydata, 'sortByOrdery');
echo "min of y => ".$xydata [0]['y'];
echo "max of y => ".$xydata [$count]['y'];
DEMO
You can try the below functions:
function array_max($a) {
foreach ($a as $value) {
if (is_array($value)) {
$value = array_max($value);
}
if (!(isset($max))) {
$max = $value;
} else {
$max = $value > $max ? $value : $max;
}
}
return $max;
}
function array_min($a) {
foreach ($a as $value) {
if (is_array($value)) {
$value = array_min($value);
}
if (!(isset($min))) {
$min = $value;
} else {
$min = $value < $min ? $value : $min;
}
}
return $min;
}
Its work fine for me :)
You can use array_multisort to build a function that will give you all possible pairs of min/max:
function getXY(array $xyArray, $x = 'min', $y = 'min')
{
$xFlag = $x === 'max' ? SORT_DESC : SORT_ASC;
$yFlag = $y === 'max' ? SORT_DESC : SORT_ASC;
array_multisort(
array_column($xyArray, 'x'), $xFlag,
array_column($xyArray, 'y'), $yFlag,
$xyArray
);
return array_shift($xyArray);
}
Here is working demo.

Sort and shuffle multidimensional array

I am working on gaming project, which needs sort and shuffle multidimensional array. First i need to sort based on bid. If multiple bids are same i need to sort based on priority. If bid & priority both are same means I need to shuffle those elements. For example we have 3 array elements in bid=0.4 & priority=4. Id's are 102,103 & 104. These array element position should be shuffled.
array(
array('id' => 101, 'bid' => 0.5, 'priority' => 5),
array('id' => 102, 'bid' => 0.4, 'priority' => 4),
array('id' => 103, 'bid' => 0.4, 'priority' => 4),
array('id' => 104, 'bid' => 0.4, 'priority' => 4),
array('id' => 105, 'bid' => 0.3, 'priority' => 5),
array('id' => 106, 'bid' => 0.3, 'priority' => 5),
array('id' => 107, 'bid' => 0.2, 'priority' => 5),
array('id' => 108, 'bid' => 0.7, 'priority' => 5),
array('id' => 108, 'bid' => 0.1, 'priority' => 4)
);
You should take a look at array_multisort to do that. There are examples on that page on how to sort a multi-dimensional array
<?php
// Obtain a list of columns
foreach ($data as $key => $row) {
$bid[$key] = $row['bid'];
$prio[$key] = $row['priority'];
}
array_multisort($bid, SORT_ASC, $prio, SORT_ASC, $data);
?>
To shuffle I would add an extra column to the multidimensional array called "rand" and then fill it with a random number before you use multisort. Then you can add a 3th sort order on that column for shuffling.
Based on idea #Hugo's answer about using random weight:
$array = array(
array('id' => 101, 'bid' => 0.5, 'priority' => 5),
array('id' => 102, 'bid' => 0.4, 'priority' => 4),
array('id' => 103, 'bid' => 0.4, 'priority' => 4),
array('id' => 104, 'bid' => 0.4, 'priority' => 4),
array('id' => 105, 'bid' => 0.3, 'priority' => 5),
array('id' => 106, 'bid' => 0.3, 'priority' => 5),
array('id' => 107, 'bid' => 0.2, 'priority' => 5),
array('id' => 108, 'bid' => 0.7, 'priority' => 5),
array('id' => 108, 'bid' => 0.1, 'priority' => 4)
);
function cmp(&$a, &$b) { # notice the use of & in function signature
if ($a['bid'] - $b['bid']) {
return $a['bid'] - $b['bid'] > 0 ? 1 : -1; # bid is different, sort using bid
} else if ($a['priority'] - $b['priority']) {
return $a['priority'] - $b['priority'] > 0 ? 1 : -1; # priority is different, sort using priority
} else {
if (isset($a['rw']) == false) {
$a['rw'] = rand(1, 100); # assign random tie breaker
}
if (isset($b['rw']) == false) {
$b['rw'] = rand(1, 100); # assign random tie breaker
}
if ($a['rw'] - $b['rw']) {
return $a['rw'] - $b['rw'] > 0 ? 1 : -1; # sort using random weight
} else {
return 0;
}
}
}
usort($array, 'cmp');
var_dump($array);
Output
array(9) {
[0]=>array(3) {["id"]=>int(108) ["bid"]=>float(0.1) ["priority"]=>int(4)}
[1]=>array(3) {["id"]=>int(107) ["bid"]=>float(0.2) ["priority"]=>int(5)}
[2]=>array(4) {["id"]=>int(106) ["bid"]=>float(0.3) ["priority"]=>int(5) ["rw"]=>int(70)}
[3]=>array(4) {["id"]=>int(105) ["bid"]=>float(0.3) ["priority"]=>int(5) ["rw"]=>int(73)}
[4]=>array(4) {["id"]=>int(103) ["bid"]=>float(0.4) ["priority"]=>int(4) ["rw"]=>int(29)}
[5]=>array(4) {["id"]=>int(104) ["bid"]=>float(0.4) ["priority"]=>int(4) ["rw"]=>int(67)}
[6]=>array(4) {["id"]=>int(102) ["bid"]=>float(0.4) ["priority"]=>int(4) ["rw"]=>int(80)}
[7]=>array(3) {["id"]=>int(101) ["bid"]=>float(0.5) ["priority"]=>int(5)}
[8]=>array(3) {["id"]=>int(108) ["bid"]=>float(0.7) ["priority"]=>int(5)}
}
Usort would be ideal for this situation http://www.php.net/manual/en/function.usort.php
You define the function that does the comparisons
<?php
function cmp($a, $b)
{
if ($a['bid'] == $b['bid']) {
if ($a['priority'] == $b['priority']) return 0;
return ($a['priority'] < $b['priority']) ? -1 : 1;
}
return ($a['bid'] < $b['bid']) ? -1 : 1;
}
usort($data, "cmp");
?>
Also based on #Hugos answer, adding shuffle using PHP built in shuffle() and range() functions:
<?php
$data=array(
array('id'=>101,'bid'=>0.5,'priority'=>5),
array('id'=>102,'bid'=>0.4,'priority'=>4),
array('id'=>103,'bid'=>0.4,'priority'=>4),
array('id'=>104,'bid'=>0.4,'priority'=>4),
array('id'=>105,'bid'=>0.3,'priority'=>5),
array('id'=>106,'bid'=>0.3,'priority'=>5),
array('id'=>107,'bid'=>0.2,'priority'=>5),
array('id'=>108,'bid'=>0.7,'priority'=>5),
array('id'=>108,'bid'=>0.1,'priority'=>4)
);
$rand=range(0,count($data)-1);
shuffle($rand);
foreach ($data as $key => $row) {
$bid[$key] = $row['bid'];
$prio[$key] = $row['priority'];
}
array_multisort($bid, SORT_ASC, $prio, SORT_ASC, $rand, SORT_ASC, $data);
I first tried simply shuffling the array before sorting, but for some unknown reason, sorting seems to sort on id as well. Probably some effect of algorithm used.
You can use usort
usort($array,function ($a, $b) {
if ($a['id'] == $b['id']) {
if ($a['priority'] == $b['priority'] && $a['bid'] == $b['bid']) {
$pos = array(-1,0,1);
return $pos[mt_rand(0, 2)]; // shurffle
}
$a = $a['priority'];
$b = $b['priority'];
return ($a == $b) ? 0 : (($a > $b) ? - 1 : 1); // sorty by priority
}
// First i need to sort based on bid
$a = $a['id'];
$b = $b['id'];
return ($a == $b) ? 0 : (($a < $b) ? - 1 : 1); //sort by bid id
});
<?php
foreach ($data as $key => $row) {
//just create a random field
$data[$key]['randSort']= rand(1,999999);
$sameRand[$key] = $data[$key]['randSort'];
$bid[$key] = $row['bid'];
$prio[$key] = $row['priority'];
}
array_multisort($bid, SORT_ASC, $prio, SORT_ASC, $sameRand, SORT_ASC, $data);
?>
put elements to be shuffled into an array and remove them from the initial array until the initial array is empty.
call shuffle on the created array
put the shuffled array into a new array with the results.

How to sum numbers in arrays in php?

In php, how do I get the total number of posts (16)?
array1("posts" => 2, "reactions" => 0)
array2("posts" => 4, "reactions" => 4)
array3("posts" => 7, "reactions" => 0)
array4("posts" => 3, "reactions" => 1)
You can use this function
array_merge_recursive
And I made an example for you
<?php
$a = array("posts" => 2, "reactions" => 0);
$b = array("posts" => 4, "reactions" => 4);
$c = array("posts" => 7, "reactions" => 0);
$d = array("posts" => 3, "reactions" => 1);
$array = array_merge_recursive($a,$b,$c,$d);
$sum = array_sum($array['posts']);
echo $sum;
?>
If you want to read more about array_merge_recursive
Follow this Link
Don't know how your variables are named, but some sort of:
$total = 0;
foreach ($arrayofstuff as $item) {
$total += $item['posts'];
}
$numposts = $arr1["posts"]+$arr2["posts"]+$arr3["posts"]+$arr4["posts"]
Do you have them in separate arrays or in one single array? If you have them separately then this would suffice:
$array1 = array("posts" => 2, "reactions" => 0);
$array2 = array("posts" => 4, "reactions" => 4);
$array3 = array("posts" => 7, "reactions" => 0);
$array4 = array("posts" => 3, "reactions" => 1);
$sum = $array1['posts'] + $array2['posts'] + $array3['posts'] + $array4['posts'];
echo $sum;
Outputs:
16

Categories