How can I randomly ordering an IEnumerable<>?

本秂侑毒 提交于 2019-12-23 17:27:34

问题


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 />");
}

Random 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 :(


回答1:


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.)




回答2:


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)



回答3:


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.



来源:https://stackoverflow.com/questions/6569422/how-can-i-randomly-ordering-an-ienumerable

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!