【问题标题】:Resolve duplicate issues with while loops and dictionaries解决 while 循环和字典的重复问题
【发布时间】:2019-03-26 01:32:31
【问题描述】:

我有一个项目列表,由玩家在几个输入字段中输入的内容决定,但为了这个示例,假设它包含“a”、“b”、“c”、“d”和“e”。然后将它们分类到一个字典中,其中包含一个数字列表作为值(不重要)。然后我用两个不同的随机变量(i 和 j)随机化字典,以便从字典中取出两个对象并将它们显示到屏幕上,以便玩家可以按下各种相关的按钮。这种情况一直持续到经过 x 圈。 主要问题我遇到的是防止出现半重复,例如“a b”和“b a”。

我尝试将随机对及其半重复项插入另一个字典,然后使用 while 循环语句阻止该字典中的任何对出现。不幸的是,这没有奏效。

下面是我的代码。

public void Start() {
    finalList = new Dictionary<string, int>();
    for (index = 0; index < allNumbers; index++)
    {
        finalList.Add(itemList[index], valueList[index]);
        Debug.Log(finalList[index.ToString()]);
    }
}
public void Update() {
    choose();
}

public void choose() {
    duplicates = new Dictionary<string, string>();
    duplicates.Clear();
    while (rounds < insertNum) {

        key = "(" + itemList[i].ToString() + " " + itemList[j].ToString() + ")";
        reverseKey = "(" + itemList[j].ToString() + " " + itemList[i].ToString() + ")";

        while (j == i || (duplicates.ContainsKey(key) || duplicates.ContainsKey(reverseKey))) {
            i = UnityEngine.Random.Range(0, allNumbers - 1);
            j = UnityEngine.Random.Range(0, allNumbers - 1);
            key = "(" + itemList[i].ToString() + " " + itemList[j].ToString() + ")";
            reverseKey = "(" + itemList[j].ToString() + " " + itemList[i].ToString() + ")";
            Debug.Log("(new keys " + key + ", " + reverseKey + ")");
            //break;
            } while (j == i || (duplicates.ContainsKey(key) && duplicates.ContainsKey(reverseKey)))
            {
                i = UnityEngine.Random.Range(0, allNumbers - 1);
                j = UnityEngine.Random.Range(0, allNumbers - 1);
                key = "(" + itemList[i].ToString() + " " + itemList[j].ToString() + ")";
                reverseKey = "(" + itemList[j].ToString() + " " + itemList[i].ToString() + ")";
                Debug.Log("(new keys " + key + ", " + reverseKey + ")");
            }while (j == i && (duplicates.ContainsKey(key) || dupes.ContainsKey(reverseKey))) {
            i = UnityEngine.Random.Range(0, allNumbers - 1);
            j = UnityEngine.Random.Range(0, allNumbers - 1);
            key = "(" + itemList[i].ToString() + " " + itemList[j].ToString() + ")";
            reverseKey = "(" + itemList[j].ToString() + " " + itemList[i].ToString() + ")";
            Debug.Log("(new keys " + key + ", " + reverseKey + ")");

        }
        while (j == i && (duplicates.ContainsKey(key) && duplicates.ContainsKey(reverseKey))) {
            i = UnityEngine.Random.Range(0, allNumbers - 1);
            j = UnityEngine.Random.Range(0, allNumbers - 1);
            key = "(" + itemList[i].ToString() + " " + itemList[j].ToString() + ")";
            reverseKey = "(" + itemList[j].ToString() + " " + itemList[i].ToString() + ")";
            Debug.Log("(new keys " + key + ", " + reverseKey + ")");
        }
        duplicates.Add(key, "1"); // the one is just a filler variable
        duplicates.Add(reverseKey, "1");
        if (buttonOneBool) { //this is in another script, ignore
            finalList[itemList[i].ToString()] = valueList[i] += 2;
            finalList[itemList[j].ToString()] = valueList[j] -= 2;
            i = UnityEngine.Random.Range(0, n - 1);
            j = UnityEngine.Random.Range(0, n - 1);
        } else if (buttonTwoBool) {
            finalList[itemList[i].ToString()] = valueList[i] -= 2;
            finalList[itemList[j].ToString()] = valueList[j] += 2;
            i = UnityEngine.Random.Range(0, n - 1);
            j = UnityEngine.Random.Range(0, n - 1);
        } else if (buttonThreeBool) {
            finalList[itemList[i].ToString()] = valueList[i] -= 1;
            finalList[itemList[j].ToString()] = valueList[j] -= 1;
            i = UnityEngine.Random.Range(0, n - 1);
            j = UnityEngine.Random.Range(0, n - 1);
        } else if (buttonFourBool) {
            finalList[itemList[i].ToString()] = valueList[i] += 1;
            finalList[itemList[j].ToString()] = valueList[j] += 1;
            i = UnityEngine.Random.Range(0, n - 1);
            j = UnityEngine.Random.Range(0, n - 1);
        }
        break;
    } 

【问题讨论】:

  • 对值进行排序,然后将它们连接起来——所以“a b”变成了“ab”,“b a”变成了“ab”。然后添加到HashSet。如果Add 返回false,那么您之前已经看到过该组合,应该再试一次。
  • @mjwills 你能解释一下如何设置哈希表吗?
  • var g = new HashSet&lt;string&gt;();

标签: c# dictionary input while-loop duplicates


【解决方案1】:

解决此问题的最简单方法是保证i &lt; j。当像这样选择一个新的 i 和 j 时:

i = UnityEngine.Random.Range(min, max); j = UnityEngine.Random.Range(min, max);

改为这样做:

i = UnityEngine.Random.Range(min, max - 1); j = UnityEngine.Random.Range(i + 1, max);

这样做排除了选择先前案例的“镜像”的可能性,也避免了“i == j”的情况。

在这些修改之后,您的 choose() 函数应该如下所示:

    public void choose()
{
    duplicates = new HashSet<string>();
    while (rounds < insertNum)
    {
        key = "(" + itemList[i].ToString() + " " + itemList[j].ToString() + ")";
        while (duplicates.Contains(key))
        {
            i = UnityEngine.Random.Range(0, allNumbers - 2);
            j = UnityEngine.Random.Range(i + 1, allNumbers - 1);
            key = "(" + itemList[i].ToString() + " " + itemList[j].ToString() + ")";
        }
        duplicates.Add(key); // the one is just a filler variable

        if (buttonOneBool) { //bool definitions are in another script, ignore
            finalList[itemList[i].ToString()] = valueList[i] += 2;
            finalList[itemList[j].ToString()] = valueList[j] -= 2;
            i = UnityEngine.Random.Range(0, n - 1);
            j = UnityEngine.Random.Range(0, n - 1);
        } else if (buttonTwoBool) {
            finalList[itemList[i].ToString()] = valueList[i] -= 2;
            finalList[itemList[j].ToString()] = valueList[j] += 2;
            i = UnityEngine.Random.Range(0, n - 1);
            j = UnityEngine.Random.Range(0, n - 1);
        } else if (buttonThreeBool) {
            finalList[itemList[i].ToString()] = valueList[i] -= 1;
            finalList[itemList[j].ToString()] = valueList[j] -= 1;
            i = UnityEngine.Random.Range(0, n - 1);
            j = UnityEngine.Random.Range(0, n - 1);
        } else if (buttonFourBool) {
            finalList[itemList[i].ToString()] = valueList[i] += 1;
            finalList[itemList[j].ToString()] = valueList[j] += 1;
            i = UnityEngine.Random.Range(0, n - 1);
            j = UnityEngine.Random.Range(0, n - 1);
        }
        break;
    }
}

【讨论】:

  • 是否应该在 buttonBools 部分中也更改 i 和 j 值?
  • 根据评论“这是在另一个脚本中,忽略”我不确定这些值是否具有相同的限制。
  • 哈哈,对不起,那是关于布尔的定义。同时,删除“j==i”似乎会调用创建更多重复项。
  • 我的错,j 的最小值应该是“i + 1”,而不是“i”。这将解决“j == i”的情况。
  • 我很难修改按钮案例,因为控制流程难以遵循。例如,外部 while 循环保证最多运行一次,因为最后有 break 语句。
【解决方案2】:

您可以使用以下代码获取列表的两个随机索引。该代码使用整数作为列表类型,适用于任何类型。

List<int> randomList = itemList.Select((x, i) => new { index = i, rand = rand.Next() }).OrderBy(x => x.rand).Select(x => x.index).ToList();

那么列表中的两个随机索引是randomList[0]和randomList[1]。该代码为列表的每个索引 i 分配一个随机数。要从列表中获取两个项目,请使用 itemList[randomList[0]] 和 itemList[randomList[1]]。该代码假定原始列表 ItemList[] 中至少有两个项目。

如果您的原始列表有重复项,则需要使用 Distinct(),如下面的代码所示

        List<int> distinctList = itemList.Distinct().ToList();
        List<int> randomList = distinctList.Select((x, i) => new { index = i, rand = rand.Next() }).OrderBy(x => x.rand).Select(x => x.index).ToList();

【讨论】:

  • 你能澄清一下吗?我的问题不在于我无法获取随机索引。
  • 为什么需要索引?我的代码随机化列表中的值。
  • 我想要它,这样我就可以得到'ab'而不是'b a',但我也希望能够得到'a c',所以过早地将'a'从列表中删除不工作
  • 一旦你使用我的方法随机化你只运行一次算法。那么第一个玩家是索引 0,第二个玩家是索引 1,第三个玩家是索引 2。您还需要建立一个游戏时间表,例如 1 - 2、1 - 3、2 - 3,其中数字是玩家。然后你随机分配一个玩家到一个数字,所以“a”是玩家 2,“b”是玩家 1,“c”是玩家 3。
  • 所以,为了清楚起见,如果我运行程序一次,得到一个结果列表,然后再次运行它,列表会一样吗?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-11-08
  • 1970-01-01
  • 2021-01-03
  • 2016-03-22
  • 2019-07-23
相关资源
最近更新 更多