I know there are many similar questions here, but I am having trouble implementing it correctly in my code.

I am pulling in id, ip, port and weight from a database and from there I want to be able to select a random ip that has a very low weight (not used recently).

Here is a subset of a result set. The full list is here.

id  ip  port  weight  tries
174  127.0.0.1  3128  906  0
101  127.0.0.1  8080  629  2
123  127.0.0.1  3128  433  3
226  127.0.0.1  3128  393  1
82  127.0.0.1  8080  333  2
252  127.0.0.1  8080  276  3
253  127.0.0.1  3128  209  0
240  127.0.0.1  3129  204  1
249  127.0.0.1  3128  190  0
261  127.0.0.1  8888  165  1
120  127.0.0.1  3128  161  3
188  127.0.0.1  8080  149  0
265  127.0.0.1  8080  108  1
275  127.0.0.1  8080  104  0
63  127.0.0.1  8080  95  2
196  127.0.0.1  8080  79  2
248  127.0.0.1  8080  73  1
223  127.0.0.1  8000  72  3
88  127.0.0.1  3128  69  3
422  127.0.0.1  8080  47  0

Going down the list I have many ip's that just aren't being selected and with a majority few being used over and over again.

Thanks to Yaniro, I came up with a better solution.

My code:

private function _weighted_random_simple($proxies)
{
    foreach ($proxies as $proxy) {
        $weight[] = $proxy['weight'];           
    }

    array_multisort($weight, SORT_ASC, $proxies);

    // Define the custom sort function
    $proxie = array(
        'id' => $proxies[0]['id'], 
        'ip' => $proxies[0]['ip'], 
        'port' => $proxies[0]['port'], 
        'weight' => $proxies[0]['weight'], 
        'tries' => $proxies[0]['tries']
    );

    return $proxie;
}   

Can anyone offer a better piece of code?

Thanks

link|improve this question

1  
How about you just sort the array by the weight in an ascending order and choose the first entry? won't this guarantee you will always pick the least busy server? – Yaniro Mar 1 at 13:56
Why do you want to pick a random one? Couldn't you just use the one with the lowest weight? – Emil Vikström Mar 1 at 14:01
Yaniro and Emil Vikström, yeah I guess I could do that. But what if I have 500 rows with weight 1. Will it always just pick a random one out of that? – PaulM Mar 1 at 14:12
@Yaniro can you make your suggestion an answer. So I can award points. Thanks – PaulM Mar 1 at 15:18
feedback

1 Answer

up vote 0 down vote accepted

You could sort the array by the weight in ascending order and then select the first element which will guarantee the selection of the least busy server.

You code seems fine and you could also use: usort() or uasort() like so:

function cmp( $a, $b )
{
    if ( $a[ 'weight' ] == $b[ 'weight' ] )
    {
        return 0;
    }

    return ( $a[ 'weight' ] < $b[ 'weight' ] ) ? -1 : 1;
}

usort( $fruits, "cmp" );

If you want the comparison function to be a part of you class do something like this:

class YourClass
{
    static function cmp( $a, $b )
    {
        if ( $a[ 'weight' ] == $b[ 'weight' ] )
        {
            return 0;
        }

        return ( $a[ 'weight' ] < $b[ 'weight' ] ) ? -1 : 1;
    }

    private function _weighted_random_simple( $proxies )
    {
        usort( $proxies, array( "YourClass", "cmp" ) );
        return $proxies[ 0 ];
    }
}

Or just loop through the array, find the lowest weight and return its index:

$lowest = -1;
$index  = 0;

for ( $i = 0; $i < count( $proxies ); ++$i )
{
    if ( $proxies[ $i ][ 'weight' ] < $lowest || $lowest == -1 )
    {
        $lowest = $proxies[ $i ][ 'weight' ];
        $index  = $i;
    }
}

return $proxies[ $index ];
link|improve this answer
feedback

Your Answer

 
or
required, but never shown

Not the answer you're looking for? Browse other questions tagged or ask your own question.