在 for 循环中调用具有相似名称的不同列表

Call different list with similar name in a for loop

我有几个带有名称的列表:group1、group2、group3... 我需要一个 for 循环(比如说 for (int i=1; i<=6; i++),现在我检查例如如果我是 1 然后使用 group1,如果我是 2 使用 group2 等......我的问题是,我可以用最后的'i'来调用列表吗?像groupi,当i为1时,它的group1,当i为2时,它的group2等。这是代码:

for (int i = 0; i < groupNum; i++)
{
    if (i == 0)
    {
        foreach (Player p1 in group1)
        {
            foreach (Player p2 in group1)
            {
                if (p1 != p2)
                {
                    if (group1.IndexOf(p1) > group1.IndexOf(p2))
                    {
                        Game game = new Game(tournamentID, p1.id, p2.id);
                        game.status = "Pending";
                        gm.CreateGame(game);
                    }
                }
            }
        }
    }

    else if (i == 1)
    {
        foreach (Player p1 in group2)
        {
            foreach (Player p2 in group2)
            {
                if (p1 != p2)
                {
                    if (group2.IndexOf(p1) > group2.IndexOf(p2))
                    {
                        Game game = new Game(tournamentID, p1.id, p2.id);
                        game.status = "Pending";
                        gm.CreateGame(game);
                    }
                }
            }
        }
    }

    else if (i == 2)
    {
        foreach (Player p1 in group3)
        {
            foreach (Player p2 in group3)
            {
                if (p1 != p2)
                {
                    if (group3.IndexOf(p1) > group3.IndexOf(p2))
                    {
                        Game game = new Game(tournamentID, p1.id, p2.id);
                        game.status = "Pending";
                        gm.CreateGame(game);
                    }
                }
            }
        }
    }

    else if (i == 3)
    {
        foreach (Player p1 in group4)
        {
            foreach (Player p2 in group4)
            {
                if (p1 != p2)
                {
                    if (group4.IndexOf(p1) > group4.IndexOf(p2))
                    {
                        Game game = new Game(tournamentID, p1.id, p2.id);
                        game.status = "Pending";
                        gm.CreateGame(game);
                    }
                }
            }
        }
    }

    else if (i == 4)
    {
        foreach (Player p1 in group5)
        {
            foreach (Player p2 in group5)
            {
                if (p1 != p2)
                {
                    if (group5.IndexOf(p1) > group5.IndexOf(p2))
                    {
                        Game game = new Game(tournamentID, p1.id, p2.id);
                        game.status = "Pending";
                        gm.CreateGame(game);
                    }
                }
            }
        }
    }

    else if (i == 5)
    {
        foreach (Player p1 in group6)
        {
            foreach (Player p2 in group6)
            {
                if (p1 != p2)
                {
                    if (group6.IndexOf(p1) > group6.IndexOf(p2))
                    {
                        Game game = new Game(tournamentID, p1.id, p2.id);
                        game.status = "Pending";
                        gm.CreateGame(game);
                    }
                }
            }
        }
    }

如您所见,不同 if 语句的代码实际上是相同的,但唯一的区别在于使用具有相似名称(group1、group2..)的不同列表。

创建群组列表

 var groups = new List<Group>(){
     group1, group1, group3};

现在你可以做

  if(group[i].Indexof.....)

等等

只需将您的组组成一个数组,假设它们在下面 List<Player>,然后对其进行迭代:

foreach(var grp in new List<Player>[] {group1, group2, group3, group4, group5, group6}) {
    foreach (Player p1 in grp)
    {
        foreach (Player p2 in grp)
        {
            if (p1 != p2)
            {
                if (grp.IndexOf(p1) > grp.IndexOf(p2))
                {
                    Game game = new Game(tournamentID, p1.id, p2.id);
                    game.status = "Pending";
                    gm.CreateGame(game);
                }
            }
        }
    }
}

一般

这经常出现。不;您不能以编程方式构建变量名。编译代码时,变量名无论如何都消失了

如果你的变量名字像

something1
something2
something3

等,那么这是使用数组的候选,但记住数组从 0

开始
var something = new Thing[3];

(在你的例子中,Thing 是一个玩家)

现在您的名字可以有一个固定部分和一个可变部分:

Before you had    Now you have
--------------    ------------
something1        something[0]
something2        something[1]
something3        something[2]

数组可以用 forforeach 循环,并且可以像上面那样用硬编码索引随机访问它们。就像您的代码只有 3 个名为 somethingX 的变量一样,您的数组也有固定数量的 3 个值。数组不增长

如果您需要像数组一样工作但会增长的东西,请使用列表:

var something = new List<Thing>();

这是一个 Thing 列表,就像之前您有一个 Thing 数组一样。


另外,不要忘记字典,它们就像列表一样,会增长,但它们可以被任何东西索引,所以你可以通过编程方式建立索引,不像 arrays/lists 那样被索引通过递增整数,字典可以跳过一些索引:

var dict = new Dictionary<int, Thing>();

这意味着“由 int 索引并包含 Thing 的字典”

现在,这是可能的:

dict[1] = new Thing();
dict[2] = new Thing();
dict[4] = new Thing(); //we skipped

键可以是任何东西,例如字符串:

var dict = new Dictionary<string, Thing>();
dict["something1"] = new Thing();
dict["something2"] = new Thing();
dict["sometheng4"] = new Thing(); //watch out for typos!

您可以通过编程方式构建密钥:

int x = 1;
dict["something"+x].SomePropertyOfThing = "Hello";

唯一需要注意的是字典不一定以任何顺序存储它的内容。如果您 foreach 它,您可能会以 something2, sometheng4, something1 顺序输出条目。如果您需要排序,您要么必须对 dict.Keys 进行排序,然后使用它来访问字典,要么根据您的需要使用 SortedDictionary 或 OrderedDictionary


综上所述,这些是我们在 C# 中使用的主要集合类型;他们有不同的长处和短处,在某种情况下选择使用哪一个通常是一个重要的工程决策

最后一点注意事项;在处理集合时尽量使用复数名称,因为它使代码更容易推理

具体在这种情况下

在您的特定情况下,您实际上是在寻找一个数组数组,而一些 LINQ 可能会使您的代码更易于处理:

var groups = new []{ group1, group2, group3 };

foreach(var g in groups)
  foreach(var p1 in g)
    foreach(var p2 in g.Where(p => p.id > p1.id)) 
      gm.CreateGame(new Game(tournamentID, p1.id, p2.id){status = "Pending"});

如果您只想为特定组 N 举办一场锦标赛,请将 foreach(var g in groups) 替换为 var g = groups[N]


你有这样的逻辑“对于每个玩家 1,对于每个玩家 2,如果他们不是同一个玩家,找到玩家 1 的索引,找到玩家 2 的索引,如果一个索引小于两个索引”包含冗余逻辑,浪费资源寻找它已经找到的东西

说“对于组中的每一个 player1,对于每一个 id 大于 player1 的 player2”就可以解决所有问题。玩家 2 必须与玩家 1 不同,因为他们的 id 更大。无需查找索引;您可以将代码简化为比较 ID,而不是进行 notequals 检查然后查找索引然后比较

如果您的 ID 值由于某种原因在大于意义上本质上不具有可比性(我假设它们是整数),您可以使用更多的 linq 为组中的每个玩家 p 分配一个索引 i:

var groups = new []{
  group1.Select((p,i) => (p,i)),
  group2.Select((p,i) => (p,i)),
  group3.Select((p,i) => (p,i))
};

这会生成玩家的元组以及他们所在的索引,因此可以使用与之前类似的逻辑:

foreach(var g in groups)
  foreach(var p1t in g)
    foreach(var p2t in g.Where(pt => pt.i > p1t.i)) 
      gm.CreateGame(new Game(tournamentID, p1t.p.id, p2t.p.id){status = "Pending"});

这次 Where 要求玩家 2 的索引 i 更大

您应该使用 PascalCase 命名您的属性,而不是 camelCase

如前所述,您可以将所有组收集在一个数组中,然后遍历该组数组:

List<Player>[] groups = new[] { group1, group2, group3, group4, group5, group6 };

foreach (var group in groups)
{
    // play games
}

我也想建议简化您的逻辑。您可以使用更少的嵌套循环来实现相同的结果,只需在每个组中循环 player 1player 2 的必要组合。

一种方法是:

  • 遍历玩家列表索引而不是列表中的 Player 对象(即将嵌套 foreach (Player p*) 循环替换为嵌套 for (int i*)(玩家索引)循环)
  • 让外层循环(遍历 玩家 1 的索引)从 0 迭代当前组到 second-to-last-index
  • 让内部循环(遍历 玩家 2 的索引)从 一个比 [=51= 的索引大的索引遍历当前组]玩家1到最后一个索引

实施:

foreach (var group in groups)
{
    for (int i1 = 0; i1 < group.Count - 1; i1++)
    {
        Player p1 = group[i1];

        for (int i2 = i1 + 1; i2 < group.Count; i2++)
        {
            Player p2 = group[i2];

            Game game = new Game(tournamentID, p1.id, p2.id);
            game.status = "Pending";
            gm.CreateGame(game);
        }
    }
}

如果我们将 player 1 的索引简单地称为 1player 2 简单地表示为 2,包含四个玩家的组的迭代可以可视化如下:

1 2 _ _
1 _ 2 _
1 _ _ 2

_ 1 2 _
_ 1 _ 2

_ _ 1 2


如果您更希望按照与原始 post 完全相同的玩家组合顺序创建游戏,则需要更改索引条件,以便 p2 始终出现在组中 p1 之前:

2 1 _ _

2 _ 1 _
_ 2 1 _

2 _ _ 1
_ 2 _ 1
_ _ 2 1

这可以通过稍微改变 for loop 语句来实现:

  • 玩家 1 的索引从 1 到组中的最后一个索引
  • 玩家 2 的索引从 0 变为 玩家 1[=72] 小一个索引=]
foreach (var group in groups)
{
    for (var i1 = 1; i1 < group.Count; i1++)
    {
        //

        for (var i2 = 0; i2 < i1; i2++)
        {
            //
        }
    }
}

为确保您不会尝试对任何组执行无效循环,您可以更改 foreach 语句以考虑每个组的长度;通过使用 System.Linq 命名空间中的 .Skip(1).Any()

//using System.Linq;

foreach (var group in groups.Where(gr => gr.Skip(1).Any()))
{
    // play games
}

或计算每组中的项目数:

foreach (var group in groups.Where(gr => gr.Count > 1))
{
    // play games
}

我们正在检查每组中的项目数是否大于 1(即项目数至少为 2),因为我们想同时与两个玩家玩游戏。