How can I randomly ordering an IEnumerable<>?
I have this IEnumerable :
IEnumerable<MyObject>
and I need to order the list of the MyObject randomly. Do I need to cast into an ArrayList?
Or I can do it directly? Thanks
EDIT
this is my actual random order function :
IList<ArchiePacchettoOfferta> list = new List<ArchiePacchettoOfferta>(m_oEnum);
for (int i = 0; i < list.Count; ++i)
{
HttpContext.Current.Response.Write(list[i].Titolo + "<br />");
}
Rando开发者_运维问答m rnd = new Random();
for (int i = 0; i < list.Count; ++i)
{
int swapIndex = rnd.Next(i + 1);
ArchiePacchettoOfferta tmp = list[i];
list[i] = list[swapIndex];
list[swapIndex] = tmp;
}
for (int i = 0; i < list.Count; ++i)
{
HttpContext.Current.Response.Write(list[i].Titolo + "<br />");
}
it orders the list in the same way every time :(
IEnumerable<int> ints;
var random = new Random();
var shuffled = ints.OrderBy(i => random.Next()).ToList();
The ToList is only there to ensure that the same (random) order is returned when iterating over shuffled more than once. Of course you can shuffle 'inplace' if you don't need the original anymore
ints = ints.OrderBy(i => random.Next()).ToList();
Update
There is some discussion on whether you should rely on OrderBy comparing elements only once. If you don't want to do trust your .NET implementation to do that, spell it out:
var random = new Random();
var shuffled = ints
.Select(i => new { key=random.Next(), i })
.OrderBy(tmp => tmp.key)
.Select(tmp => tmp.i)
.ToList();
See these links for more background on what potential problem this solves (mainly a performance degradation for the current sample, but also the risk of having non-uniform distribution):
- Jon Skeet's blog (section "There may be trouble ahead")
- Shuffle string array without duplicates (that's Eric arguing for the short version)
- Eric Lipperts blog: Shuffling is not sorting (that's the opposite argument)
Enumerators allow "iterated" access only. Thus, there is no possibility to access the elements randomly or in a sorted way. You have to read the enumerated values and (temporarily) store them in another list for which you can apply your (random) sorting algorithm.
[edit] Example:
List<MyObject> list = new List<MyObject>( my_enumerable );
Random rnd = new Random(/* Eventually provide some random seed here. */);
for (int i = list.Count - 1; i > 0; --i)
{
int j = rnd.Next(i + 1);
MyObject tmp = list[i];
list[i] = list[j];
list[j] = tmp;
}
my_enumerable = list;
(I have not tested the example code.)
You can't just cast an IEnumerable<T>
to a different type - and you wouldn't want to convert to the non-generic ArrayList
type anyway.
However, what you can do is read everything into a list (simplest with the ToList
extension method) and then shuffle that. My answer here has an example of the shuffle code - admittedly within an iterator block, but the guts are there.
EDIT: If you're seeing the same ordering every time, I suspect you're creating multiple instances of Random
in a short space of time, and they've all got the same seed.
Read this article for details and workarounds.
精彩评论