I got array of points:
array(
array('x' => ...,'y' => ...),
array('x' => ...,'y' => ...)
...
)
What is the best way to make those points one, that is in "avarge" position? Is pairing and then pairing and then pairing... a good algorithm?
I would give myself -1 for this question, as it seems to be really easy, but I am working on project for more than 20 hours now, and my brain went off.
Hmm... is it as simple as counting avarge x and avarge y?
The best solution would be to turn your computer off and go to sleep for a couple of good hours. Then wake up rested and ready for a new programming session. This solution in based on an assumption that those 20 hours you have assigned this project was without any proper breaks.
While this isn't a direct answer to your question, it will certainly help you get there by yourself. Don't underestimate the power of a nap.
Take a look at this function I wrote to loop through all the elements of your multidimensional array and return their average after adding all of the elements together.
print_r(getAveragePoints(array(array('x' => 1,'y' => 3),array('x' => 2,'y' => 4))));
function getAveragePoints($arrays = array()) {
if(!empty($arrays)) {
$i=0;
$x = 0;
$y = 0;
foreach($arrays as $array) {
// this would take avg
$x += $array['x']; // x
$y += $array['y']; // y
$i++;
}
$avgX = $x / $i;
$avgY = $y / $i;
return array($avgX,$avgY);
} else {
return array(0,0);
}
}
Simple average option:
$pointArray = array(
array('x' => 1,'y' => 2),
array('x' => 2,'y' => 5),
array('x' => 3,'y' => 3) ,
array('x' => 4,'y' => 6) ,
array('x' => 4,'y' => 5) ,
);
$valueCount = count($pointArray);
$midpoint = array_map(
function($value) use($valueCount) {
return $value / $valueCount;
},
array_reduce(
$pointArray,
function($summary, $value) {
return array(
'x' => $summary['x'] += $value['x'],
'y' => $summary['y'] += $value['y']
);
},
array('x' => 0, 'y' => 0)
)
);
var_dump($midpoint);
Related
So I'm trying to create a script in PHP that has multiple objects on a cartesian plane (xy) and to find the closest distance.
for e.g., lets say we have 3 objects on an XY plane and I want to find the 2 closest objects by distance.
Now I can use the distance formula:
http://www.mathwarehouse.com/algebra/distance_formula/index.php
However, how do I write a function on this that takes in an array of objects?
I'm thinking something like this (please advise):
-array $objects will be the list (of objects w/ names/coordinates)
-it should return array the closest object names
$object1 = ['object1' => 'a', 'x' => 1, 'y' => 1];
$object2 = ['object2' => 'b', 'x' => 1, 'y' => 3];
$object3 = ['object3' => 'c', 'x' => 5, 'y' => 5];
I'm not sure how to write this though. I've started the function:
function findClosestObject(array $objects) {
d = sqrt(pow((x2-x1),2) + pow((y2-y1)),2))
}
Put your objects in an array.
Iterate over the array.
You can save a fair number of CPU cycles by not performing the sqrt() since you don't care what the literal distance is.
eg:
function getDistanceIsh($a, $b) {
return pow(abs(($a['x']-$b['x'])), 2) + pow(abs(($a['y']-$b['y'])), 2);
}
$testPoint = ['x'=>1, 'y'=>2];
$closest = $objects[0];
$closestDist = getDistance($testpoint, $objects[0]);
for( $i=1,$c=count($objects); $i<$c; $i++ ) {
$dist = getDistance($testpoint, $objects[$i]);
if( $dist < $closestDist ) {
$closest = $objects[$i];
$closestDist = $dist;
}
}
For 3 objects, there are only 3 combinations of 2 objects - 1 + 2, 1 + 3, and 2 + 3.
Abstract your distance formula into a function :
function distance($obj1,$obj2) {
return sqrt(pow(($obj1['x']-$obj2['x']),2) + pow(($obj1['y']-$obj2['y']),2));
}
Now calculate each combination of two objects, and store the results in an array :
$dist['12'] = distance($object1,$object2) ;
$dist['13'] = distance($object1,$object3) ;
$dist['23'] = distance($object2,$object3) ;
// sort values into ascending order
asort($dist);
// take 1st element index
reset($dist);
$closest = key($dist);
echo $closest;
To do this with a larger array of objects, you're going to need to implement code which first generates all the two-object combinations.
Writing your own code for such a computationally expensive programs is actually a bad start. Always first try to see if there is any Open Source code which can perform the same task more faster, and secure way. Because those codes are verified by many professionals and will mostly be error free, and also reduces your development time. So in your case, first finding the fastest algorithm is important. Dijkstra Algorithm is widely used for finding the shortest path, and some examples of Open Source PHP code are PHP-Dijkstra and Taniko-Dijkstra
Here's a solution that allows for a variable amount of objects (needs more than 1 of course). It utilizes hypot(), which is basically the same as your distance formula.
$objects = [
[ 'name' => 'obj1', 'x' => 1, 'y' => 1 ],
[ 'name' => 'obj2', 'x' => 1, 'y' => 3 ],
[ 'name' => 'obj3', 'x' => 5, 'y' => 5 ],
[ 'name' => 'obj4', 'x' => 10, 'y' => 8 ],
[ 'name' => 'obj5', 'x' => 30, 'y' => 12 ],
[ 'name' => 'obj6', 'x' => 31, 'y' => 13 ],
[ 'name' => 'obj7', 'x' => 40, 'y' => 15 ]
];
function findClosestObjects( array $objects ) {
// initialize $minDistance to null
$minDistance = null;
// total amount of objects
$len = count( $objects );
// loop from first object to the second-to-last
// last will be handled inside nested for loop
for( $i = 0; $i < $len - 1; $i++ ) {
// set $o1 to current $i object
$o1 = $objects[ $i ];
// loop from next object to the last, to avoid duplicate pairs
for( $j = $i + 1; $j < $len; $j++ ) {
// set $o2 to current $j object
$o2 = $objects[ $j ];
// calc distance
$distance = hypot( $o2[ 'x' ] - $o1[ 'x' ], $o2[ 'y' ] - $o1[ 'y' ] );
// if $minDistance is null or $distance is smaller than $minDistance
if( $minDistance == null || $minDistance > $distance ) {
// put objects and distance in $result
$result = [ $o1, $o2, 'distance' => $distance ];
// and update $minDistance
$minDistance = $distance;
}
}
}
return $result;
}
var_dump( findClosestObjects( $objects ) );
view parsed online # eval.in
It seems that a large, complicated codebase depends on the order arsort produces. Before I dive in to discern what's actually happening in like 50 classes -- is there a simple way to shuffle items with equal values?
In other words, if the input is
['foo' => 3, 'bar' => 3, 'baz' => 3, 'this' => 2, 'that' => 2]
I'd like to get
['baz' => 3, 'bar' => 3, 'foo' => 3, 'this' => 2, 'that' => 2]
one run maybe, then
['baz' => 3, 'bar' => 3, 'foo' => 3, 'that' => 2, 'this' => 2]
on another random run.
How about something like this? (Untested)
Worst Case complexity: O(k)
Note: Written for algorithmic clarity and not PHP details...
function shuffleInput( $data ) {
// Separate into sets.
$sets = [];
foreach ( $data as $k => $v ) {
$sets[$v][] = $k;
}
// Shuffle & Join.
$data = [];
foreach ( $sets as $v => &$set ) {
shuffle( $set );
foreach( $set as $k ) {
$data[$k] = $v;
}
}
return $data;
}
Depending on the size of your input, it might be a better idea to unset every element in $data in the first loop instead of just creating a new array. This applies if data is very large and memory is precious to you - as well as reducing any sudden spikes & dips in memory usage.
Also, if you're going to continously shuffle the same $data around you might want to separate out the making of $sets to some other place or at least allow the developer to pass/get it as a side effect.
If you do not want to deal with shuffle, but rather prefer to check all permutations of the array, then you can do something like this:
$arr = array('foo' => 3, 'bar' => 3, 'baz' => 3, 'this' => 2, 'that' => 2);
$keys = array_keys($arr);
$indexes = range(0, count($arr) - 1);
pc_permute($indexes, $perms);
var_dump($perms);
function pc_permute($items, &$ret = array(), $perms = array( )) {
if (empty($items)) {
$ret[] = $perms;
} else {
for ($i = count($items) - 1; $i >= 0; --$i) {
$newitems = $items;
$newperms = $perms;
list($foo) = array_splice($newitems, $i, 1);
array_unshift($newperms, $foo);
pc_permute($newitems, $ret, $newperms);
}
}
}
Array $perms will give all permutations of the indexes, key name by index you can get from $keys and value by key or index (use array_slice) from $arr :)
ps: but you should understand - more elements you have in the original array, more permutations you will find. if there are n elements then there will be n! permutations. for n = 5 there are 120 permutations.
So, I need to find out the highest possible difference between any two random values of an indexed array and I am not sure if my answer is correct, coz you know it's way too simple for the weight of this question:
function($array)
{
asort($array);
$diff = $array(sizeof($array) - 1) - $array(0);
return $diff;
}
I am sure this is correct, then again I always have my doubts!
You are right that the largest difference you will find is between the maximum value and the minimum value. However, you could achieve this more efficiently (O(N) instead of O(N log N)) by simply scanning the array to find the min and max values without sorting.
Just to wrap your head around the logic, here is a manual way of doing this:
$myarray = array(
'this' => 2,
'that' => 14,
'them' => -5,
'other' => 200,
'nothing' => 42,
'somethingelse' => 1,
'you' => 10,
'me' => 30);
foreach ($myarray as $key => $value) {
if (!isset ($min) || $value < $min) { $min = $value; }
if (!isset ($max) || $value > $max) { $max = $value; }
}
$diff = $max - $min;
echo $diff;
So I have an array of possible combinations:
$faces = array ('Bar', 'Cherry', 'Lemon', 'Seven', 'DoubleBar', 'TripleBar');
And an array of payouts
$payouts = array (
'Bar|Bar|Bar' => '5',
'Double Bar|Double Bar|Double Bar' => '10',
'Triple Bar|Triple Bar|Triple Bar' => '15',
'Cherry|Cherry|Cherry' => '20',
'Seven|Seven|Seven' => '70',
'Seven|Any|Any' => '70',
'Diamond|Diamond|Diamond' => '100',
);
And an array for every wheel (3 in total), how can I make weighted random combinations with Seven|Any|Any working properly?
I know I can just create two arrays 6^3 in size one representing the weights and the other array representing every possible combination and using something like this script, but isn't there a shorter, more efficient way?
function weighted_random_simple($values, $weights){
$count = count($values);
$i = 0;
$n = 0;
$num = mt_rand(0, array_sum($weights));
while($i < $count){
$n += $weights[$i];
if($n >= $num){
break;
}
$i++;
}
return $values[$i];
}
How about an array that correlates counts of possible results, rather than actual positions?
e.g. you do a run, get something like A/A/B, so you've got 2 A's, and look in the table
$payouts = array(
2 => array('Bar' => 10, 'Double Bar' => 20, etc...)
3 => array('Diamond' => 100, 'Bar' => 40, etc...)
);
I had some troubles implementing Lawler's algorithm but thanks to SO and a bounty of 200 reputation I finally managed to write a working implementation:
Lawler's Algorithm Implementation Assistance
I feel like I'm using too many variables and loops there though so I am trying to refactor the code. It should be simpler and shorter yet remain readable.
Does it make sense to make a class for this? Any advice or even help with refactoring this piece of code is welcomed:
<?php
/*
* #name Lawler's algorithm PHP implementation
* #desc This algorithm calculates an optimal schedule of jobs to be
* processed on a single machine (in reversed order) while taking
* into consideration any precedence constraints.
* #author Richard Knop
*
*/
$jobs = array(1 => array('processingTime' => 2,
'dueDate' => 3),
2 => array('processingTime' => 3,
'dueDate' => 15),
3 => array('processingTime' => 4,
'dueDate' => 9),
4 => array('processingTime' => 3,
'dueDate' => 16),
5 => array('processingTime' => 5,
'dueDate' => 12),
6 => array('processingTime' => 7,
'dueDate' => 20),
7 => array('processingTime' => 5,
'dueDate' => 27),
8 => array('processingTime' => 6,
'dueDate' => 40),
9 => array('processingTime' => 3,
'dueDate' => 10));
// precedence constrainst, i.e job 2 must be completed before job 5 etc
$successors = array(2=>5,
7=>9);
$n = count($jobs);
$optimalSchedule = array();
for ($i = $n; $i >= 1; $i--) {
// jobs not required to precede any other job
$arr = array();
foreach ($jobs as $k => $v) {
if (false === array_key_exists($k, $successors)) {
$arr[] = $k;
}
}
// calculate total processing time
$totalProcessingTime = 0;
foreach ($jobs as $k => $v) {
if (true === array_key_exists($k, $arr)) {
$totalProcessingTime += $v['processingTime'];
}
}
// find the job that will go to the end of the optimal schedule array
$min = null;
$x = 0;
$lastKey = null;
foreach($arr as $k) {
$x = $totalProcessingTime - $jobs[$k]['dueDate'];
if (null === $min || $x < $min) {
$min = $x;
$lastKey = $k;
}
}
// add the job to the optimal schedule array
$optimalSchedule[$lastKey] = $jobs[$lastKey];
// remove job from the jobs array
unset($jobs[$lastKey]);
// remove precedence constraint from the successors array if needed
if (true === in_array($lastKey, $successors)) {
foreach ($successors as $k => $v) {
if ($lastKey === $v) {
unset($successors[$k]);
}
}
}
}
// reverse the optimal schedule array and preserve keys
$optimalSchedule = array_reverse($optimalSchedule, true);
// add tardiness to the array
$i = 0;
foreach ($optimalSchedule as $k => $v) {
$optimalSchedule[$k]['tardiness'] = 0;
$j = 0;
foreach ($optimalSchedule as $k2 => $v2) {
if ($j <= $i) {
$optimalSchedule[$k]['tardiness'] += $v2['processingTime'];
}
$j++;
}
$i++;
}
echo '<pre>';
print_r($optimalSchedule);
echo '</pre>';
I would make it a class. I find it easier to refactor an algorithm when all necessary variables are encapsulated as class members, rather than remembering what values I have to pass in and out every time I extract a method.
You should set your inputs to the algorithm in the constructor and then have a generic execute method. This would allow you to conform to both the command and strategy patterns more easily.
Make all your loop and conditional bodies into individual protected functions. With appropriate naming, that will increase the readability immensely, and make it much easier to alter the algorithm through inheritance.