Ranking within a PHP array - php

I have a seemingly simple ranking-type problem associated with php arrays, unfortunately after much research it has defeated me:
I have a simple array where the keys are names of people and the values are just associated numbers:
$myArray = Array("David"=>36, "James"=>24, "Sarah"=>70, "Mary"=>55);
Here’s the challenge: Given a name, what is their rank within the array? For example: Sarah=rank1; It seems simple because I figured I could just sort the array by the values then loop though to the required name to get the rank. However, weirdly when I sort the array it just unhelpfully returns 1!
print_r(asort($myArray)) = 1 (??)
I suppose I could put the array in an MySQL table but that seems a bit heavy handed. Is anyone aware of a php solution? Where am I going wrong with the sort? I've read the documentation here and it seems asort is the appropriate function (preserves association and sorts on values).
Thanks
The Grinch

(Edited - works now)
Kind of ugly but this should work:
arsort($origArr);
$rankedArr = array_keys($origArr);
foreach ($rankedArr as $rank => $person) {
if ($person == 'Sarah') {
echo $rank + 1;
break;
}
}
What you're doing is first sorting by values, then you're dropping those values and just getting an indexed list of people. Their key value + 1 is their rank. (because first is 0, right?)
EDIT2 - slightly cleaner:
arsort($origArr);
$rankedArr = array_keys($origArr);
$finalRanks = array_flip($rankedArr);
$rank = $finalRanks['Sarah'] + 1;
:-)

asort function returns a boolean and sort the given array as a reference
var_dump(asort($myArray)) = bool(true)
If you print_r($myArray) after this previous line, you'll get your sorted array in $myArray
EDIT: Re-read.
Try doing this to get your ranking numerously:
<?php
/* asort = Lower num to Upper */
asort($myArray);
/* arsort = Upper one to lower */
// arsort($myArray);
$ranks = array_fill(1,count($myArray),'foo');
$ranked = array_combine(array_flip($myArray),array_keys($ranks));
/* Output */
print_r($ranked);
/* Array ( [James] => 1 [David] => 2 [Mary] => 3 [Sarah] => 4 ) */
?>

asort returns bool value, as described here.

Related

PHP sort an array based on another array

I have the following scenario
$elementsInPairs = ["xyz","xxx","yyy","zzz"];
$valuesInPair =[4,2,3,1];
and i need to sort the second array which would give me
[1,2,3,4]
which i can do by
sort($valuesInPair)
but i need the same to happen in first array as well, based on the sorting of the second array
["zzz","xxx","yyy","xyz"];
EDIT
As i had to fix it urgently, i guess i wasn't able to share more information, and the question seemed vague
basically the idea is that i have two sets of arrays, same number of elements in all cases, and they are linked to each other, The second array is a set of order IDs. and first array is set of names,
so in the above example, i have
4 relates to xyz
2 relates to xxx
3 relates to yyy
1 relates to zzz
So i need to sort based on IDs, and have the same order reflect in the first array as well,
so the final result would be,
["zzz","xxx","yyy","xyz"];
which is sorted based on
[1, 2, 3, 4];
Hopefully this clears things above
You can achieve this by using array_multisort method.
array_multisort($valuesInPair, SORT_ASC, $elementsInPair);
Use this below code, this does exactly what you're looking for.
$elementsInPairs = ["xyz","xxx","yyy","zzz"];
$valuesInPair =[4,2,3,1];
$data = array_combine($elementsInPairs,$valuesInPair);
asort($data);
$dumpdata = [];
foreach($data as $x => $x_value) {
$dumpdata[] = $x;
}
print_r($dumpdata);
I hope this helps you.
You kan do like this :
<?php
$elementsInPairs = ["xyz","xxx","yyy","zzz"];
$valuesInPair =[4,2,3,1];
//use [asort][1] - Sort an array in reverse order and maintain index association
asort($valuesInPair);
// and make a new array to sort elementsInPairs
$newelementsInPairs = array();
foreach($valuesInPair as $key=>$val){
$newelementsInPairs[] = $elementsInPairs[$key];
}
print_r(implode(",",$valuesInPair)."\n");
print_r(implode(",",$newelementsInPairs));
/** Output
1,2,3,4
zzz,xxx,yyy,xyz
**/
Hi please combine two array and sort
$newArray =array_combine($valuesInPair,$elementsInPairs);
then sort($newArray);
You can use array_combine(), ksort() and array_values():
<?php
$elementsInPairs = ["xyz","xxx","yyy","zzz"];
$valuesInPair = [4,2,3,1];
$newArray = array_combine($valuesInPair, $elementsInPairs);
ksort($newArray);
$sortedElements = array_values($newArray);
print_r($sortedElements);
will output
Array
(
[0] => zzz
[1] => xxx
[2] => yyy
[3] => xyz
)

How can I count the number of elements each key holds in an associative array in PHP?

I am trying to update the variable $numberOfFoods in a foreach loop with the number of elements that each key holds in an associative array. Here is my code:
$foodsArray = array (
'France' => ['Souffle' , 'Baguette' , 'Fois gras'],
'England' => ['Bangers and mash' , 'Tea and biscuits'],
'America' => ['Hamburger', 'Steak and Eggs', 'Texas chili']
);
$countriesByCuisine = array();
foreach ($foodsArray as $originCountry => $countryAssocFood) {
$numberOfFoods = count(array_values($foodsArray));
for ($countryAssocFoodIndex = 0; $countryAssocFoodIndex < $numberOfFoods; $countryAssocFoodIndex++) {
$countriesByCuisine[$countryAssocFood[$countryAssocFoodIndex]] = $originCountry;
}
}
foreach (array_keys($countriesByCuisine) as $foodFromCountry) {
echo $foodFromCountry . ', From ' . $countriesByCuisine[$foodFromCountry] . '. ';
}
As it is, this code simply sets the $numberOfFoods variable to the integer 3, rather than updating the number to reflect the number of values that the current key holds. My overall goal with this code was to learn how to transform an array such that the values become keys in a new array, with those keys holding their previous keys as values. Please forgive my messy code, as I am pretty new to programming and PHP.
#Robbie Averill is right about array_flip to achieve you "overall goal" of flipping the keys and the values.
There are multiple, more efficient, ways to fix your current code, the best one probably being array_map, but I also want to provide you with why your current code is failing:
The issue is that you are counting $foodsArray for each iteration (and it's always equal to 3), instead of counting $countryAssocFood:
$numberOfFoods = count(array_values($countryAssocFood));

PHP Typecasting an Int as a String - doesn't seem to work as expected

I am trying to calculate percentiles for users in a database. In order to do this I have a $data array that I need to sort.
I have a query object that contains User_ID, Total_User_Orders, and Total_Orders. Here's how the code looks so far:
// Loop through the users
foreach($query->result() as $row)
{
(string)$user_id = (string)$row->user_id;
$data[$user_id] = number_format((($row->total_user_orders/$row->total_orders)*100), 5);
}
// Sort the $data array
array_multisort($data);
print_r($data);
What (I believe) that should do is typecast $row->user_id (an int) as a string. Then, the $data[$user_id] index should be set as a string - right...?
When I sort the array using array_multisort it sorts it as though the index was an Integer, rather than a String. This means it loses the index.
The PHP manual for array_multisort() states, "Associative (string) keys will be maintained, but numeric keys will be re-indexed.". I have also tried using array_multisort($data, SORT_STRING), but the same output occurs. However - it does work when I do $data['#'.$user_id], but this doesn't quite feel like the right solution to me!
Can anyone help? Thanks in advance!
I think you're overcomplicating things. With no testing, I'd think indexing the $data-array like this would work:
$data[(string)$row->user_id] = ...
or
$data[''.$user_id] = ...
EDIT:
Otherwise you could build your array multi-dimensional and sort by one of the indices, like this:
foreach($query->result() as $row) {
$data[] = array(
'user_id' => $row->user_id,
'percent' => number_format((($row->total_user_orders/$row->total_orders)*100), 5);
);
}
Or you could index by the percentage and sort by the keys (using ksort()):
foreach($query->result() as $row) {
$data[number_format((($row->total_user_orders/$row->total_orders)*100), 5)] = $row->user_id];
}
The last solution could be dangerous if several users have the same percentage.
Personally I would probably go with the asort() solution mentioned above.
As described in my comment, array_multisort() is not what you are after here. You don't have multiple arrays or a multi-dimensional array.
To maintain the key => value association in the array and sort the contents use asort().
foreach ($query->result() as $row) {
$percent = ($row->total_user_orders / $row->total_orders) * 100;
$data[$row->user_id] = number_format($percent, 5);
}
asort($data);
If you want descending percentages reverse the array after it's been sorted.
$data = array_reverse($data, true);

how to compare two arrays and find the count of match elements

i have two arrays i.e$ar1=array("Mobile","shop","software","hardware");and$arr2=arry("shop","Mobile","shop","software","shop")
i want to compare the elements of arr2 to arr1 i.e
foreach($arr2 as $val)
{
if(in_array($val, $arr1))
{
//mycode to insert data into mysql table
variable++; // here there should be a variable that must be increamented when ever match found in $arr2 so that it can be saved into another table.
}
$query="update table set shop='$variable',Mobile='$variable'.......";
}
the $variable should be an integer value so that for later use i can use this variable(shop i.e in this example its value should be 3) to find the match.
My question is how can i get the variable that will increamented each time match found.
Sorry, I don't fully understand the purpose of your code. You can use array_intersect to get common values and array_diff to get the unique values when comparing two arrays.
i want to compare the elements of arr2 to arr1 i.e
Then you are essentially doing the same search for shop three times. It's inefficient. Why not sort and eliminate duplicates first?
Other issues. You are comparing arr2 values with the ones in arr1, which means the number of repetation for "shop" will not be 3 it will be one. Doing the opposite might give you the number of repetation of arr1[1] in arr2 =3.
There are multitude of ways to solve this problem. If efficiency is required,you might wish to sort so you don't have to go beyond a certain point (say s). You can learn to use indexes. Infact the whole datastructure is revolved around these kinds of things - from quick and dirty to efficient.
Not sure I understand the connection between your two arrays. But you can use this to count how many items are in your second array:
$items = array("shop","Mobile","shop","software","shop");
$count = array();
foreach($items as $item)
{
if(isset($count[$item]))
{
$count[$item]++;
}
else
{
$count[$item] = 1;
}
}
print_r($count); // Array ( [shop] => 3 [Mobile] => 1 [software] => 1 )

How to properly calculate the amount of levels in an array?

I have a function that has to accept an array of points, or an array of array of points (a 2 or 3 dimensional array). I'm looking for an reliable way to detect whether it has 2 or 3 levels. The thing is, I cannot count on the keys of the arrays to do the checking, so this wont work:
$levels = isset($array[0][0]) && is_array($array[0][0]) ? 3 : 2;
..as the first key might not be 0. It usually is, but I don't want to rely on this. And anyways, it's an crappy and a close minded way to do that. Optimally, I would like to check for any number of levels without having to loop through the whole array.
Here's what the arrays might look like:
array(5) {
[2] => array(2) {
[x] => 3
[y] => 6
}
[3] => array(2) {
[x] => 4
[y] => 8
}
...
And a three dimensional array would contain these arrays.
Some notes:
The arrays are large, so completely looping through the arrays is not a very good option
The arrays are numerically and sequentially indexed (with the exception of the last level, which has x and y)
The array keys might or might not start from 0
While writing this, I came up with a solution that might be feasible; a recursive function that checks the first item of an array, if it is, then call itself on the newly found array etc.
Are there any better, cleaner ideas? Bonus points for supporting arrays that might have both scalar values and arrays (eg. the first item of an array might be a string, but the next is an array).
If you expect a complete array or a complete array of arrays then you could try:-
if (isset $points[0][0][0])
If however your array is sparse its more difficult.
The basic problem is that a php "array" is actually a one dimensional hash. The trick being that a value can be another "array". So you need to access to second level to determine whether its a value or an array.
Again if you expect a given array to contain only point values, or only other arrays you only need to check one entry so:
if ( is_array(current(current($points))) )
Should get you what you want: the current() function returns the current array pointer (which defaults to the first - so it will always be set to something), so the inside current($points) would get you $points[0] or the first entry with an actual value, likwise the outside current will get you something like $points[0][0].
I don't see how you could do this without at least iterating through the array. The simple fact is that any one of the elements in your array could have an additional level. As a result, every element needs to be tested.
That being said, you can still use recursion to improve your code a bit:
/**
* Determine the maximum depth of an array.
* #param $input The object to test. Might be an array, or might be an int (or
* any other object).
* #param $startDepth The starting depth. Will be added as an offset to the
* result.
* #return The depth of the array, plus any initial offset specified in
* $startDepth.
*/
function testDepth($input, $startDepth = 0) {
if (is_array($input)) {
$max = $startDepth;
foreach ($input as $i) {
// Check what the depth of the given element is
$result = testDepth($i, $startDepth + 1);
// We only care about the maximum value
if ($result > $max) {
$max = $result;
}
}
return $max;
} else {
// This isn't an array, so it's assumed not to be a container.
// This doesn't add any depth to the parent array, so just return $startDepth
return $startDepth;
}
}
testDepth($array);
$levels = is_array(current(current($array))) ? 3 : 2;

Categories