【问题标题】:Using Random class to randomize 2d array使用 Random 类随机化二维数组
【发布时间】:2020-06-14 21:59:26
【问题描述】:

我正在尝试随机化二维数组中的一组预定元素。

using System;

namespace array
{
    public class tiles
    {
        static void Main(string[] args)
        {
            Random random = new Random();
            int[,] tilearr = { { 0, 1, 2 }, { 3, 4, 5 }, { 6, 7, 8 } };

            for (int i = 0; i < 3; i++)
            {
                for (int j = 0; j < 3; j++)
                {
                    Console.Write(tilearr[i, j] + " ");
                }
                Console.WriteLine();
            }

            Console.ReadLine();
        }
    }
}

我的问题是,如果我执行 tilearr[i, j] = random.Next(0, 8); 之类的操作,它会随机化数组,但不关心是否存在相同元素的任何重复项。

2 6 7
1 1 3
2 7 0

我所追求的更像是这样的:

2 4 8  1 3 0
0 3 1  5 6 8 
6 7 5, 2 4 7

【问题讨论】:

  • Shuffle 改为值
  • 您想随机化数组但不重复?
  • 如果您不想重复,您希望以随机顺序放置一组值(或项目)。这叫做 shuffle,这里有成千上万的帖子
  • 这是来自 xanatos 的一个很棒的答案:stackoverflow.com/questions/30164019/…
  • 一个非常简单的洗牌算法是这样的:“指向”最后一个元素。现在在此之前随机选择一个元素。交换这两个元素。然后“指向”倒数第二个元素并在此之前随机选择一个元素并切换这两个元素。依此类推,直到您“指向”第一个元素。

标签: c# arrays random


【解决方案1】:

一个简单而中肯的解决方案是列出一个可用数字列表,然后逐个位置地从列表中随机选择数字。

像这样:

var numbers = new List<int> { 0, 1, 2, 3, 4, 5, 6, 7, 8 };
for(int x = 0; x < 3; ++x) {
    for(int y = 0; y < 3; ++y) {
        // select a random number from the list ...
        int rand = random.Next(0, numbers.Count - 1);
        tilearr[x, y] = numbers[rand];
        // ... and remove it from the list
        numbers.RemoveAt(rand);
    }
}

【讨论】:

    【解决方案2】:

    正如用户Wai Ha Lee 在 cmets 中所述,随机播放将实现您所寻找的。我会推荐 Fisher Yates Shuffle。

    public static void Shuffle<T>(Random random, T[,] array)
    {
        int lengthRow = array.GetLength(1);
    
        for (int i = array.Length - 1; i > 0; i--)
        {
            int i0 = i / lengthRow;
            int i1 = i % lengthRow;
    
            int j = random.Next(i + 1);
            int j0 = j / lengthRow;
            int j1 = j % lengthRow;
    
            T temp = array[i0, i1];
            array[i0, i1] = array[j0, j1];
            array[j0, j1] = temp;
         }
    }
    

    我从这个answer 中检索了这个实现。

    这应该像这样在你的代码中实现,

    using System;
    
    namespace array
    {
        public class tiles
        {
            static void Main(string[] args)
            {
                Random random = new Random();
                int[,] tilearr = { { 0, 1, 2 }, { 3, 4, 5 }, { 6, 7, 8 } };
                Shuffle<int>(random, tilearr);
    
                for (int i = 0; i < 3; i++)
                {
                    for (int j = 0; j < 3; j++)
                    {
                        Console.Write(tilearr[i, j] + " ");
                    }
                    Console.WriteLine();
                }
    
                Console.ReadLine();
            }
        }
    }
    

    确保将 shuffle 通用函数放在您的类中。

    HERE 是我在 dotnetfiddle.net 上实现的一个示例。

    【讨论】:

    • hm 我知道名称数组不存在?我是不是做错了什么?
    • 如果您可以复制确切的错误代码或回溯,它将帮助我理解您的意思。
    • 在随机播放函数public static void Shuffle&lt;T&gt;(Random random, T[,] array) 中说名称数组不存在
    • 我添加了一个我的实现示例尝试该链接中的代码以确保它不是一个简单的错误。
    • 这只是虚拟工作室创建功能的简单错误,出于某种原因它不正确,我处于自动驾驶状态,只是没有检查它是否有问题
    【解决方案3】:

    如果从头开始生成数组,则更容易随机化一维数组,然后将其加载到二维数组中。

    static int[,] GenerateArray(int size)
    {
        Random r = new Random();   
        var arr = new int[size, size];
        var values = Enumerable.Range(0, size * size).OrderBy(x => r.Next()).ToArray();
    
        for (int i = 0; i < size; i++)
            for (int j = 0; j < size; j++)
                arr[i, j] = values[i * size + j];
    
        return arr;
    }
    

    【讨论】:

      【解决方案4】:

      随机化的一种方法是将二维数组展平,将其随机排列,然后根据原始尺寸重新创建。如果您想使用 Linq/Extension 方法,您可以执行以下操作

      Random random = new Random();
      int[,] tilearr = {{ 0, 1, 2 }, { 3, 4, 5 }, { 6, 7, 8 }};
      
      var result = tilearr.OfType<int>()
             .OrderBy(x=> random.Next())
             .ChunkBy(tilearr.GetLength(1))
             .To2DArray();
      
      

      其中 ChunkBy 和 To2DArray 定义为

      public static class Extensions
      {
          public static IEnumerable<IEnumerable<T>> ChunkBy<T>(this IEnumerable<T> source, int chunkSize) 
          {
              return source
                  .Select((x, i) => new { Index = i, Value = x })
                  .GroupBy(x => x.Index / chunkSize)
                  .Select(x => x.Select(v => v.Value));
          }
      
          public static T[,] To2DArray<T>(this IEnumerable<IEnumerable<T>> source)
          {
              var data = source
                  .Select(x => x.ToArray())
                  .ToArray();
      
              var res = new T[data.Length, data.Max(x => x.Length)];
              for (var i = 0; i < data.Length; ++i)
              {
                  for (var j = 0; j < data[i].Length; ++j)
                  {
                      res[i,j] = data[i][j];
                  }
              }
      
              return res;
          }
      }
      

      Sample Demo

      【讨论】:

        猜你喜欢
        • 2016-12-24
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-11-13
        • 1970-01-01
        • 2012-07-27
        相关资源
        最近更新 更多