Rank system - Determine ranking of multiply objects assigned with two variables - php

I'm sorry if this is a little strange question. I'm trying to determine every object (assigned with two variables [rounds, x]).
Rounds means how many time the object have moved around a track (like a race car?)
x is how far the object is form start (where goal is 750). When the object hits 750 or above the position will reset and add a +1 to its rounds.
I need to determine the placement/rank of every object. Like if we have this:
array("id"=>"object1", "rounds"=>5, "x"=>520)
array("id"=>"object2", "rounds"=>10, "x"=>140)
array("id"=>"object3", "rounds"=>10, "x"=>10)
Here is the ranking:
1. Object 2
2. Object 3
3. Object 1
How do you think is the best way to do this? I have tried any idea i can come up with right now, but i cant figure this out without getting wrong or non existence objects.
Thanks!

As far as I understood you need to sort 2-dimensional array in a custom way.
Try this code:
$array = array(
array('id'=>'object1', 'rounds'=>5, 'x'=>520),
array('id'=>'object2', 'rounds'=>10, 'x'=>140),
array('id'=>'object3', 'rounds'=>10, 'x'=>10),
);
usort($array, function ($a, $b) {
$a['rounds'] * 750 + $a['x'] < $b['rounds'] * 750 + $b['x'];
});
print_r($array);

There's almost certainly a better (more efficient) way, but this should work:
$places = Array(
array("id"=>"object1", "rounds"=>5, "x"=>520),
array("id"=>"object2", "rounds"=>10, "x"=>140),
array("id"=>"object3", "rounds"=>10, "x"=>10)
);
$placesGroupedByRealX = Array();
foreach( $places as $place ) {
/**
* rounds = 750x
*/
$realX = ((int)$place['rounds'] x 750) + $place['x'];
/**
* Make each $placesGroupedByRealX an array for the value of
* $place["rounds"] if it isn't already.
*/
$placesGroupedByRealX[ $realX ] = ( isset($placesGroupedByRealX[ $realX ]))
? $placesGroupedByRealX[ $realX ]
: Array();
// We store into the array to prevent over-writes, even though
// it feels clunky
$placesGroupedByRealX[ $realX ][] = $place;
}
/**
* Order them by realX descending
*/
natsort($placesGroupedByRealX);
$placesGroupedByRealX = array_reverse($placesGroupedByRealX, true);
$results = Array();
/**
* Iterate over the nested arrays and add them a resultset
*/
foreach ( $placesGroupedByRealX as $score => $place ) {
$results[] = $place;
}
//results should now be your places ordered highest to lowest for x and rounds.
$results;

Something like this maybe?
$contestants; = array();
array_push($array1);
array_push($array2);
array_push($array2);
$places = array();
foreach ($contestants as $index => $contestant) {
$distance = ($contestant['rounds'] * 750) + $contestant['x'];
$places[$distance] = $contestant['id'];
};
$result = rsort($places);

Related

Generate a PHP array with 100 tickets and a random number to compare

I am new to symfony and I am trying to make a function that generates a random number and then I want to check this random number in an array of prices. Let's say there are 100 tickets so 100 items in the array. 50 of them are a price "foo" 30 "bar" and 0 "win nothing".
My goals is to populate this array at random so it should look like this:
array(
1=>foo,
2=>foo,
3=>bar,
4=>nothing,
...
)
EDIT
here is what i've tried but doesn't seem to be working. The array is being filled with only the last fill
$prices = array_fill(0, 99, '10');
$prices = array_fill(100, 139, '100');
$prices = array_fill(139, 149, '200');
$prices = array_fill(149, 150, 'reis');
($prices);
I have no idea how to populate my array at random and could use all the help in the world
Any help would be realy awesome!
Thanks in advance!
Your problem can be broken up into two simple parts. First, you need to create an array with an arbitrary number of values, which you could do with a function like this, as per your requirements described above.
function createTickets(Array $items, $totalItems) {
$arr = [];
// populate each item with $quantity
foreach($items as $item => $quantity) {
$arr = array_merge($arr, array_fill(0, $quantity, $item));
}
// fill in the rest with 'nothhing'
$arr = array_merge($arr, array_fill(0, $totalItems - array_sum($items), 'nothing'));
// return the final result
return $arr;
}
So, to create an array of 100 items, with 50 foo and 30 bar, and the rest are nothing, you would do something like this.
$tickets = createTickets(['foo' => 50, 'bar' => 30], 100);
Second, you need to select items at random from the array you created.
The actual order of the elements in the array doesn't matter. You can use something like shuffle to randomize the order of elements in the array, but that's not necessary, because you can always select items from the array at random using array_rand, for example.
// Randomly select an item from the array
$someItem = $tickets[array_rand($tickets)];
Becuase you already know how many items you're creating in the array, you can always supply the amount of random items to extract to array_rand.
// Select 10 items at random
foreach(array_rand($tickets, 10) as $key) {
echo $tickets[$key], "\n"; // do something with item here
}
If you prefer to just shuffle the array because you intend to consume the entire array at random you could just do that instead.
shuffle($tickets);
foreach($tickets as $ticket) {
// now each item is at random
}

sorting arrays - Sorting an array from outside data

I am attempting to make an ordered array based on an unsorted array from an SQL database.
The data that is gotten from the database will look something like this:
Array (
//array ('name', position)
array ('george', 2),
array ('lenny' , 4),
array ('rabbit', 1),
array ('pet' , 3)
)
The idea is to sort the 'names' in an array where position is there place in the array.
What I would like to to end up being:
Array ( 'rabbit', 'george', 'pet', 'lenny' )
The current way I have attempted this is using split_array()
$result is the array from the database.
foreach ( $result as $res ){
$a = array(array($res['name'], $res['position']));
array_splice($finalArray, ($res['position'] - 1), 0, $a);
}
The issue is sometimes depending on the order the users are retrieved it will not sort it properly, is there a better way to do this, or is this good and I am doing it wrong?
Thanks.
Use uasort http://php.net/manual/en/function.uasort.php function where you can pass a user defined comparasion function like this:
$myArray = array(array('bill',3),array('joe',4),array('john',1));
/**
* #desc compare two arrays by the second element
* #param array $a (array to compare with an other)
* #param array $b (array to compare with an other)
* #return int 0|1|-1 equals|first is bigger|second is bigger
*/
function myCompare($a,$b){
if( $a[1] == $b[1] ){
return 0; //if the 2nd elements equals return 0
}
return ( $a[1] > $b[1] )?1:-1; //if the 2nd element of the 1st parameters is bigger returns 1 , else returns -1
}
Usage:
uasort( $myArray, 'myCompare' );
The uasort manipolates the original array in place.
Result:
var_dump($myArray);
array(
array('john',1),
array('bill',3),
array('joe',4)
);
Recommendation:
If you could edit the SQL query , better to short the results in the query with ORDER BY directive like this:
SELECT `name`,`position`
FROM `mytable` #your table name
WHERE 1 #or your conditions here
ORDER BY `position` ASC #ordering directive
This should run faster. And if use this, recommend to add index to position field.

PHP MySQL building a 3 Tier multi dimensional array

So I have my query, its returning results as expect all is swell, except today my designer through in a wrench. Which seems to be throwing me off my game a bit, maybe its cause Im to tired who knows, anyway..
I am to create a 3 tier array
primary category, sub category (which can have multiples per primary), and the item list per sub category which could be 1 to 100 items.
I've tried foreach, while, for loops. All typically starting with $final = array(); then the loop below that.
trying to build arrays like:
$final[$row['primary]][$row['sub']][] = $row['item]
$final[$row['primary]][$row['sub']] = $row['item]
I've tried defining them each as there own array to use array_push() on. And various other tactics and I am failing horribly. I need a fresh minded person to help me out here. From what type of loop would best suit my need to how I can construct my array(s) to build out according to plan.
The Desired outcome would be
array(
primary = array
(
sub = array
(
itemA,
itemB,
itemC
),
sub = array
(
itemA,
itemB,
itemC
),
),
primary = array
(
sub = array
(
itemA,
itemB,
itemC
),
sub = array
(
itemA,
itemB,
itemC
),
),
)
Something like this during treatment of your request :
if (!array_key_exists($row['primary'], $final)) {
$final[$row['primary']] = array();
}
if (!array_key_exists($row['sub'], $final[$row['primary']])) {
$final[$row['primary']][$row['sub']] = array();
}
$final[$row['primary']][$row['sub']][] = $row['item'];
Something like this....
$final =
array(
'Primary1'=>array(
'Sub1'=>array("Item1", "Item2"),
'Sub2'=>array("Item3", "Item4")
),
'Primary2'=>array(
'Sub3'=>array("Item5", "Item6"),
'Sub4'=>array("Item7", "Item8")
),
);
You can do it using array_push but it's not that easy since you really want an associative array and array_push doesn't work well with keys. You could certainly use it to add items to your sub-elements
array_push($final['Primary1']['Sub1'], "Some New Item");
If I understand you correctly, you want to fetch a couple of db relations into an PHP Array.
This is some example code how you can resolve that:
<?php
$output = array();
$i = 0;
// DB Query
while($categories) { // $categories is an db result
$output[$i] = $categories;
$ii = 0;
// DB Query
while($subcategories) { // $subcategories is an db result
$output[$i]['subcategories'][$ii] = $subcategories;
$iii = 0;
// DB Query
while($items) { // $items is an db result
$output[$i]['subcategories'][$ii]['items'][$iii] = $items;
$iii++;
}
$ii++;
}
$i++;
}
print_r($output);
?>

PHP-How To Pair Up items in Array based on condition

How can I pair up items in an array?
Let's say I have an array of Fighters. And I want to pair them up based on their Weights. Fighters with closest weights should be paired as the Best Match. But if they are in the same team they shouldn't be paired.
**---Team 1--**
Fighter A Weight is 60
Fighter B Weight is 65
**--Team 2--**
Fighter C Weight is 62
Fighter D Weight is 60
**--Team 3--**
Fighter E Weight is 64
Fighter F Weight is 66
Output:
Fighter A VS Fighter D
Fighter B VS Fighter F
Fighter C VS Fighter E
I've been researching for this topic and found something similar but not quite:
Random But Unique Pairings, with Conditions
Would really appreciate some help. Thanks in advance!
I liked your question a lot, so I made a full robust version of it.
<?php
header("Content-type: text/plain");
error_reporting(E_ALL);
/**
* #class Fighter
* #property $name string
* #property $weight int
* #property $team string
* #property $paired Fighter Will hold the pointer to the matched Fighter
*/
class Fighter {
public $name;
public $weight;
public $team;
public $paired = null;
public function __construct($name, $weight, $team) {
$this->name = $name;
$this->weight = $weight;
$this->team = $team;
}
}
/**
* #function sortFighters()
*
* #param $a Fighter
* #param $b Fighter
*
* #return int
*/
function sortFighters(Fighter $a, Fighter $b) {
return $a->weight - $b->weight;
}
$fighterList = array(
new Fighter("A", 60, "A"),
new Fighter("B", 65, "A"),
new Fighter("C", 62, "B"),
new Fighter("D", 60, "B"),
new Fighter("E", 64, "C"),
new Fighter("F", 66, "C")
);
usort($fighterList, "sortFighters");
foreach ($fighterList as $fighterOne) {
if ($fighterOne->paired != null) {
continue;
}
echo "Fighter $fighterOne->name vs ";
foreach ($fighterList as $fighterTwo) {
if ($fighterOne->team != $fighterTwo->team && $fighterTwo->paired == null) {
echo $fighterTwo->name . PHP_EOL;
$fighterOne->paired = $fighterTwo;
$fighterTwo->paired = $fighterOne;
break;
}
}
}
First, the fighters are kept in classes, which makes it easier to assign properties to them (if you haven't done so yourself, I urge you to do!)
Make an array of fighters, and assign them names, weights and teams.
sort the array by weight (using usort() and a sorting function sortFighters() to sort by the weight property of each element.
Iterate through the array and match based on:
Fighter one is not already matched
Fighter two is not on the same team as Fighter one
Fighter two is not already matched
When a match is found, store the object pointer of each matching fighters to each other (So it's not null anymore, plus you can access each of fighters' pairs by going to $fighterVariable->paired)
Finally, print the result.
This is just extension of Truth's answer based on comments:
The first thing I'd do differently is basic keeping trace players.
$unassignedPlayers = $fighterList;
Than the algorithm would work in the way: prepare list of teams (if you're using database, use SELECT DISTINCT or GROUP BY teams.id):
$teams = array();
foreach( $fighterList as $fighter){
$teams[] = $figter->team;
}
$teams = array_unique( $teams);
Next we'll need method that will split array of fighters (let's say, we have teams {A,A,B,B,C,C} we want to split that into {A,A}, {B,B,C,C}):
// Don't use string type declaration, it's just ilustrating
function splitFighters( array $input, string $team){
$inteam = array();
$outteam = array();
foreach( $input as $fighter){
if( $figter->team == $team){
$inteam[] = $fighter;
} else {
$outteam[] = $fighter;
}
}
return array( $inteam, $outteam);
}
Now that we do have that, we may create function that will sort team members:
function assignFighters( array &$input, array $teams, array &$output){
// Nothing to work with?
if( !count( $input)){
return true;
}
// No team left and still unassigned players, that fatal error
if( !cont( $teams)){
throw new Exception( 'Unassigned players occurred!');
}
// Shift team
$team = array_shift( $teams);
// Split into in and out team
list( $inteam, $outteam) = splitFighters( $input, $team);
// Inteam is already empty (let's say all players were assigned before)
// Just go deeper (where's DiCaprio?)
if( !count( $inteam) && count( $teams)) {
return assignFighters( $input, $teams, $output)
}
// There're unassigned and nonassignable players in this team
// This is error and we'll have to deal with it later
if( !count($outteam)){
$input = $inteam; // Propagate unassigned players to main
return false;
}
// Sort both teams by fighters weight
// Uses Truth's comparison function
usort($inteam, "sortFighters");
usort($outteam, "sortFighters");
// Fig = Fighter
while( $fig1 = array_shift( $inteam)){
// Are there any players to work with
if( !count( $outteam)){
array_unshift( $inteam, $fig1);
$input = $inteam; // Propagate unassigned players to main
return false;
}
// Assign players to each other
$fig2 = array_shift( $outteam);
$fig1->paired = $fig2;
$fig2->paired = $fig1;
// This will propagate players to main nicely
$output[] = $fig1;
$output[] = $fig2;
}
// Still here? Great! $inteam is empty now
// $outteam contains all remaining players
$input = $outteam;
return assignFighters( $input, $teams,$output);
}
Until this point you could use Truth's algorithm, but this should have better weight matching and represents what you intend more clearly but anyway now comes $unassignedPlayers into work:
$assignedPlayers = array();
$state = assignFighters( $unassignedPlayers, $teams, $assignedPlayers);
// Note:
$state === !(bool)count($unassignedPlayers)
// should evaluate as true, otherwise I'm having an error in algorithm
So what now... If you have $state === false resp. count( $unassignedPlayers) > 0 something went wrong and we need to apply some magic. How will that magic work:
// Keep the trace of swapped players so we don't end up in endless loop
$swappedPlayers = array();
// Browse all unassigned players
while( $fig1 = array_shift( $unassignedPlayers)){
// Store as swapped
$swappedPlayers[] = $fig1;
// At first check whether there's not unassigned player in the different team
// this shouldn't occur in first iteration (all fighters should be from one team
// in the beginning) but this is most effective part of this method
foreach( $unassignedPlayers as $key => $fig2){
if( $fig2->team != $fig1->team){
$fig1->pair = $fig2;
$fig2->pair = $fig1;
continue;
}
}
// No luck, normal magic required
list( $inteam, $outteam) = splitFighters( $assignedPlayers, $fig1->team);
$fig2 = null; // I like my variables initialized, this actually quite important
// Now select someone from $outteam you will want to swap fights with.
// You may either iterate trough all players until you find best weight
// match or select it random, or whatever, I'll go with random,
// it's your job to implement better selection
$i = 1000; // Limit iterations
while(($i--) > 1){
$key1 = array_rand( $outteam, 1);
if( $outteam[$key]->team == $fig1->team){
continue; // No point in swapping fit team member
}
// No recursive swaps
if( in_array( $outteam[$key], $swappedPlayers)){
continue;
}
// This may speed things really up:
// That means we'll get rid of 2 players due to foreach loop at the beggining
// However I'm not sure how this condition will really work
if( $outteam[$key]->pair->team == $fig1->team){
continue;
}
// Store matched fighter
$fig2 = $outteam[$key];
// Unset pair from another fighter
$fig2->pair->pair = null;
// Find the pair in $assignedPlayers and move it to $unassignedPlayers
$key = array_search( $fig2->pair, $assignedPlayers);
if( $key === false){
throw new Exception( 'Cannot find pair player');
}
unset( $assignedPlayers[$key]);
$unassignedPlayers[] = $fig2->pair;
$swappedPlayers[] = $fig2->pair;
// Remove pair from self
$fig2->pair = null;
$swappedPlayers[] = $fig2;
break; // hh, try forgetting this one :)
}
// This shouldn't be happening
if( $fig2 === null){
throw new Exception( 'Didn\'t find good match in 1000 iterations.');
}
// Ok now just make matches as go to the next iteration
$fig1->pair = $fig2;
$fig2->pair = $fig1;
// And store those
$assignedPlayers[] = $fig1;
$assignedPlayers[] = $fig2;
}
I've written all this out of my head (it was challenge), test it and leave notes in comments please :)
Sort the array by weight. You will then have pairs of weights that are close to each other.

Return all page_names in WordPress, without excess?

I need to retrieve an array of every page_name registered in WordPress. I've got two issues, I can do a get_pages() and such, but it literally pulls every freakin thing about each page including their content. Totally unnecessary overhead when all I need is page_name for each.
The other is that I'd like to do it with a built in method if possible, as this is for an in-house plugin and we'd like to keep it compatible with the mainline. (worst case will just access the DB directly and get them) I know you can include/exclude in the get_pages() call, but I haven't figured out if it is possible to exclude retrieving everything but one, instead of the opposite.
It needs to be dynamic in that it cannot have any hard-coded strings i.e. know anything about the pages themselves or what they're called. Also no extra junk like it being in an unordered list or something. Straight up array, no levels needed. (sub-pages are listed same as primary)
Any ideas guys? I've searched and searched..but the documentation is retarded for these types of things as you guys probably know.
Thanks.
Example of what I'd like in the end or similar:
Array
(
[0] => stdClass Object
(
[page_name] => 'page1'
)
[1] => stdClass Object
(
[page_name] => 'page2'
)
[2] => stdClass Object
(
[page_name] => 'page3'
)
[3] => stdClass Object
(
[page_name] => 'page4'
)
)
To limit the fields returned, you can set up a filter. In your themes functions.php file, or a plugin, try
add_filter( 'get_pages', 'get_pages_filter' );
function get_pages_filter( $res ){
$res = array_map( 'get_pages_title', $res );
return $res;
}
function get_pages_title( $item ){
return (object) array( 'page_name' => $item->post_name );
}
$pages = get_pages();
var_dump( $pages );
I checked get_pages() source code and there's no way you can limit what's being requested from a database. Pages are fetched at lines 3177-3184, and as you can see, there's a hardcoded SELECT * FROM query.
If anyone has a clean solution, please chime in. For now I'm just going to use WordPress's built in DB connection and grab them manually.
For the curious...I just threw this together quick...probably not the best..
/**
* get_wpdb_values()
*
* DESC:
*
* Allows you to make a WP Database connection
* and return an Array => Object of what ever
* values you need from a table.
*
* Was made for the purpose of returning a page
* list, but since you pass it the field you
* want returned, along with with optional filters
* it can easily be used for other purposes.
*
* USAGE:
*
* array get_wpdb_values ( string $table [, string $field [, array $filters ]] )
*
* PARAMETERS:
*
* ----------|-----------------------------------------------------------------
* $table | Required table you want to return values from.
* | DO NOT INCLUDE THE WP PREFIX! (e.g. use 'posts' not 'wp_posts'
* ----------|-----------------------------------------------------------------
* $field | Optional field name you want returned. (Default returns * all)
* ----------|-----------------------------------------------------------------
* $filters | Optional filtering passed as field => value array.
* ----------|-----------------------------------------------------------------
*/
function get_wpdb_values( $table = null,
$field = "*",
$filters = null )
{
// Get access to the
// WordPress Database
// class in this scope
global $wpdb;
// If we weren't passed any
// arguments, get out quick
if(is_null($table) || empty($table))
return false;
// Add optional filters if
// they were passed in
if(!is_null($filters))
{
// Counter is so we can tell
// if there is more then one
// filter so we can add the
// AND separator in the
// SQL query
$WHERE = "WHERE ";
$counter = 0;
foreach ($filters as $key => &$value)
{
$counter++;
// If we're on the second or more
// pair, we add the AND to chain
// conditional WHERE's
$AND = ($counter >= 2) ? " AND" : null;
// Append to existing WHERE
// statement
$WHERE .= "$AND $key = '$value' ";
}
}
else
{
// No filters passed
$WHERE = null;
}
// Get WordPress formatted
// table name
$wp_table = $wpdb->$table;
// Putting it all together
$query = "SELECT $field FROM $wp_table $WHERE ";
// Make actual DB call
// through the built in
// MySQL interface for
// WordPress to at least
// attempt to remain
// compatible with mainline
return $wpdb->get_results($query);
}

Categories