tags:

views:

244

answers:

7

I have a list of objects and I want to reorder them randomly on each request. What is the best way of doing this?

+1  A: 

My favorite solution to shuffling stuff is use an N*log N sort and pass it a sort predicate that returns a random result. It has the nice feature that is can be done with a minimum of new code using building blocks that most languages have handy in even the most striped versions.

BCS
On the other hand a shuffle is only O(n) and is only about 5 lines of code, as shown in other answers. (And can be done just once with generics very easily.)
Jon Skeet
5 lines to 1 line is either not much (only 4 lines) or a lot (80%). Also it's simpler to remember.
BCS
And the other advantage is that the sort might leverage something to get good perf on the swaps so for small n it might be faster.
BCS
+2  A: 

You could use the Fisher-Yates shuffle algorithm which runs in linear-time.

dalle
Produces incorrect results - see http://www.codinghorror.com/blog/archives/001015.html
Gavin Miller
@LFSR: read the article again?
Jimmy
What about Knuth? :(
configurator
+11  A: 

How about some kind of Knuth-Fisher-Yates shuffle algorithm ?

for (int i = cards.Length - 1; i > 0; i--)
{
    int n = rand.Next(i + 1);
    Swap(ref cards[i], ref cards[n]);
}

Code taken from Coding Horror. This is also a recommended reading on how people often do this wrong.

m3rLinEz
Format code as code. But good algorithm.
recursive
@recursive Thanks, I reformat the code.
m3rLinEz
+2  A: 

Let me direct you to one WRONG way of doing it, and a way I confess I used before, and never saw the error of it until this blog post:

http://www.codinghorror.com/blog/archives/001015.html

abelenky
That also shows the *right* way of doing it :)
Jon Skeet
A: 

I would create a new List and filling it with items that are randomly selected and removed from the original List.

Germstorm
+6  A: 

Check out this cool Linq way of doing it:

public class Employee
{
    public int Id
    {
        get;
        set;
    }
    public string Name
    {
        get;
        set;
    }
}

Populate a list:

    List<Employee> list = new List<Employee>();

    list.Add(new Employee { Id = 1, Name = "Davolio Nancy" });
    list.Add(new Employee { Id = 2, Name = "Fuller Andrew" });
    list.Add(new Employee { Id = 3, Name = "Leverling Janet" });
    list.Add(new Employee { Id = 4, Name = "Peacock Margaret" });
    list.Add(new Employee { Id = 5, Name = "Buchanan Steven" });
    list.Add(new Employee { Id = 6, Name = "Suyama Michael" });
    list.Add(new Employee { Id = 7, Name = "King Robert" });
    list.Add(new Employee { Id = 8, Name = "Callahan Laura" });
    list.Add(new Employee { Id = 9, Name = "Dodsworth Anne" });

Then sort:

    list = list.OrderBy(emp => Guid.NewGuid()).ToList();

Credit

BFree
Not exactly fast, but friggen awesome.
Will
Who cares about performance when you can whip out your big LINQ stick and show others you're better than them? :-P
BFree
Just remember that GUID's are **NOT** to be treated as random numbers for crypto purposes. They'll work for this kind of thing, but they're not interchangeable.
clintp
Goddamn right! Until we HAVE a requirement for doing it fast, that is.
Will
http://msdn.microsoft.com/en-us/library/system.security.cryptography.rngcryptoserviceprovider.aspx use a class similar to the example code to generate a cryptographically random number rather than using NewGuid(). No word on performance on this, tho.
Will
Linq rules. I think would take a random number over a GUID though.
Mark Maxham
A: 

Try this code here

It uses the IComparer.Compare

It will be a good practice if you do the function using generics

Geries Handal