I'm trying to figure out the best way to create an array of sets of randomly selected numbers from a range. So, for instance I have a range of numbers from which to select: 1-100. I want to generate X number of sets of 5 of those numbers WITHOUT DUPLICATES. So, I want to generate something like:
[3, 24, 32, 49, 68]
[2, 18, 43, 76, 98]
[10, 12, 23, 45, 67]
[5, 56, 64, 72, 90]
...
I know how to generate random numbers from a range once, I just am stuck on doing it X number of times without the possibility of duplicate sets.
One way to solve this problem is simply to generate the desired range $arr = range(1, 100), then shuffle it to randomize shuffle($arr) then chunk it to get sets of 5 $sets = array_chunk($arr, 5).
So the final answer:
$arr = range(1, 100); // gives us an array of 100 integers 1-100
shuffle($arr); // randomly orders those integers
$sets = array_chunk($arr, 5); // creats an array of arrays of sets of 5 integers
foreach ($sets as $set) {
echo implode(',', $set), "\n";
}
Gives you something like...
14,24,60,95,86
47,54,10,77,3
11,22,88,80,39
72,46,81,78,59
63,98,52,82,8
79,34,43,13,41
67,33,75,1,2
4,57,84,73,17
32,55,35,18,70
64,85,100,93,71
25,19,26,20,76
99,89,7,87,91
37,97,68,27,5
74,48,65,61,58
45,31,9,30,21
16,56,50,96,90
92,40,6,44,23
28,94,38,83,29
36,62,51,66,15
12,69,49,42,53
Alternative implementation
Another way to solve this problem, that doesn't require writing the entire array into memory at once and then resorting it randomly, would be to use a hashset that tracks all randomly generated integers to prevent duplicates. This gives us the same exact result except that we do both the random number generation and sorting in a single step instead of two. You can also even do the chunking in the same step this way.
Keep in mind, however, that this solution is technically slower since it's in unbounded time (we have to keep guessing if the number already exists).
I'm going to use a generator to implement this solution since it's easier to write than an Iterator pattern.
function randomizeIntegerXRangeChunked($start, $end, $chunks = 5): Generator
{
$inSet = []; // track the integers already in the set
for ($i = $start, $c = 0; $i <= $end; $i++) {
/* solution is in unbounded time */
while (isset($inSet[($n = mt_rand($start, $end))]));
$inSet[$n] = true;
yield $c => $n;
if (!($i % $chunks)) {
$c++;
}
}
}
$arr = [];
foreach (randomizeIntegerXRangeChunked(1, 100, 5) as $chunk => $int) {
$arr[$chunk][] = $int;
}
var_dump($arr);
The output will be similar to...
array(20) {
[0]=>
array(5) {
[0]=>
int(43)
[1]=>
int(52)
[2]=>
int(38)
[3]=>
int(73)
[4]=>
int(55)
}
[1]=>
array(5) {
[0]=>
int(59)
[1]=>
int(3)
[2]=>
int(71)
[3]=>
int(47)
[4]=>
int(50)
}
[2]=>
array(5) {
[0]=>
int(54)
[1]=>
int(19)
[2]=>
int(60)
[3]=>
int(40)
[4]=>
int(5)
}
[3]=>
array(5) {
[0]=>
int(26)
[1]=>
int(46)
[2]=>
int(93)
[3]=>
int(80)
[4]=>
int(63)
}
[4]=>
array(5) {
[0]=>
int(18)
[1]=>
int(45)
[2]=>
int(98)
[3]=>
int(1)
[4]=>
int(72)
}
[5]=>
array(5) {
[0]=>
int(37)
[1]=>
int(97)
[2]=>
int(15)
[3]=>
int(68)
[4]=>
int(8)
}
[6]=>
array(5) {
[0]=>
int(34)
[1]=>
int(14)
[2]=>
int(33)
[3]=>
int(24)
[4]=>
int(65)
}
[7]=>
array(5) {
[0]=>
int(4)
[1]=>
int(16)
[2]=>
int(13)
[3]=>
int(41)
[4]=>
int(86)
}
[8]=>
array(5) {
[0]=>
int(95)
[1]=>
int(12)
[2]=>
int(44)
[3]=>
int(66)
[4]=>
int(83)
}
[9]=>
array(5) {
[0]=>
int(67)
[1]=>
int(48)
[2]=>
int(91)
[3]=>
int(27)
[4]=>
int(79)
}
[10]=>
array(5) {
[0]=>
int(56)
[1]=>
int(25)
[2]=>
int(2)
[3]=>
int(64)
[4]=>
int(78)
}
[11]=>
array(5) {
[0]=>
int(57)
[1]=>
int(17)
[2]=>
int(74)
[3]=>
int(42)
[4]=>
int(69)
}
[12]=>
array(5) {
[0]=>
int(96)
[1]=>
int(20)
[2]=>
int(9)
[3]=>
int(28)
[4]=>
int(7)
}
[13]=>
array(5) {
[0]=>
int(30)
[1]=>
int(75)
[2]=>
int(21)
[3]=>
int(6)
[4]=>
int(89)
}
[14]=>
array(5) {
[0]=>
int(51)
[1]=>
int(36)
[2]=>
int(62)
[3]=>
int(58)
[4]=>
int(23)
}
[15]=>
array(5) {
[0]=>
int(85)
[1]=>
int(32)
[2]=>
int(100)
[3]=>
int(61)
[4]=>
int(49)
}
[16]=>
array(5) {
[0]=>
int(39)
[1]=>
int(87)
[2]=>
int(76)
[3]=>
int(70)
[4]=>
int(22)
}
[17]=>
array(5) {
[0]=>
int(88)
[1]=>
int(77)
[2]=>
int(10)
[3]=>
int(99)
[4]=>
int(53)
}
[18]=>
array(5) {
[0]=>
int(94)
[1]=>
int(35)
[2]=>
int(92)
[3]=>
int(90)
[4]=>
int(84)
}
[19]=>
array(5) {
[0]=>
int(81)
[1]=>
int(82)
[2]=>
int(31)
[3]=>
int(29)
[4]=>
int(11)
}
}
You can try it like this as well.
// Array
$NumberArray = array();
$TempArray = array(); // Used for storing randoms while we check via if statement.
// Loop 5 times.
for ($x=0; $x<=4; $x++) {
// Random Number 1-100
$RandomNumber = rand(1,100);
// We can use Array Push to add to the array and check using in_array.
array_push($TempArray, $RandomNumber);
// Check first thing in temp array and see if its already in number array. (If not then push)
if (!in_array(reset($TempArray), $NumberArray)) {
array_push($NumberArray, reset($TempArray)); // Add to NumberArray
// Clear Temp Array
$TempArray = array();
} else {
// Add to the loop
$x--;
}
}
print_r($NumberArray);
This outputs an array like such:
Array
(
[0] => 32
[1] => 26
[2] => 59
[3] => 96
[4] => 34
)
Why list() method using two array (array of arrays) as values don't work (for one specific array ($subCategories) the list wrap in another array, the other array is output equals before list()).
list method:
list($subCategories, $subCategoriesName) = [$subCategories, $subCategoriesName]; //[array, array]
[$subCategories, $subCategoriesName] are the return of a function
$subCategories before list
array(4) {
[0]=>
array(3) {
["id"]=>
int(1)
["sub_category_name"]=>
string(14) "Industrilizado"
["category_id"]=>
int(1)
}
[1]=>
array(3) {
["id"]=>
int(2)
["sub_category_name"]=>
string(9) "In natura"
["category_id"]=>
int(1)
}
[2]=>
array(3) {
["id"]=>
int(3)
["sub_category_name"]=>
string(13) "Comida pronta"
["category_id"]=>
int(1)
}
[3]=>
array(3) {
["id"]=>
int(4)
["sub_category_name"]=>
string(11) "Desidratado"
["category_id"]=>
int(1)
}
}
$subCategories after list
array(1) {
[0]=>
array(4) {
[0]=>
array(3) {
["id"]=>
int(1)
["sub_category_name"]=>
string(14) "Industrilizado"
["category_id"]=>
int(1)
}
[1]=>
array(3) {
["id"]=>
int(2)
["sub_category_name"]=>
string(9) "In natura"
["category_id"]=>
int(1)
}
[2]=>
array(3) {
["id"]=>
int(3)
["sub_category_name"]=>
string(13) "Comida pronta"
["category_id"]=>
int(1)
}
[3]=>
array(3) {
["id"]=>
int(4)
["sub_category_name"]=>
string(11) "Desidratado"
["category_id"]=>
int(1)
}
}
In this array, I am attempting to extract the value int(2128) from the ["member_count"] key.
array(3) {
["total"]=>
int(1)
["data"]=>
array(1) {
[0]=>
array(17) {
["id"]=>
string(10) "999999999999"
["web_id"]=>
int(421097)
["name"]=>
string(21) "Name Of List"
["date_created"]=>
string(19) "2014-07-14 13:51:01"
["email_type_option"]=>
bool(false)
["use_awesomebar"]=>
bool(true)
["default_from_name"]=>
string(14) "Department Name"
["default_from_email"]=>
string(24) "user#email.com"
["default_subject"]=>
string(0) ""
["default_language"]=>
string(2) "en"
["list_rating"]=>
float(3.5)
["subscribe_url_short"]=>
string(23) "website/4545"
["subscribe_url_long"]=>
string(91) "website"
["beamer_address"]=>
string(47) "key goes here"
["visibility"]=>
string(3) "pub"
["stats"]=>
array(16) {
["member_count"]=>
int(2128)
["unsubscribe_count"]=>
int(20)
["cleaned_count"]=>
int(57)
["member_count_since_send"]=>
int(1)
["unsubscribe_count_since_send"]=>
int(9)
["cleaned_count_since_send"]=>
int(29)
["campaign_count"]=>
int(2)
["grouping_count"]=>
int(1)
["group_count"]=>
int(4)
["merge_var_count"]=>
int(6)
["avg_sub_rate"]=>
int(17)
["avg_unsub_rate"]=>
int(3)
["target_sub_rate"]=>
int(17)
["open_rate"]=>
float(38.672399892502)
["click_rate"]=>
float(14.932747735383)
["date_last_campaign"]=>
string(19) "2014-11-07 19:14:30"
}
["modules"]=>
array(0) {
}
}
}
["errors"]=>
array(0) {
}
}
Here is the PHP that I have so far but I'm unable to get just the value "int(2128)"
foreach($result as $row){
foreach($row[0] as $row1){
echo '<pre>';
var_dump($row1['member_count']);
echo '</pre>';
}
}
The Results I get:
string(1) "6"
NULL
string(1) "F"
string(1) "2"
NULL
NULL
string(1) "B"
string(1) "d"
string(0) ""
string(1) "e"
NULL
string(1) "h"
string(1) "h"
string(1) "u"
string(1) "p"
int(2128)
NULL
I greatly appreciate any help to narrow the results down to just the value "int(2128)".
Thanks.
If you only want the value 2128 use this:
$array['data'][0]['stats']['member_count']
($array is the name of your multidimensional array)
I have a 2D array that looks like this:
array(2) {
[45]=>
array(5) {
[0]=>
int(2)
[1]=>
int(5)
[2]=>
int(1)
[3]=>
int(3)
[4]=>
int(4)
}
[42]=>
array(5) {
[0]=>
int(5)
[1]=>
int(4)
[2]=>
int(3)
[3]=>
int(2)
[4]=>
int(1)
}
}
The key values of the outer array are numerical, but do not start at 0, and are not sequential. I want to sort the outer array by ascending keys, and the inner arrays by ascending values, so I try this:
ksort($arr);
foreach ($arr as $a) {
sort($a);
}
var_dump($arr);
Which sorts the outer array as expected, but doesn't seem to touch the inner arrays at all:
array(2) {
[42]=>
array(5) {
[0]=>
int(5)
[1]=>
int(4)
[2]=>
int(3)
[3]=>
int(2)
[4]=>
int(1)
}
[45]=>
array(5) {
[0]=>
int(2)
[1]=>
int(5)
[2]=>
int(1)
[3]=>
int(3)
[4]=>
int(4)
}
}
Why is this, and how can I achieve what I want? I think it's something to do with the array being nested, because the following works as expected:
$test = array(5,2,3,1,4);
sort($test);
var_dump($test);
array(5) {
[0]=>
int(1)
[1]=>
int(2)
[2]=>
int(3)
[3]=>
int(4)
[4]=>
int(5)
}
foreach iterates over a copy of the array. If you want to modify the actual values, you have to reference them:
// v
foreach ($arr as &$a) {
sort($a);
}
unset($a);
From the documentation:
As of PHP 5, you can easily modify array's elements by preceding $value with &. This will assign reference instead of copying the value.
$GLOBALS["items"] = array('one', 'two', 'three', 'four', 'five' ,'six', 'seven');
$alter = &$GLOBALS["items"]; // Comment this line
foreach($GLOBALS["items"] as $item) {
echo get_item_id();
}
function get_item_id(){
var_dump(key($GLOBALS["items"]));
}
Check output of this code, with commented and uncommented second line.
My result(PHP 5.3.0).
With second line
int(1) int(2) int(3) int(4) int(5) int(6) NULL
Without second line:
int(1) int(1) int(1) int(1) int(1) int(1) int(1)
Why so strange result?
Here is a possible explanation:
We know that foreach always loops over a copy of the array if it is not referenced:
Unless the array is referenced, foreach operates on a copy of the specified array and not the array itself. foreach has some side effects on the array pointer.
That means that the internal pointer of the original array is not changed and key() will always return the same value (as we can see when we comment out the line). And indeed if we do a var_dump($GLOBALS), we get:
["items"]=>
array(7) {
[0]=>
string(3) "one"
[1]=>
string(3) "two"
[2]=>
string(5) "three"
[3]=>
string(4) "four"
[4]=>
string(4) "five"
[5]=>
string(3) "six"
[6]=>
string(5) "seven"
}
(no reference)
But as soon as we generate a reference to the array (with $alter), $GLOBALS['items'] becomes a reference too, because both entries have to point to the same array:
["items"]=>
&array(7) {
[0]=>
string(3) "one"
[1]=>
string(3) "two"
[2]=>
string(5) "three"
[3]=>
string(4) "four"
[4]=>
string(4) "five"
[5]=>
string(3) "six"
[6]=>
string(5) "seven"
}
["alter"]=>
&array(7) {
[0]=>
string(3) "one"
[1]=>
string(3) "two"
[2]=>
string(5) "three"
[3]=>
string(4) "four"
[4]=>
string(4) "five"
[5]=>
string(3) "six"
[6]=>
string(5) "seven"
}
Hence, the foreach loop does iterate over the original array and changes the internal pointer, which affects key().
To sum up: It is a problem with references, not with $GLOBALS.