你如何随机遍历一个没有重复的二维数组?

How do you randomly iterate through a 2D array with no duplicates?

您通常会使用两个 for 循环遍历二维数组:

For i = 0 to 5
   For j = 0 to 5
      Console.Writeline(Arr(i,j))
   Next
Next

我需要遍历 2D 数组(具有方形边 - 两边的长度相同,即 5x5 7x7 等),但我需要完全随机地进行,并且不重复相同的元素。

For Each i In iRandArr
   For Each j In jRandArr
      Console.Writeline(arr(iRandArr(j), jRandArr(i)))
   Next
Next
'note: the elements i and j are swapped round above in order to maintain the "column", "row" nomenclature

我已经尝试通过将每一边的长度推入一个列表,随机化它(即取消排序,参见 here),然后以相同的双 for 循环方式迭代来做到这一点。不幸的是,这种方法不是随机迭代,而是通过选择随机“列”并随机迭代“行”来进行半随机迭代。唯一的问题是迭代受列元素的限制,因此不是真正随机的(在编程意义上)。

有没有人有我可以尝试的任何其他可能的选择?

这是我评论中的想法的完整编译实现:

  1. 构建一组 对象,表示二维数组中的一个位置
  2. 随机化一维点集
  3. 迭代随机集

请注意,使用自定义点结构的选择是可选的;您可以使用任何您想要的 class/struct 类型,甚至 Tuple。随机化算法也是如此——使用你想要的任何东西。下面的代码只是问题中 link 中相同逻辑的奇特 LINQ 实现。

Option Explicit On
Option Strict On
Option Infer Off
Option Compare Binary

Imports System
Imports System.Collections.Generic
Imports System.Linq

Module Module1

    Sub Main()
        'init an array
        ' this is just for testing purposes;
        ' presumably the 'real' array comes from somewhere else
        Console.WriteLine("Original Array Ordering:")
        Const arrayMaxIndex As Integer = 5
        Dim arr(arrayMaxIndex, arrayMaxIndex) As Integer
        Dim value As Integer = 0
        For row As Integer = 0 To arrayMaxIndex
            For col As Integer = 0 To arrayMaxIndex
                Console.WriteLine($"Row: {row} | Col: {col} | Value: {value}")
                arr(row, col) = value
                value += 1
            Next
        Next

        'build a 1D list of points that refer to array locations
        ' this is written separately from initializing the 2D array on purpose,
        ' since the assumption is that it will be used on an array of unknown origin
        Dim pointList As New List(Of Point)
        For row As Integer = 0 To arr.GetUpperBound(0)
            For col As Integer = 0 To arr.GetUpperBound(1)
                pointList.Add(New Point(row, col))
            Next
        Next

        'randomize the 1D list
        ' choose whatever randomization algorithm you want; this is just one implementation
        Dim rnd As New Random
        Dim randomizedList As IEnumerable(Of Point) = pointList.OrderBy(Function() rnd.Next())

        'step through the randomized 1D list
        Console.WriteLine()
        Console.WriteLine("Randomized Array Ordering:")
        For Each p As Point In randomizedList
            Console.WriteLine($"Row: {p.Row} | Col: {p.Col} | Value: {arr(p.Row, p.Col)}")
        Next

    End Sub

End Module

'use whatever Point type you want
' Didn't want to hard-code to System.Drawing
Friend Structure Point
    Public Sub New(row As Integer, col As Integer)
        _Row = row
        _Col = col
    End Sub

    Public ReadOnly Property Row As Integer
    Public ReadOnly Property Col As Integer
End Structure

示例输出(说明 'randomness' 没有重复):

Original Array Ordering:
Row: 0 | Col: 0 | Value: 0
Row: 0 | Col: 1 | Value: 1
Row: 0 | Col: 2 | Value: 2
Row: 0 | Col: 3 | Value: 3
Row: 0 | Col: 4 | Value: 4
Row: 0 | Col: 5 | Value: 5
Row: 1 | Col: 0 | Value: 6
Row: 1 | Col: 1 | Value: 7
Row: 1 | Col: 2 | Value: 8
Row: 1 | Col: 3 | Value: 9
Row: 1 | Col: 4 | Value: 10
Row: 1 | Col: 5 | Value: 11
Row: 2 | Col: 0 | Value: 12
Row: 2 | Col: 1 | Value: 13
Row: 2 | Col: 2 | Value: 14
Row: 2 | Col: 3 | Value: 15
Row: 2 | Col: 4 | Value: 16
Row: 2 | Col: 5 | Value: 17
Row: 3 | Col: 0 | Value: 18
Row: 3 | Col: 1 | Value: 19
Row: 3 | Col: 2 | Value: 20
Row: 3 | Col: 3 | Value: 21
Row: 3 | Col: 4 | Value: 22
Row: 3 | Col: 5 | Value: 23
Row: 4 | Col: 0 | Value: 24
Row: 4 | Col: 1 | Value: 25
Row: 4 | Col: 2 | Value: 26
Row: 4 | Col: 3 | Value: 27
Row: 4 | Col: 4 | Value: 28
Row: 4 | Col: 5 | Value: 29
Row: 5 | Col: 0 | Value: 30
Row: 5 | Col: 1 | Value: 31
Row: 5 | Col: 2 | Value: 32
Row: 5 | Col: 3 | Value: 33
Row: 5 | Col: 4 | Value: 34
Row: 5 | Col: 5 | Value: 35

Randomized Array Ordering:
Row: 2 | Col: 5 | Value: 17
Row: 3 | Col: 2 | Value: 20
Row: 1 | Col: 0 | Value: 6
Row: 2 | Col: 1 | Value: 13
Row: 4 | Col: 0 | Value: 24
Row: 3 | Col: 5 | Value: 23
Row: 4 | Col: 2 | Value: 26
Row: 5 | Col: 1 | Value: 31
Row: 1 | Col: 5 | Value: 11
Row: 0 | Col: 2 | Value: 2
Row: 4 | Col: 5 | Value: 29
Row: 0 | Col: 5 | Value: 5
Row: 4 | Col: 1 | Value: 25
Row: 3 | Col: 0 | Value: 18
Row: 0 | Col: 4 | Value: 4
Row: 0 | Col: 0 | Value: 0
Row: 1 | Col: 4 | Value: 10
Row: 4 | Col: 3 | Value: 27
Row: 5 | Col: 0 | Value: 30
Row: 2 | Col: 2 | Value: 14
Row: 1 | Col: 1 | Value: 7
Row: 3 | Col: 1 | Value: 19
Row: 2 | Col: 0 | Value: 12
Row: 2 | Col: 4 | Value: 16
Row: 5 | Col: 2 | Value: 32
Row: 0 | Col: 1 | Value: 1
Row: 4 | Col: 4 | Value: 28
Row: 5 | Col: 5 | Value: 35
Row: 1 | Col: 2 | Value: 8
Row: 5 | Col: 4 | Value: 34
Row: 5 | Col: 3 | Value: 33
Row: 1 | Col: 3 | Value: 9
Row: 2 | Col: 3 | Value: 15
Row: 0 | Col: 3 | Value: 3
Row: 3 | Col: 3 | Value: 21
Row: 3 | Col: 4 | Value: 22

P.S。我希望你不要关心这里的性能;这真是一个蛮力实施。

很简单:

Dim Arr As Integer(,) =
    {{ 11, 12, 13 }, { 21, 22, 23 }, { 31, 32, 33 }}

Dim random As New Random

Dim indices = _
        Enumerable _
            .Range(0, 3) _
            .SelectMany(Function(i) _
                Enumerable _
                    .Range(0, 3) _
                    .Select(Function(j) (i, j))) _
            .OrderBy(Function(x) random.Next())
            
For Each x In indices
    Console.Writeline(Arr(x.i, x.j))
Next

这只是生成所有可能的索引对,然后随机打乱它们。这样可以确保没有重复。

在这个例子中我得到:

23
32
22
13
33
12
11
31
21