简体   繁体   English

如何在C#中消除二维数组中的重复项

[英]How to eliminate duplicates in 2D arrays in C#

just started to learn programming and I need 2D array without duplicates.刚开始学习编程,我需要没有重复的二维数组。 This code (well edited for 1D) worked just fine for 1D but doesn't for 2D and have no clue why.这段代码(针对 1D 进行了很好的编辑)对于 1D 工作得很好,但不适用于 2D 并且不知道为什么。 Would be very happy if someone helped me.如果有人帮助我,我会很高兴。 Thanks.谢谢。

        Random r = new Random();
        int[,] array = new int[10, 8];

        for (int i = 0; i < array.GetLength(0); i++)
        {
            for (int j = 0; j < array.GetLength(1); j++)
            {
                array[i, j] = r.Next(10, 100);
                for (int k = 0; k < i; k++)
                {
                    for (int l = 0; l < j; l++)
                    {
                        if (array[i,j] == array[k,l])
                        {
                            i--;
                            j--;
                            break;
                        }
                    }
                }
            }
        }

With the nested j loop you are filling the entire second dimension for each i , but in the k and l loops you are only checking the grid to the upper and left of current cell.使用嵌套的j循环,您可以为每个i填充整个第二维,但在kl循环中,您只检查当前单元格左上角和左上角的网格。 You could place a number twice because you are not checking every previously filled location.您可以将一个数字放置两次,因为您没有检查之前填写的每个位置。

If we change the code to this:如果我们把代码改成这样:

        for (int k = 0; k < array.GetLength(0); k++)
        {
            for (int l = 0; l < array.GetLength(1); l++)
            {
                if (i != k && j != l && array[i, j] == array[k, l])
                {
                    i--;
                    j--;
                    break;
                }
            }
        }

Then you eliminate that problem, but you very quickly find that you get a IndexOutOfRangeException because you're decrementing both i & j at the same time.然后你消除了这个问题,但是你很快发现你得到了一个IndexOutOfRangeException因为你同时减少了ij That's not moving you to the previous value - it's jumping back a whole row and left one cell - and that's ultimately sending i or j to -1 and that's not good.这并没有将您移动到前一个值 - 它跳回一整行并留下一个单元格 - 这最终将ij发送到-1 ,这并不好。

If you want to do it like you're attempting then you need to have a way to simply move back to the previously filled cell, regardless of the row or column you're on.如果你想像你尝试的那样做,那么你需要有一种方法可以简单地移回以前填充的单元格,而不管你在哪一行或哪一列。

Try this:尝试这个:

for (int x = 0; x < array.GetLength(0) * array.GetLength(1); x++)
{
    array[x % array.GetLength(0), x / array.GetLength(0)] = r.Next(10, 100);
    for (int y = 0; y < x; y++)
    {
        if (array[x % array.GetLength(0), x / array.GetLength(0)] == array[y % array.GetLength(0), y / array.GetLength(0)])
        {
            x--;
            break;
        };
    }
}

However, that's not very efficient.但是,这不是很有效。 Try this instead:试试这个:

var values = Enumerable.Range(10, 90).OrderBy(_ => r.Next()).ToArray();

for (int x = 0; x < array.GetLength(0) * array.GetLength(1); x++)
{
    array[x % array.GetLength(0), x / array.GetLength(0)] = values[x];
}

So, first of all, that just seems inefficient.所以,首先,这似乎效率低下。 Not sure why you want to do it this way, but then again, don't know the reason.不知道你为什么要这样做,但话说回来,不知道原因。 Looks like a programming assignment.看起来像一个编程任务。

My guess, you need a sort of double break going on.我的猜测,你需要一种双重休息。 When you break finding a match, you don't break out to the "k" for loop, so you continue looking for a match even though you found one.当您中断查找匹配项时,您不会跳到“k”for 循环,因此即使您找到了匹配项,您仍会继续查找匹配项。 Try setting a boolean value to say it's found, then use that in the criteria for the for loop for k.尝试设置一个布尔值来表示它已找到,然后在 for 循环的标准中使用该值。 That'll break it out and let you start over on the outside loops for i and j.这将打破它,让您重新开始 i 和 j 的外部循环。

Even then, it won't work because you indescriminately subtracted i and j.即使那样,它也不会起作用,因为您不加选择地减去了 i 和 j。 So if you're on position 1,2 you will jump back to 0,1 rather than 1,2.因此,如果您在位置 1,2,您将跳回 0,1 而不是 1,2。 So you need to subtract j, if it drops below 0, then subtract from i and add "array.GetLength(1)" to j.所以你需要减去 j,如果它低于 0,然后从 i 中减去并将“array.GetLength(1)”添加到 j。

This solution depends on HashSet 's property of containing unique elements.此解决方案取决于HashSet包含唯一元素的属性。 It has an Add method that returns false when we try to add existing elements.它有一个Add方法,当我们尝试添加现有元素时,该方法返回false

Random r = new Random();
int[,] array = new int[10, 8];
var usedValues = new HashSet<int>();

for (int i = 0; i < array.GetLength(0); i++)
{
    for (int j = 0; j < array.GetLength(1); j++)
    {
        int uniqueValue;
        while (true)
        {
            uniqueValue = r.Next(10, 100);
            if (usedValues.Add(uniqueValue)) break; // It is unique indeed
            // It is not unique, try again.
        }
        array[i, j] = uniqueValue;
    }
}

The above solution is more suitable when the range of the acceptable unique values is large.当可接受的唯一值范围较大时,上述解决方案更合适。 In this specific case the range is very small (10-99), and the solution offered by @Enigmativity is preferable.在这种特定情况下,范围非常小(10-99),@Enigmativity 提供的解决方案是可取的。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM