2

Whats the equivalent for java.util.Collections.shuffle() method for vb.net? I did not find anything similar on MSDN. Help is very much appreciated.

Dobrobobr
  • 8,216
  • 4
  • 17
  • 18
  • I think there's nothing native, but you can check this post. They suggest some solutions there [http://stackoverflow.com/q/554587/2619091](http://stackoverflow.com/q/554587/2619091) – yamilmedina Dec 07 '13 at 17:09

1 Answers1

6

There is (as far as I can tell) no built-in .NET function, but a general equivalent is easily written using Linq:

Function Shuffle(Of T)(collection As IEnumerable(Of T)) As List(Of T)
    Dim r As Random = New Random()
    Shuffle = collection.OrderBy(Function(a) r.Next()).ToList()
End Function

Calling this function assigns a random value to each element in an input list, and then sorts by that random number, returning a new (shuffled) list.

If the collection is an array or derives from IList, a more performant approach could be to use the Fisher-Yates algorithm to shuffle the list in-place:

Sub Shuffle(Of T)(list As IList(Of T))
    Dim r As Random = New Random()
    For i = 0 To list.Count - 1
        Dim index As Integer = r.Next(i, list.Count)
        If i <> index Then
            ' swap list(i) and list(index)
            Dim temp As T = list(i)
            list(i) = list(index)
            list(index) = temp
        End If
    Next
End Sub
drf
  • 8,461
  • 32
  • 50
  • `Calling this function assigns a random value to each element in an input list, and then sorts by that random number` That's not true. It assigns random numbers for elements at each comparison. A shuffle algorithm needs to compare against many elements in a collection more than once, and this will use a different random value each time, which can put the algorithm into a unexpected place. In fact, it's not even guaranteed the sort will ever finish, and this can produce runtime exceptions. Fisher-Yates is **NOT** about performance. It's about correctness, and getting it truly random. – Joel Coehoorn Jan 20 '17 at 15:26
  • *"That's not true. It assigns random numbers for elements at each comparison"*. Actually, it is true and no it doesn't. I've tested that "issue" specifically and it is not an issue. In the case of `OrderBy`, it works as described by @drf, i.e. a single value is generated per item and the list is sorted based on those values. It's when you call a `Sort` method that takes an object or delegate that performs a comparison of two items directly that what you describe becomes an issue. E.g. when passing an `IComparer(Of T)` object or `Comparison(Of T)` delegate. `OrderBy` works just fine this way. – jmcilhinney Sep 17 '18 at 03:10
  • Interesting. Quickly looking at the MSDN documentation, it doesn't seem the `OrderBy` specification addresses the case of nondeterministic sort functions specifically; the reference source seems to show the sort is stable because the internal class `EnumerableSorter` happens to call the key selector once per item. It might be safer to have something along the lines of (in C#) `var r = new Random(); return l.Select(i=>new {Value=i, SortKey = r.Next()}).OrderBy(i=>i.SortKey).Select(i=>i.Value).ToList();`, if only to clarify intent and avoid relying on an implementation detail. – drf Sep 18 '18 at 12:05