1

Im looping through some XML nodes, and say i have between 1 and 200 of these nodes.

How can i "randomly" select a maximum of 10 of these nodes. It has to be as most ten, but as few as 1.

This is what im working with now...

        $i = 0;
        foreach ($butters->users->user as $user) {
            if($i==10) break;
            $id = $user->id;
            $name = $user->screen_name;
            $profimg = $user->profile_image_url;
            echo "things";
            $i++;
        } 

The difficulty is that i don't know how many i will have, but would like the pool from which i select my "random" 10 to be from the entirety of however many are present.

mrpatg
  • 10,001
  • 42
  • 110
  • 169

6 Answers6

5
$randomPool = array_rand ( $butters->users->user, 10 );
lamas
  • 74
  • 2
  • 2
    I don't think this will work, depending on what XML module he is using, as array_rand requires array as first item, however $butters->users->user maybe a DOMNODE::ELEMENT_LIST if you are using the DOM module. Could be wrong though – Psytronic Jan 04 '10 at 08:56
  • What works on foreach will work on array_rand() too, assuming Patrick's given example didn't output an error. – lamas Jan 04 '10 at 09:01
  • It sounds as if the patrick wants 10 as an upper limit on the random elements so you should be passing a random number between 1 and 10 for the second argument of array_rand then you will get a random set of nodes with a length between 1 and 10 – Jeff Beck Jan 04 '10 at 09:05
3

I'd get the 10 random indexes, then loop through those and get the nodes.


$indexes = array();
for($i = 0; $i< 10; $i++){
  $indexes[] = rand(0, $butters->users->length);
}

foreach($indexes as $index){
  $user = $butters->users->item($index);
  //do whatever with $user
}

You'll need to add a check to make sure that you have not already got the index when you add it to the $indexes array.

You could put this into one command, however you may end up with duplicates (unlikely depending on the amount of elements, but possible...

for($i = 0; $i< 10; $i++){
  $user = $butters->users->item(rand(0, $butters->users->length));
  //do something with $user
}
Psytronic
  • 6,043
  • 5
  • 37
  • 56
2

Put all users in an array, shuffle it and grab the first ten items:

$users = array[];
foreach ($butters->users->user as $user) {
    $users[] = &$user;
}
shuffle($users);
$tenRandomUsers = array_slice($users, 0, 10);

Maybe you can shorten the first step with just $users = (array) $butters->users->user.

Gumbo
  • 643,351
  • 109
  • 780
  • 844
0

Create a random object (don't know the PHP specific code) then call it and compare with 10 / (total in the set). This means you should in theory select 10%, however it could be less, and your exiting code stops it from selecting more.

cjk
  • 45,739
  • 9
  • 81
  • 112
0

Assuming you are using SimpleXML, you could use an XPath to get all the users. This will return an array and from that it should be cake.

Something like this should do:

$users  = $xml->xpath('//butters/users/user');
$random = array_rand($users, 10);

Someone might want to correct me on the Xpath though. Doing it from memory

Gordon
  • 312,688
  • 75
  • 539
  • 559
0

if you have some sort of strange self-implemented data structure for $users you might want to use reservior sampling -- Efficiently selecting a set of random elements from a linked list

Community
  • 1
  • 1
Igor Serebryany
  • 3,307
  • 3
  • 29
  • 41