1
var r = new Random();
var orderedList = aListOfPeople.OrderBy(x => x.Age).ThenBy(x => r.Next());

What would be a better way of ordering a list by "age" and then by random?

My goal is to make sure that if PersonA age = PersonB age, PersonA will come first on some occasions and PersonB will come first on some other occasions.

Max
  • 2,529
  • 1
  • 18
  • 29
  • 2
    Sorting *by random* isn't sorting, it's shuffling. I think grouping by age and then shuffling the groups might be a better approach. – Matt Burland Jun 01 '15 at 17:31
  • @MattBurland so my goal is to "sort" and then "shuffle" only equal values – Max Jun 01 '15 at 17:35
  • 1
    @Max, see this for shuffle: http://stackoverflow.com/a/375446/961113 – Habib Jun 01 '15 at 17:39
  • Shuffling a list doesn't seems so hard to do but I'd like to preserve the order of the list. I just want to shuffle equal values. Can't get my head around it. – Max Jun 01 '15 at 17:43
  • 1
    If you just sort by `Age`, then you should get the result you are looking for. If the `Age` values are equal, there is no guarantee which order you get them in. – dub stylee Jun 01 '15 at 17:47
  • If I randomly shuffle the list first. And then I order it with OrderBy(x=>x.Age). Will I always get the same results? Ex: PersonA (age=5), PersonB (age=5). Will I some time get PersonA, PersonB and some other time PersonB, PersonA ? – Max Jun 01 '15 at 17:50
  • Best way to find out would be to just try it yourself. Run your program a few times and see what results you get. – dub stylee Jun 01 '15 at 17:51
  • @dubstylee I might be wrong but it seems like I always get the same order when the age values are equal. – Max Jun 01 '15 at 17:52
  • @dubstylee yes, absolutely. I'll try it now with unit tests. I just asked because sometimes there are some tricky things going on under the hood that you don't realize in the first place. Thanks for the answers! – Max Jun 01 '15 at 17:53
  • @Max You are correct. There is a big difference between no guarantees and random. You will quite often get the same results if you just order by age (Until something changes, like a new record inserted, etc). – Robert McKee Jun 02 '15 at 00:26

2 Answers2

1

Using the technique from SQL

var orderedList = aListOfPeople.OrderBy(x => x.Age).ThenBy(x => Guid.NewGuid());

Warning: it is not a true random, just a lazy approach, please refer to comment section of the question

Eric
  • 5,675
  • 16
  • 24
0

The simplest answer is to shuffle and then sort. If you use a stable sort then the sort must preserve the shuffled order for equal-keyed values. However, even though an unstable sort will perturb your shuffle I can't think of any reasonable case in which it could un-shuffle equal-keyed values.

That might be a little inefficient, though...

If you're concerned about collisions I might assume your ages are integer ages in years. In that case you might consider a radix sort (256 bin will be enough for any living human), and when it comes time to stitch the bins back together, you would remove elements from each bin in random order as you append them to the list.

If your list is already sorted by age, and you just want to shuffle in-place, then you just need to iterate through the list, count how many of the following elements are equal, perform an in-place shuffle of that many elements, and then advance to the next non-matching element and repeat.

The latter would be something like this, I think (I'll write in C because I don't know C#):

int i = 0;
while (i < a.length) {
  int j;
  while (a[j] == a[i] && j < a.length) j++;
  while (i + 1 < j) {
    int k = random(j - i) + i;
    swap(a[i], a[k]);
    i++;
  }
  i++;
}

Haven't tested it, but it should give the rough idea.

sh1
  • 4,324
  • 17
  • 30