1

I walk around here with some hesitation, I have passed an array with sub elements (so to speak) and I need three random values ​​but these are obtained without repeating.

The array is as follows:


    Array
    (
        [0] => Array
            (
                [uid] => 1
                [ticket_code] => 0oreb8yo
            )

        [1] => Array
            (
                [uid] => 1
                [ticket_code] => 2oeii8hm
            )

        [2] => Array
            (
                [uid] => 1
                [ticket_code] => m0dwtjiw
            )

        [3] => Array
            (
                [uid] => 1
                [ticket_code] => q6c7cymb
            )

        [4] => Array
            (
                [uid] => 1
                [ticket_code] => zyqhm5bj
            )

        [5] => Array
            (
                [uid] => 1
                [ticket_code] => amdqzjpi
            )

        [6] => Array
            (
                [uid] => 2
                [ticket_code] => tzql7l42
            )

        [7] => Array
            (
                [uid] => 2
                [ticket_code] => gap0r6vf
            )

        [8] => Array
            (
                [uid] => 2
                [ticket_code] => ypqum5yz
            )

        [9] => Array
            (
                [uid] => 4
                [ticket_code] => smupluac
            )

        [10] => Array
            (
                [uid] => 4
                [ticket_code] => 9d8jsha7
            )

        [11] => Array
            (
                [uid] => 5
                [ticket_code] => 6hdnja42
            )

    )

And I need you to get 3 "ticket_code" but no right to repeat the "uid".

I've been on trying as follows, but also repeats the "uid".

$ticketsWinners = array();
  for ($i=0; $i < 3; $i++) {
    $aux = array_rand($allTickets);
    $aux2 = $allTickets[$aux]['uid'];

    $ticketsWinners[] = array(
      'uid' => $aux2,
      'ticket_code' => $allTickets[$aux]['ticket_code']
    );
  }

Any way to do it without repeats?

We thank you in advance if anyone knows of something ^^

Steeep
  • 11
  • 1
  • whats the source of the data? –  Jul 06 '14 at 06:27
  • can you restructure the input array? it would be easier to index by the uid as the key, then array_suffle, unset( uid ) – ArtisticPhoenix Jul 06 '14 at 06:31
  • ^never mind that will un-biased the output, ie. the more tickets purchased the greater the chance of winning should be but only win once maybe the other way, tickets as the the key with users as the data, then array filter with the user id when they win to remove them. – ArtisticPhoenix Jul 06 '14 at 06:36
  • As you mention ArtisiticPhoenix is a raffle system. How could I be so if the array is restructured? – Steeep Jul 06 '14 at 06:40
  • see my answer, and explanation, if you plan to sell a lot of tickets, you will need to reduce the complexity as you remove uids not increase it. – ArtisticPhoenix Jul 06 '14 at 07:17

3 Answers3

1

Try something like:

$ticketsWinners = array();
while (sizeof($ticketsWinners) < 3) {
    $aux = array_rand($allTickets);
    // array_rand return array of keys so you need first value only
    $uid = $allTickets[$aux[0]]['uid']

    // add uid as a key so ass not tot check all $allTickets values
    if (!isset($ticketsWinners[$uid]))
        $ticketsWinners[$uid] = $allTickets[$aux[0]]; 
}
// if you need $allTickets back to numeric keys [0, 1, 2]
$allTickets = array_values($allTickets);

if you're afraid of infinite loops (that can take place really) then try this:

$ticketsWinners = array();
// shuffle array before checking
shuffle($allTickets);
foreach ($allTickets as $tick_data) {
    $uid = $tick_data['uid'];

    if (!isset($ticketsWinners[$uid]))
        $ticketsWinners[$uid] = $tick_data;

    if (sizeof($ticketsWinners) == 3)
        break;
}

Here in worst case you check $allTickets array and get winners of size <= 3.

u_mulder
  • 54,101
  • 5
  • 48
  • 64
0

Try this:

$ticketsWinners = array();
$ticketUid = array();
for ($i=0; $i < 3; $i++) {
    $aux = array_rand($allTickets);
    $aux2 = $allTickets[$aux]['uid'];

    if(! in_array($aux2, $ticketUid)) {
        $ticketUid[$i] = $aux2;

        $ticketsWinners[] = array(
          'uid' => $aux2,
          'ticket_code' => $allTickets[$aux]['ticket_code']
        );
    } else {
        $i--;
    }
}
prava
  • 3,916
  • 2
  • 24
  • 35
  • how many tickets are you selling? to how many people? any idea. – ArtisticPhoenix Jul 06 '14 at 06:59
  • for each ticket you sell you may be adding winners*tickets loops to the operation, so for a small example as this it may be fine but if you sell 10,000 tickets to 100 uids, you could do 100 x previous winners loops assuming each user got 100 tickets, each time a winner is picked. -- had a few extra 0's in there – ArtisticPhoenix Jul 06 '14 at 07:09
0

this structure would be better ( added benefit of ticket numbers being unique )

$tickets = Array
    (
    '0oreb8yo' => 1,              
    '2oeii8hm' => 1,
    'm0dwtjiw' => 1,
    'q6c7cymb' => 1,
     'zyqhm5bj' => 1,
    'amdqzjpi' => 1,
    'tzql7l42' => 2,
    'gap0r6vf' => 2,
    'ypqum5yz' => 2,
    'smupluac' => 3,
    '9d8jsha7' => 4,
    '6hdnja42' => 5,
    );

        $winners = array();
        $picks = 3;
        for($i = 0; $i < $picks; $i++){
if(count($tickets) == 0 ){
break; //or error -- shouldn't need this unless picks exceed uids
}
            $ticket = array_rand($tickets);
            $winner = $tickets[$ticket];
            $winners[] = $winner;
            $tickets = array_filter($tickets, function($item) use ($winner){
                return $winner != $item;
            });
        }

        echo '<pre>';
        var_export($winners);

outputs

array (
  0 => 2,
  1 => 1,
  2 => 4,
)

array (
  0 => 2,
  1 => 1,
  2 => 3,
)

array (
  0 => 1,
  1 => 3,
  2 => 2,
)

unlike the while option, this will reduce the operations for each loop of the for loop by reducing the ticket array by the uid. It's also the only way to insure your not always pulling out a user with tickets, what if user 1 bought 90% of the tickets, you'd loop on him 90% of the time, in any case you have to reduce the ticket array by winners if they can win only once. In essence you remove each uid from the list when they win. You can also be sure that each ticket has the same chance to win ( as well as array_rand is random that is ) - they all have equal footing.

ticket array reduction after loop1

array (
  'tzql7l42' => 2,
  'gap0r6vf' => 2,
  'ypqum5yz' => 2,
  'smupluac' => 3,
  '9d8jsha7' => 4,
  '6hdnja42' => 5,
)

after loop2

array (
  'smupluac' => 3,
  '9d8jsha7' => 4,
  '6hdnja42' => 5,
)

after loop3

array (
  'smupluac' => 3,
  '6hdnja42' => 5,
)

winners

array (
  0 => 1,
  1 => 2,
  2 => 4,
)

to return both the uid and wining ticket change

$winners[] = $winner;

to

$winners[$ticket] = $tickets[$ticket];

now winners will be, just like the input array

ticketnumber => uid

ticket is the key ( which is the ticket ) and winner is the value ( which is the uid )

ArtisticPhoenix
  • 21,464
  • 2
  • 24
  • 38
  • Ok, this works, but it happens that not only need the "uid", but also "ticket_code" as would be checking in that case? What would be the best way to do this? I Speak seeing it on the side of site optimization. – Steeep Jul 06 '14 at 15:27
  • so you need to have returned both the uid and ticket that won, that's easy. – ArtisticPhoenix Jul 06 '14 at 21:26