I would like to display some array data in relation to a competition, each player is ranked by the number of points they have, however if a player has the same amount of points to somebody else they should both have the exact same ranking position.
For instance...
1st Bob 500pts
2nd Joe 350pts
3rd Tom 250pts
3rd Tim 250pts
5th Jay 100pts
In this instance, as Tom & Tim have the exact same number of points they should be joint third, making the next person down 5th (rather than 4th), can anyone suggest the best way to achieve this with a simple array similar to follows
array('Bob' => 500, 'Joe' => '350', 'Tom' => '250', 'Tim' => '250', 'Jay' => '100');
Can anyone suggest the 'cleanest' solution for achieving this
This code will work for you:
$array = array('Bob' => 500, 'Joe' => '350', 'Tom' => '250', 'Tim' => '250', 'Jay' => '100');
arsort($array, SORT_NUMERIC);
$previousPoints = null;
$position = $total = 1;
foreach($array as $name=>$points) {
if ($points != $previousPoints) {
$position = $total;
}
echo $position.' '.$name.' '.$points."\n";
$previousPoints = $points;
$total++;
}
Online demo here.
$ar = array(
'Bob' => 500,
'Tim' => '250',
'Joe' => '350',
'Tom' => '250',
'Jay' => '100'
);
arsort($ar, SORT_NUMERIC);
$i = 1;
$previous = 1;
$previousPosition = 1;
foreach($ar as $k => $v)
{
if($v === $previous)
{
//If the value now is the same as the previous value use the previous position
echo "Position: $previousPosition, $k : $v <br />";
}
else
{
echo "Position: $i, $k : $v <br />";
}
//Previous value
$previous = $v;
//Previous Position
$previousPosition = $i;
//Always increment the value
$i++;
}
Try below code:
$a = array('Bob' => 500, 'Joe' => '350', 'Tom' => '250', 'Tim' => '250', 'Jay' => '100');
arsort($a);
$rank = 1;
$index = 1;
$prevUserPoints = 0;
foreach($a as $name=>$points) {
if($points != $prevUserPoints) {
$rank = $index;
}
$index++;
echo $rank . ' ' . $name . ' ' . $points . "\n";
$prevUserPoints = $points;
}
For displaying 1 as 1st, 2 as 2nd etc, you can use something like below:
function ordSuffix($n) {
$str = "$n";
$t = $n > 9 ? substr($str,-2,1) : 0;
$u = substr($str,-1);
if ($t==1) return $str . 'th';
else switch ($u) {
case 1: return $str . 'st';
case 2: return $str . 'nd';
case 3: return $str . 'rd';
default: return $str . 'th';
}
}
example: echo ordSuffix(23); This prints 23rd
Just a basic and alternative point of view you might want to consider.
$arr = [
"Joe" => "350",
"Tom" => "250",
"Jay" => "200",
"Tim" => "250",
"Bob" => "500",
"John" => "250" ,
"Paul" => "251.40"
];
$rank = array();
array_walk($arr,function($v, $k) use (&$rank)
{
if(isset($rank[$v]))
{
$rank[$v][$k] = $v;
asort($rank[$v]); //alphabetical order John, Tim, Tom
} else
{
$rank[$v] = array($k => $v);
}
});
krsort($rank);
var_dump(array_values($rank));
Related
My array is
$rank = [
'20' => 1,
'30' => 1,
'40' => 2,
'50' => 2,
'60' =>3,
];
expected op
$rank = ['30' => 1,'20' => 1,'50' => 2,'40' => 2,'60' =>3];
I want ranking random means only rank 1(value) should shuffle, later rank 2 should shuffle. later 3 and so on.. how to do it this in PHP?
function shuffle_array($list) {
if (!is_array($list)) return $list;
$keys = array_keys($list);
shuffle($keys);
$random = array();
foreach ($keys as $key) {
$random[$key] = $list[$key];
}
return $random;
}
echo "<pre>"; print_r(shuffle_array($rank));
First step can be to collect all values(say roll numbers) in an array( say a set) grouped by ranks nicely.
Now, get all the unique ranks from your array.
Sort the ranks(skip this step and just run a for loop starting from 1 if ranks are sequential).
Loop over this unique ranks and get all roll numbers according to the rank in hand.
Shuffle() them and add all of them to your result.
Snippet:
<?php
function getRandomizedSortedData($ranks){
$rank_set = [];
foreach($ranks as $roll_no => $rank){
if(!isset($rank_set[ $rank ])){
$rank_set[$rank] = [];
}
$rank_set[$rank][] = $roll_no;
}
$unique_ranks = array_unique($ranks);
sort($unique_ranks);
$result = [];
foreach($unique_ranks as $rank){
$roll_nos = $rank_set[$rank];
shuffle($roll_nos);
foreach($roll_nos as $roll_no){
$result[$roll_no] = $rank;
}
}
return $result;
}
Demo: http://sandbox.onlinephpfunctions.com/code/86c0ead227a06dda5c048dc9316c53788838bd65
you can use php function array_filter():
$rank = [
'20' => 1,
'30' => 2,
'40' => 3,
'50' => 2,
'60' => 1,
];
function filterRank1($value) {
return $value === 1;
}
function filterRank2($value) {
return $value === 2;
}
...
$rank1 = array_filter($rank, 'filterRank1');
$rank2 = array_filter($rank, 'filterRank2');
...
I have two array, and want to have queueing system in third array in php
Array 1
3
4
5
6
7
Array 2
24 => U //Unavailable
39 => A //Available
55 => A //Available
77 => A //Available
Result expected:-
So in Array 3 I want the one's that are Available
Array 3
39 => 3
55 => 4
77 => 5
Also the data from Array 1 should get deleted once it is assigned to Array 3.
Array 1 should become
6
7
Let me know. Thanks in advance.
I would start with the numbers from $array2 which are available.
$availables = [];
foreach ($array2 as $key => $value) {
if ($value == 'A') $availables[] = $key;
}
Now we have two arrays: $availables and $array1 one, and we need to combine them where one represents the keys and the other the values of the new array. You would do this with this function:
http://nl1.php.net/manual/en/function.array-combine.php
The only thing we need to be careful about is the size of the arrays, so:
$size1 = count($array1);
$size2 = count($availables);
if ($size1 > $size2) $array1 = array_slice($array1,0,$size2);
if ($size2 > $size1) $availables = array_slice($availables,0,$size1);
and then we can combine them:
$array3 = array_combine($availables,$array1);
See: https://eval.in/1056040
It would be better to put this in a function or a method, so that changes in the arrays don't affect the original arrays.
There are, of course, lot's of other ways to do the last two steps, for instance:
$array3 = [];
foreach ($array1 as $key => $number)
{
if (!isset($availables[$key])) break;
$array3[$availables[$key]] = $number;
}
See: https://eval.in/1056044
foreach($array[1] as $key => $value){
if($value === 'A') $array[2][$key] = $value;
}
I would do something like this:
<?php
$quee = range(1, 100);
$stations = ['1' => ['status' => 'A', 'client' => ''], '2' => ['status' => 'A', 'client' => ''], '3' => ['status' => 'U', 'client' => null], '4' => ['status' => 'A', 'client' => '']];
while ($quee) {
foreach ($stations as $name => &$station) {
if ($station['status'] === 'U') {
echo 'Station ' . $name . ' is busy' . PHP_EOL;
$station['status'] = 'A';
} else {
$station['status'] = 'U';
$client = array_shift($quee);
if ($client != null) {
$station['client'] = $client;
echo 'Im doing client ' . $client . ' on station ' . $name . PHP_EOL;
} else {
break;
}
}
}
}
I have an array like this
array:32 [▼
"ID" => "7917"
"ProvinceCode" => "MB"
"Create" => "2016-05-18 18:16:26.790"
"DayOfTheWeek" => "4"
"Giai1" => "28192"
"Giai2" => "83509"
"Giai3" => "51911-02858"
"Giai4" => "14102-97270-96025-08465-89047-45904"
"Giai5" => "7892-9140-4069-8499"
"Giai6" => "6117-7471-5541-9119-4855-0566"
"Giai7" => "843-860-023"
"Giai8" => "71-13-55-89"
"Giai9" => ""
"Status" => "1"
]
I have a int variable $position = 59, and my job is find value by counting characters from Giai1 to Giai9 for 59 times count from 0 and get value of this position not include character -, so if $position = 59 then the getted value at position 58 will return.
For example, find value at position 20, the return is 1 at 14102 in Giai4 (actually 19 count from 0)
I've been wrote this code to do this
$position = 59;
$count = 0;
foreach ($data['result'][0] as $key => $item)
{
if(preg_match('#Giai#s', $key))
{
$_item = str_replace('-', '', $item);
$count = $count + strlen($_item);
$chars = str_split($item);
$chars_sp = array_count_values($chars);
$countChar = count($chars);
if($count > $position)
{
//this block contains needed position
$math = $count - $position;
$secmath = strlen($_item) - $math;
for($i=$secmath;$i>=0;$i--){
if($chars[$i] == '-'){
$splash_last++;
}
}
$secmath = $secmath + $splash_last;
if($chars[$secmath] == '-'){
echo "+1 - ";
$secmath = $secmath + 1;
}
echo "Count: $count Match: $math Secmatch: $secmath Splash_last: $splash_last";
$chars[$secmath] = 'x' . $chars[$secmath] . 'y';
$edited = implode('', $chars);
$data['result'][0][$key] = $edited;
break;
}
}
}
dd($data['result'][0]);
}
Expected result will return this array with the mark of getted number.
For example, code found number at position 59 (58 from 0) and signed it by x at first and y at end of value. You can see this in Giai5
//This is expected result
//Result array with mark of value at needed position
array:32 [▼
"ID" => "7917"
"ProvinceCode" => "MB"
"Create" => "2016-05-18 18:16:26.790"
"DayOfTheWeek" => "4"
"Giai1" => "28192"
"Giai2" => "83509"
"Giai3" => "51911-02858"
"Giai4" => "14102-97270-96025-08465-89047-45904"
"Giai5" => "7892-9140-x4y069-8499"
"Giai6" => "6117-7471-5541-9119-4855-0566"
"Giai7" => "843-860-023"
"Giai8" => "71-13-55-89"
"Giai9" => ""
"Status" => "1"
]
from 1 to 50 it works fine, but after position 50, the value of position I get is always wrong
Any idea?
If I understood you correctly this time, you can do something like this:
$array = [
"ID" => "7917",
"ProvinceCode" => "MB",
"Create" => "2016-05-18 18:16:26.790",
"DayOfTheWeek" => "4",
"Giai1" => "28192",
"Giai2" => "83509",
"Giai3" => "51911-02858",
"Giai4" => "14102-97270-96025-08465-89047-45904",
"Giai5" => "7892-9140-4069-8499",
"Giai6" => "6117-7471-5541-9119-4855-0566",
"Giai7" => "843-860-023",
"Giai8" => "71-13-55-89",
"Giai9" => "",
"Status" => "1"
];
$position = 59;
$start = 0;
$end = 0;
foreach ($array as $key => &$value) {
if (!preg_match('/Giai/', $key)) {
continue;
}
$start = $end + 1;
$end = $start + strlen(str_replace('-', '', $value)) - 1;
if (($start <= $position) && ($position <= $end)) {
$counter = $start;
$value = str_split($value);
foreach ($value as &$char) {
if ($char === '-') {
continue;
}
if ($counter === $position) {
$char = "x{$char}y";
break;
}
$counter++;
}
$value = join($value);
}
}
var_dump($array);
Here is demo.
The code is a bit lengthy, but this is due to the fact that when you watch for the position you skip the dashes (-), but when you need to mark the character you have to take them into account. From this code you can understand the algorithm and then refactor code the way you want. I would suggest to escape from nested loops, as they are hard to read. You can do this by breaking code into functions or use the available array functions.
You can achieve this with a simple array_grep() to fetch all the "Giai" keys and implode to concatenate the values to one big string, then selecting a position of that string.
$giai = array_flip(preg_grep("/^Giai\d+$/", array_flip($a)));
echo implode("",$giai)[$pos];
https://eval.in/573746
How can I merge this three arrays
$name ={"Tom", "John", "David"};
$v1 = {"Tom":100, "David":200};
$v2 = {"John":500, "Tom":400};
into one multidimensional associative array in two different ways?
One way is the key order should be same as that of array "name".
$name_merged_original_order = array (
"Tom" => Array(
"v1" => 100,
"v2" => 400
),
"John" => Array(
"v1" => "N/A",
"v2" => 500
),
"David" => Array(
"v1" => 100,
"v2" => "N/A"
)
)
Another ways is the alphabetical of array "name":
$name_merged_asc = array (
"David" => Array(
"v1" => 100,
"v2" => "N/A"
),
"John" => Array(
"v1" => "N/A",
"v2" => 200
),
"Tom" => Array(
"v1" => 100,
"v2" => 400
),
)
The tricky part is that array "v1" and "v2" is not ordered as the key of "name." They also don't have all keys as in "name." Thanks!
It's not tested and the easiest solution:
$name_merged_original_order = array();
foreach($name as $key){
$name_merged_original_order[$key] = array();
if(array_key_exists($key, $v1)){
$name_merged_original_order[$key]['v1'] = $v1[$key];
}
else{
$name_merged_original_order[$key]['v1'] = 'N/A';
}
if(array_key_exists($key, $v2)){
$name_merged_original_order[$key]['v2'] = $v2[$key];
}
else{
$name_merged_original_order[$key]['v2'] = 'N/A';
}
}
sort($name);
$name_merged_asc = array();
foreach($name as $key){
$name_merged_asc[$key] = array();
if(array_key_exists($key, $v1)){
$name_merged_asc[$key]['v1'] = $v1[$key];
}
else{
$name_merged_asc[$key]['v1'] = 'N/A';
}
if(array_key_exists($key, $v2)){
$name_merged_asc[$key]['v2'] = $v2[$key];
}
else{
$name_merged_asc[$key]['v2'] = 'N/A';
}
}
As I understand you would like something like that:
$name = array("Tom", "John", "David");
$result = array();
$v1 = array("Tom" => "200", "John" => "100", "David" => "10");
$v2 = array("Tom" => "254", "David" => "156");
$vars = array("v1", "v2");
foreach($name as $n)
{
$result[$n] = array();
foreach($vars as $v)
{
if(array_key_exists($n, ${$v}))
$result[$n][$v] = ${$v}[$n];
}
}
I hope $result is what you need.
For Example, you have these arrays:
<?php
$FirstArrays = array('a', 'b', 'c', 'd');
$SecArrays = array('1', '2', '3', '4');
1)
foreach($FirstArrays as $index => $value) {
echo $FirstArrays[$index].$SecArrays[$index];
echo "<br/>";
}
or 2)
for ($index = 0 ; $index < count($FirstArrays); $index ++) {
echo $FirstArrays[$index] . $SecArrays[$index];
echo "<br/>";
}
Assume from your comments you only want items that match in all 3 arrays:
for( $i=0; $i< count($name) ; $i++){
if( !empty( $v1[ $name[$i]]) && !empty( $v2[ $name[$i]]) ){
$newArray[$name[$i]]= array( 'v1'=> $v1[ $name[$i]], 'v2'=> $v2[ $name[$i]]):
}
}
To sort:
asort($newArray);
I'm working on a leader board that pulls the top scorers into first, second, and third place based on points. Right now I'm working with a sorted array that looks like this (but could be of infinite length with infinite point values):
$scores = Array
(
["bob"] => 20
["Jane"] => 20
["Jill"] => 15
["John"] => 10
["Jacob"] => 5
)
I imagine I could use a simple slice or chunk, but I'd like to allow for ties, and ignore any points that don't fit into the top three places, like so:
$first = Array
(
["bob"] => 20
["Jane"] => 20
)
$second = Array
(
["Jill"] => 15
)
$third = Array
(
["John"] => 10
)
Any ideas?
$arr = array(
"Jacob" => 5,
"bob" => 20,
"Jane" => 20,
"Jill" => 15,
"John" => 10,
);
arsort($arr);
$output = array();
foreach($arr as $name=>$score)
{
$output[$score][$name] = $score;
if (count($output)>3)
{
array_pop($output);
break;
}
}
$output = array_values($output);
var_dump($output);
$first will be in $output[0], $second in $output[1] and so on.. Code is limited to 3 first places.
ps: updated to deal with tie on the third place
I would do something like:
function chunk_top_n($scores, $limit)
{
arsort($scores);
$current_score = null;
$rank = array();
$n = 0;
foreach ($scores as $person => $score)
{
if ($current_score != $score)
{
if ($n++ == $limit) break;
$current_score = $score;
$rank[] = array();
$p = &$rank[$n - 1];
}
$p[$person] = $score;
}
return $rank;
}
It sorts the array, then creates numbered groups. It breaks as soon as the limit has been reached.
You can do it with less code if you use the score as the key of the array, but the benefit of the above approach is it creates the array exactly how you want it the first time through.
You could also pass $scores by reference if you don't mind the original getting sorted.
Here's my go at it:
<?php
function array_split_value($array)
{
$result = array();
$indexes = array();
foreach ($array as $key => $value)
{
if (!in_array($value, $indexes))
{
$indexes[] = $value;
$result[] = array($key => $value);
}
else
{
$index_search = array_search($value, $indexes);
$result[$index_search] = array_merge($result[$index_search], array($key => $value));
}
}
return $result;
}
$scores = Array(
'bob' => 20,
'Jane' => 20,
'Jill' => 15,
'John' => 10,
'Jacob' => 5
);
echo '<pre>';
print_r(array_split_value($scores));
echo '</pre>';
?>