I am trying to return the highest percentage value along with all the other information like name,average, percentage, color etc in the array.
foreach ($array as $value) {
$name = getName($value);
$average = getAverage($value);
$percentage = getPercentage($value);
$color = getColor($value);
return $percentage;
}
How can i implement the solution to find the desired value (highest percentage) and return it If an array. I am thinking sorting can be one way but i am still not clear how should i do it.
Try this
$percentage1=0;
$datas=array();
foreach ($array as $value) {
$name = getName($value);
$average = getAverage($value);
$percentage = getPercentage($value);
$color = getColor($value);
if($percentage>$percentage1)
{
$percentage1=$percentage;
$datas['name']=$name;
$datas['average']=$average;
$datas['percentage']=$percentage;
$datas['color']=$color;
}
return $datas;
}
Though the code in your question doesn't make any sense, you can use php max function to get highest value if all value in array are numbers.
For example:
<?php $highest_value = max($array); ?>
If you want to use the buit-in PHP sorting, you can use usort(). It use a custom function to sort your array.
usort($array, function($a, $b){
$percentage_a = getPercentage($a);
$percentage_b = getPercentage($b);
if($percentage_a === $percentage_b) {
return 0;
}
return ($percentage_a > $percentage_b)? -1 : 1;
});
return array(
"name" => getName($array[0]),
"average" => getAverage($array[0]),
"percentage" => getPercentage($array[0]),
"color" = getColor($array[0]));
Then, your array is sorted with the highest percentage first.
If you don't want anonymous function, you can juste define it and call usort with its name :
function getMaxPercentage($a, $b){
$percentage_a = getPercentage($a);
$percentage_b = getPercentage($b);
if($percentage_a === $percentage_b) {
return 0;
}
return ($percentage_a > $percentage_b)? -1 : 1;
}
usort($array, 'getMaxPercentage');
return return array(
"name" => getName($array[0]),
"average" => getAverage($array[0]),
"percentage" => getPercentage($array[0]),
"color" = getColor($array[0]));
Related
I've created an array with 'maximum' values in.
$management = array(
'100' => '1',
'500' => '2',
'1000' => '3',
);
And created a loop to find the closest value, rounding it up.
$speed = 10;
$r= '';
sort($management);
foreach($management as $mgmt => $name) {
if($mgmt >= $speed) {
$r= $name;
}
}
$r= end($management);
So, where the $speed is 10, it should pick up the array key 100 and if it was 100 it should still pickup 100 but if the speed was 200, it would pickup 500
The above is picking up 500 when the $speed is 10 though.
Can anyone help please?
You have a couple of problems with your code. Firstly, the call to sort rewrites all the keys of the $management array which you are using for the comparison; you need to use ksort instead to sort by the keys instead of the values. Secondly, since the keys are in ascending order, once one is greater than the $speed value, they all will be, so you need to break from the loop once you find a higher value. Try this instead:
$r= '';
ksort($management);
foreach($management as $mgmt => $name) {
if($mgmt >= $speed) {
$r= $name;
break;
}
}
echo $r;
Demo on 3v4l.org
this is an example on how you can do it :
$array = array(1, 10, 100, 200, 400, 500, 1000);
public function getArrayRoundUp($array, $number) {
sort($array);
foreach ($array as $a) {
if ($a >= $number) return $a;
}
return end($array);
}
$value = 950;
$nearest = getArrayRoundUp($array, $value);
//the expect result will be 1000
echo $nearest;
Use the following function
function find(array $array, $search)
{
$last = null; // return value if $array array is empty
foreach ($array as $key => $value) {
if ($key >= $search) {
return $key; // found it, return quickly
}
$last = $key; // keep the last key thus far
}
return $last;
}
Tested and Working:-
echo find($management, 100); // Will result 100
echo find($management, 200); //Will result 500
for example if i have the following array:
$numbers=array(
"A"=>$value1,
"B"=>$value2,
"C"=>$value3,
"D"=>$value4,
"E"=>$value5,
"F"=>$value6,
"G"=>$value7,
);
and if some of the value variables are equal to 0 and the rest are equal to 1, how can I select the keys which values are equal, for example to 0?
Try this:
$all_zeros = array_filter($numbers);
$all_ones = array_diff($numbers, $all_zeros);
Also you might use a custom filter function like below:
function custom_filter($numbers, $targetValue) {
return array_filter($numbers, function ($i) use ($targetValue) {
return $targetValue == $i;
});
}
Ref:
array_filter
array_intersect
PHP Anonymous function
$result = [];
foreach($numbers as $id => $number) {
if($number ==0)
$result[$id] = $number;
}
I am attempting to find the closest product to the given budget
$array = array(
'productname1' => 5,
'productname2' => 10,
'productname3' => 15
)
$budget = 12;
I have tried using a function like the following to find the nearest value, but it only returns the number which is closest to the budget rather than the product name.
function closest($array, $number) {
sort($array);
foreach ($array as $a) {
if ($a >= $number) return $a;
}
return end($array);
}
I can't help but think there is a MUCH better implementation of this. Any help would be much appreciated.
foreach($array as $k => $v){ $diff[abs($v - $budget)] = $k; }
ksort($diff, SORT_NUMERIC);
$closest_key = current($diff);
var_dump($closest_key); // Product Name
var_dump($array[$closest_key]); // Product Cost
Prints:
string(12) "productname2"
int(10)
Or as a function:
function closest($array, $price)
{
foreach($array as $k => $v){ $diff[abs($v - $price)] = $k; }
ksort($diff, SORT_NUMERIC);
$closest_key = current($diff);
return array($closest_key, $array[$closest_key]);
}
print_r(closest($array, $budget));
Prints:
Array
(
[0] => productname2 // Product Name
[1] => 10 // Product Price
)
Both formats include only three steps:
Calculate the difference between the product cost and the budget
Sort these
Take the first element from the sorted array (the element whose price is closest to the budget).
EDIT: If you don't care about anything other than the single closest product, then a sort is overkill and a simple min() function (like Emil used) would be a lot faster. For example:
function closest($array, $price)
{
foreach($array as $k => $v){ $diff[abs($v - $price)] = $k; }
$closest_key = $diff[min(array_keys($diff))];
return array($closest_key, $array[$closest_key]);
}
function closest($array, $number) {
sort($array);
foreach ($array as $name => $a) {
if ($a >= $number) return $name;
}
return end(array_keys($array));
}
The trick comes in on this line:
foreach ($array as $name => $a) {
Here you assign $name to the array key and $a to the array value. Since you want the name, return $name;
Also, if no match is found, do, end(array_keys($array))); to get the name of the product, otherwise it will just spit out the value, which is not what you want.
You'll want to return the KEY, not the value:
function closest($array, $number) {
sort($array);
foreach ($array as $product=>$a) {
if ($a >= $number) return $product;
}
return $product;
}
Here's a functional way of doing it.
Map each post to the difference from the budget.
Find the smallest value.
Filter away all products not adhering to that value.
Implementation:
$diffs = array_map(function ($value) use ($budget) {
return abs($value - $budget);
}, $array);
$smallest = min($diffs);
$products = array_filter($array,
function ($value) use ($budget, $smallest) {
return abs($value - $budget) == $smallest;
});
$products will now contain all the products which are closest to the budget.
This is trapped inside a PHP foreach where there are multiple results being fetched.
$frontpage[] = array(
'perc' => $percentage,
'id' => $result->ID
);
I then want to sort $frontpage in descending order according to the values contained in 'perc', all of which are numbers. How do I do that?
Have you tried to use uasort()? It's a function with which you define a callback function that compares certain values.
function customCompare($a, $b)
{
if ($a['perc'] == $b['perc']) {
return 0;
}
return ($a['perc'] < $b['perc']) ? -1 : 1;
}
uasort($frontpage, 'customCompare');
$frontpage = array_reverse($frontpage); // for descending order
See it in action here.
There are loads of examples on how to use usort here: http://php.net/manual/en/function.usort.php
I wrote a simple test example assuming that the 'perc' key in the array is always the first one.
<?php
function percentCompare($a, $b)
{
if ($a == $b)
return 0;
//we want it decending
return ($a > $b) ? -1 : +1;
}
$frontpage[] = array();
//Fill the array with some random values for test
for ($i = 0; $i < 100; $i++)
{
$frontpage[$i] = array(
'perc' => rand($i, 100),
'id' => $i
);
}
//Sort the array
usort($frontpage, 'percentCompare');
print_r($frontpage);
?>
What would be the fastest, most efficient way to implement a search method that will return an object with a qualifying id?
Sample object array:
$array = [
(object) ['id' => 'one', 'color' => 'white'],
(object) ['id' => 'two', 'color' => 'red'],
(object) ['id' => 'three', 'color' => 'blue']
];
What do I write inside of:
function findObjectById($id){
}
The desired result would return the object at $array[0] if I called:
$obj = findObjectById('one')
Otherwise, it would return false if I passed 'four' as the parameter.
You can iterate that objects:
function findObjectById($id){
$array = array( /* your array of objects */ );
foreach ( $array as $element ) {
if ( $id == $element->id ) {
return $element;
}
}
return false;
}
Edit:
Faster way is to have an array with keys equals to objects' ids (if unique);
Then you can build your function as follow:
function findObjectById($id){
$array = array( /* your array of objects with ids as keys */ );
if ( isset( $array[$id] ) ) {
return $array[$id];
}
return false;
}
It's an old question but for the canonical reference as it was missing in the pure form:
$obj = array_column($array, null, 'id')['one'] ?? false;
The false is per the questions requirement to return false. It represents the non-matching value, e.g. you can make it null for example as an alternative suggestion.
This works transparently since PHP 7.0. In case you (still) have an older version, there are user-space implementations of it that can be used as a drop-in replacement.
However array_column also means to copy a whole array. This might not be wanted.
Instead it could be used to index the array and then map over with array_flip:
$index = array_column($array, 'id');
$map = array_flip($index);
$obj = $array[$map['one'] ?? null] ?? false;
On the index the search problem might still be the same, the map just offers the index in the original array so there is a reference system.
Keep in mind thought that this might not be necessary as PHP has copy-on-write. So there might be less duplication as intentionally thought. So this is to show some options.
Another option is to go through the whole array and unless the object is already found, check for a match. One way to do this is with array_reduce:
$obj = array_reduce($array, static function ($carry, $item) {
return $carry === false && $item->id === 'one' ? $item : $carry;
}, false);
This variant again is with the returning false requirement for no-match.
It is a bit more straight forward with null:
$obj = array_reduce($array, static function ($carry, $item) {
return $carry ?? ($item->id === 'one' ? $item : $carry);
}, null);
And a different no-match requirement can then be added with $obj = ...) ?? false; for example.
Fully exposing to foreach within a function of its own even has the benefit to directly exit on match:
$result = null;
foreach ($array as $object) {
if ($object->id === 'one') {
$result = $object;
break;
}
}
unset($object);
$obj = $result ?? false;
This is effectively the original answer by hsz, which shows how universally it can be applied.
You can use the function array_search of php like this
$key=array_search("one", array_column(json_decode(json_encode($array),TRUE), 'color'));
var_dump($array[$key]);
i: is the index of item in array
1: is the property value looking for
$arr: Array looking inside
'ID': the property key
$i = array_search(1, array_column($arr, 'ID'));
$element = ($i !== false ? $arr[$i] : null);
Well, you would would have to loop through them and check compare the ID's unless your array is sorted (by ID) in which case you can implement a searching algorithm like binary search or something of that sort to make it quicker.
My suggestion would be to first sort the arrays using a sorting algorithm (binary sort, insertion sort or quick sort) if the array is not sorted already. Then you can implement a search algorithm which should improve performance and I think that's as good as it gets.
http://www.algolist.net/Algorithms/Binary_search
This is my absolute favorite algorithm for very quickly finding what I need in a very large array, quickly. It is a Binary Search Algorithm implementation I created and use extensively in my PHP code. It hands-down beats straight-forward iterative search routines. You can vary it a multitude of ways to fit your need, but the basic algorithm remains the same.
To use it (this variation), the array must be sorted, by the index you want to find, in lowest-to-highest order.
function quick_find(&$array, $property, $value_to_find, &$first_index) {
$l = 0;
$r = count($array) - 1;
$m = 0;
while ($l <= $r) {
$m = floor(($l + $r) / 2);
if ($array[$m]->{$property} < $value_to_find) {
$l = $m + 1;
} else if ($array[$m]->{$property} > $value_to_find) {
$r = $m - 1;
} else {
$first_index = $m;
return $array[$m];
}
}
return FALSE;
}
And to test it out:
/* Define a class to put into our array of objects */
class test_object {
public $index;
public $whatever_you_want;
public function __construct( $index_to_assign ) {
$this->index = $index_to_assign;
$this->whatever_you_want = rand(1, 10000000);
}
}
/* Initialize an empty array we will fill with our objects */
$my_array = array();
/* Get a random starting index to simulate data (possibly loaded from a database) */
$my_index = rand(1256, 30000);
/* Say we are needing to locate the record with this index */
$index_to_locate = $my_index + rand(200, 30234);
/*
* Fill "$my_array()" with ONE MILLION objects of type "test_object"
*
* 1,000,000 objects may take a little bit to generate. If you don't
* feel patient, you may lower the number!
*
*/
for ($i = 0; $i < 1000000; $i++) {
$searchable_object = new test_object($my_index); // Create the object
array_push($my_array, $searchable_object); // Add it to the "$my_array" array
$my_index++; /* Increment our unique index */
}
echo "Searching array of ".count($my_array)." objects for index: " . $index_to_locate ."\n\n";
$index_found = -1; // Variable into which the array-index at which our object was found will be placed upon return of the function.
$object = quick_find($my_array, "index", $index_to_locate, $index_found);
if ($object == NULL) {
echo "Index $index_to_locate was not contained in the array.\n";
} else {
echo "Object found at index $index_found!\n";
print_r($object);
}
echo "\n\n";
Now, a few notes:
You MAY use this to find non-unique indexes; the array MUST still be sorted in ascending order. Then, when it finds an element matching your criteria, you must walk the array backwards to find the first element, or forward to find the last. It will add a few "hops" to your search, but it will still most likely be faster than iterating a large array.
For STRING indexes, you can change the arithmetic comparisons (i.e. " > " and " < " ) in quick_find() to PHP's function "strcasecmp()". Just make sure the STRING indexes are sorted the same way (for the example implementation): Alphabetically and Ascending.
And if you want to have a version that can search arrays of objects sorted in EITHER ascending OR decending order:
function quick_find_a(&$array, $property, $value_to_find, &$first_index) {
$l = 0;
$r = count($array) - 1;
$m = 0;
while ($l <= $r) {
$m = floor(($l + $r) / 2);
if ($array[$m]->{$property} < $value_to_find) {
$l = $m + 1;
} else if ($array[$m]->{$property} > $value_to_find) {
$r = $m - 1;
} else {
$first_index = $m;
return $array[$m];
}
}
return FALSE;
}
function quick_find_d(&$array, $property, $value_to_find, &$first_index) {
$l = 0;
$r = count($array) - 1;
$m = 0;
while ($l <= $r) {
$m = floor(($l + $r) / 2);
if ($value_to_find > $array[$m]->{$property}) {
$r = $m - 1;
} else if ($value_to_find < $array[$m]->{$property}) {
$l = $m + 1;
} else {
$first_index = $m;
return $array[$m];
}
}
return FALSE;
}
function quick_find(&$array, $property, $value_to_find, &$first_index) {
if ($array[0]->{$property} < $array[count($array)-1]->{$property}) {
return quick_find_a($array, $property, $value_to_find, $first_index);
} else {
return quick_find_d($array, $property, $value_to_find, $first_index);
}
}
The thing with performance of data structures is not only how to get but mostly how to store my data.
If you are free to design your array, use an associative array:
$array['one']->id = 'one';
$array['one']->color = 'white';
$array['two']->id = 'two';
$array['two']->color = 'red';
$array['three']->id = 'three';
$array['three']->color = 'blue';
Finding is then the most cheap: $one = $array['one];
UPDATE:
If you cannot modify your array constitution, you could create a separate array which maps ids to indexes. Finding an object this way does not cost any time:
$map['one'] = 0;
$map['two'] = 1;
$map['three'] = 2;
...
getObjectById() then first lookups the index of the id within the original array and secondly returns the right object:
$index = $map[$id];
return $array[$index];
Something I like to do in these situations is to create a referential array, thus avoiding having to re-copy the object but having the power to use the reference to it like the object itself.
$array['one']->id = 'one';
$array['one']->color = 'white';
$array['two']->id = 'two';
$array['two']->color = 'red';
$array['three']->id = 'three';
$array['three']->color = 'blue';
Then we can create a simple referential array:
$ref = array();
foreach ( $array as $row )
$ref[$row->id] = &$array[$row->id];
Now we can simply test if an instance exists in the array and even use it like the original object if we wanted:
if ( isset( $ref['one'] ) )
echo $ref['one']->color;
would output:
white
If the id in question did not exist, the isset() would return false, so there's no need to iterate the original object over and over looking for a value...we just use PHP's isset() function and avoid using a separate function altogether.
Please note when using references that you want use the "&" with the original array and not the iterator, so using &$row would not give you what you want.
This is definitely not efficient, O(N). But it looks sexy:
$result = array_reduce($array, function ($found, $obj) use ($id) {
return $obj['id'] == $id ? $obj : $found;
}, null);
addendum:
I see hakre already posted something akin to this.
Here is what I use. Reusable functions that loop through an array of objects. The second one allows you to retrieve a single object directly out of all matches (the first one to match criteria).
function get_objects_where($match, $objects) {
if ($match == '' || !is_array($match)) return array ();
$wanted_objects = array ();
foreach ($objects as $object) {
$wanted = false;
foreach ($match as $k => $v) {
if (is_object($object) && isset($object->$k) && $object->$k == $v) {
$wanted = true;
} else {
$wanted = false;
break;
};
};
if ($wanted) $wanted_objects[] = $object;
};
return $wanted_objects;
};
function get_object_where($match, $objects) {
if ($match == '' || !is_array($match)) return (object) array ();
$wanted_objects = get_objects_where($match, $objects);
return count($wanted_objects) > 0 ? $wanted_objects[0] : (object) array ();
};
The easiest way:
function objectToArray($obj) {
return json_decode(json_encode($obj), true);
}