首页 > 解决方案 > 从数组列表 C# 检查颜色是否已被使用

问题描述

您好,我想检查我的数组中的某种颜色是否已被使用,那么它将不会再次使用。我正在使用数组中的随机颜色,所以有时它会得到相同的颜色。

// Add random block color
            Color[] colors = new Color[] { Color.Red, Color.Blue, Color.Green, Color.Purple, Color.Black, Color.Aqua };
            Random ra = new Random();
            int rnum = ra.Next(0, 5);
            p.block.brush_color = new SolidBrush(Color.FromArgb(100, colors[rnum]));
// Add new generated process to list
            processes.Add(p);

我怎样才能做到这一点?

标签: c#

解决方案


处理此问题的一种方法是打乱数组中的项目,然后按顺序选择项目。Fisher-Yates shuffle通常被认为是最好的算法:

private static Color[] colors =
{
    Color.Red, Color.Blue, Color.Green, Color.Purple, Color.Black, Color.Aqua
};

private static Random random = new Random();

private static void ShuffleColors()
{
    for (int index = 0; index < colors.Length; index++)
    {
        var randomIndex = index + random.Next(colors.Length - index);
        var temp = colors[randomIndex];
        colors[randomIndex] = colors[index];
        colors[index] = temp;
    }
}

但是当你到达数组的末尾时会发生什么?似乎有3种可能:

  1. 重新从头开始(但你会有一个非随机模式)
  2. 打乱数组并重新从头开始
  3. 随机排列数组,但确保最后使用的颜色不是第一项

我认为最后一个可能更可取,因为它会给出最随机的输出,所以让我们实现那个。

我们可以做的是跟踪我们显示的最后一个索引,然后当它表示数组中的最后一项时,我们可以再次对数组进行洗牌。然后,在我们继续之前,我们要检查以确保数组中的第一项不是我们显示的最后一项。如果是,那么我们将它与其他一些随机元素交换,因此我们永远不会有重复项。

private static int nextIndex = 0;

private static SolidBrush GetNextColoredBrush()
{
    // If we've displayed all the items, shuffle the deck
    if (nextIndex == colors.Length)
    {                
        var lastColorUsed = colors[nextIndex - 1];
        ShuffleColors();

        // If the first color is the same as the last color
        // we displayed, swap it with a random color
        if (colors[0].Name == lastColorUsed.Name)
        {
            var rndIndex = random.Next(1, colors.Length);
            colors[0] = colors[rndIndex];
            colors[rndIndex] = lastColorUsed;
        }

        // Reset our index tracker
        nextIndex = 0;
    }

    // Return the next color and increment our index
    return new SolidBrush(colors[nextIndex++]);
}

现在我们可以在循环中调用这个方法来看看输出会是什么样子:

private static void Main()
{
    // Output our random colors. Note that even though we
    // only we only have 6 colors, they are consistently 
    // output in a random order (but with no duplicates).
    for (int i = 0; i < 20; i++)
    {
        Console.WriteLine(GetNextColoredBrush().Color.ToKnownColor());
    }


    GetKeyFromUser("\nDone! Press any key to exit...");
}

输出

请注意,在显示 6 之前没有重复元素,然后接下来的 6 个元素以不同的顺序排列:

在此处输入图像描述

在您的代码中使用

哦,最后,要在您的代码中使用它,您只需执行以下操作:

p.block.brush_color = GetNextColoredBrush();

但是,您可能会注意到我稍微更改了输出,以便输出KnownColor. 如果要维护原始代码,则应修改GetNextColoredBrush方法中返回值的行:

return new SolidBrush(Color.FromArgb(100, colors[nextIndex++]));

推荐阅读