问题
I would like to pull values from a PHP array at random, without pulling the same value twice before I've pulled all values from the entire array.
In other words, if I have the array...
_____
| foo |
| bar |
| baz |
|_____|
...I want to pull a random value three times without pulling the same value twice, so I could have...
1st: foo foo bar bar baz baz
2nd: bar baz foo baz foo bar
3rd: baz bar baz foo bar foo
...on my three separate pulls.
Now, I realize I could do this by simply removing the selected item from the array--IF I was only pulling from it once. However, that is not the case. I need the array to stay intact because I want to repeat the random pulls all over again once all values have been pulled in a cycle.
To summarize: I want to pull all values iteratively from an array in a random order without duplicates, until all items have been pulled...and then repeat the process indefinitely.
I thought I had this accomplished by inserting each selected value from the PHP array into a MySQL table, and then checking that table for each subsequent array pull (if the pulled value was in the MySQL table, I re-ran the function until I got a never-before-selected value).
This seems to accomplish the get-all-values-without-duplicates goal, but my output became a little funky in some cases.
At any rate, here is my code intended to accomplish the desired effect. I use jQuery (ajax) to call a PHP function every 7 seconds to get a new array value, and stick that value in a MySQL table for future duplication checking. When every available value has been pulled, I truncate the table and start over again.
Javascript (jQuery):
function cycle_facts() {
$.ajax({ url: 'lib/functions.php',
data: {setfact: 'yes'},
type: 'post',
success: function(output) {
$('#header').html(output);
}
});
}
PHP:
function set_fact() {
global $mysqli;
$facts = get_facts(); //gets associative array with desired values to be randomly pulled
/* see if all available values have been pulled, and truncate SQL table if so */
$rows = $mysqli->query('select * from used_facts;');
$rows = $rows->num_rows;
if ($rows == sizeof($facts)) {
$mysqli->query('truncate table used_facts;');
}
$fact = array_rand($facts);
/* see if selected value has already been pulled in this cycle, and rerun function if so */
$try = $mysqli->query('select * from used_facts where fact = \'' . $mysqli->real_escape_string($fact) . '\';');
if ($try->num_rows >= 1) {
set_fact();
}
else {
$mysqli->query('insert into used_facts (fact) values (\'' . $mysqli->real_escape_string($fact) . '\');'); //insert newly selected value into SQL table for future duplication checking
}
echo $fact . '|' . $facts[$fact]; //return selected value to jQuery for display
}
So I can probably use this approach with some tweaking, but the problem itself intrigued me enough to wonder if there was a simpler, more direct approach that fine folks on stackoverflow have used.
Thanks!
回答1:
This will give you each element of the array in a random order without reorganizing the original array
foreach (shuffle($arr) as $elem) {
echo $elem;
}
If you'd like to improve the true randomness of the shuffle, please see the comments for more details. I particularly like Fishes Yates Shuffle but you can do some research an implement whatever you like :)
PHP's shuffle
will reorder the indicies of your array – ie, it mutates the input array.
If you would like to preserve the input array and make a shuffled copy of it, I've taken the time to implement Fisher-Yates "inside-out" algorithm for you.
function pureshuffle (array $xs): array {
$acc = [];
for ($i = 0; $i < count($xs); $i++) {
$j = rand(0, $i);
if ($j != $i) $acc[$i] = $acc[$j];
$acc[$j] = $xs[$i];
}
return $acc;
}
$data = [1,2,3,4,5,6,7];
print_r(pureshuffle($data));
// [2,1,4,6,5,7,3]
print_r($data);
// [1,2,3,4,5,6,7]
Alternatively, you could sort the MySQL result using
ORDER BY RAND()
The performance of this is going to depend on a lot of other factors, but if the query is simple enough and the result is small enough, it shouldn't be an issue.
If you're looking to take this approach, do some quick googling. You'll find lots of information and tricks to optimizing random sorts in SQL.
来源:https://stackoverflow.com/questions/17200180/randomly-iterate-through-array-without-pulling-duplicate-values