LINQ,合并列表与适当的'覆盖'

时间:2010-11-05 22:49:25

标签: c# linq

这种情况可能远比我想要的复杂得多,但无论如何我都是把它带出来的。这适用于游戏型设计。

此处的值是硬编码的,但在实际环境中情况并非如此。

基本上,有一些名为Interpreter的类列表,其中包含在程序引擎中翻译其他内容的相应信息。这些有一个默认的“布局”,但在许多特殊情况下,需要覆盖一些

一个解决方案是在每个列表中都包含每个实例(这是可行的,但我认为它是多余的,我认为存在更清晰的解决方案)相反,我想要“组合”它们,但能够指定属性用作“覆盖”。 (完整的源代码可以在pastie上找到。我会把它放在这里,但我被告知,放上那么多代码会阻止人们回答我的问题):http://www.pastie.org/1276064

public class Program
{
    static void Main()
    {
        var traits = new List<Trait>
        {
            new Trait { Name = "Intellect" },
            new Trait { Name = "Strength" },
            new Trait { Name = "Constitution" }
        };

        var scores = new List<Score>
        {
            new Score { Name = "Beginner", Rank = 1 },
            new Score { Name = "Adept", Rank = 2 },
            new Score { Name = "Expert", Rank = 3 },
            new Score { Name = "Master", Rank = 4 }
        };

        // one sheet will have defaults
        var initial = new Sheet
        {
            Interpreters = new List<Interpreter>
            {
                new Interpreter
                {
                    Trait = traits.Single( s => s.Name == "Intellect" ),
                    Score = scores.Single( s => s.Rank == 1 ),
                    Requirement = 10
                },
                new Interpreter
                {
                    Trait = traits.Single( s => s.Name == "Intellect" ),
                    Score = scores.Single( s => s.Rank == 2 ),
                    Requirement = 20
                },
                new Interpreter
                {
                    Trait = traits.Single( s => s.Name == "Intellect" ),
                    Score = scores.Single( s => s.Rank == 3 ),
                    Requirement = 30
                }
            }
        };

        // other sheets will override some or all of the default
        var advanced = new Sheet
        {
            Interpreters = new List<Interpreter>
            {
                new Interpreter
                {
                    Trait = traits.Single( s => s.Name == "Intellect" ),
                    Score = scores.Single( s => s.Rank == 2 ),
                    Requirement = 15
                },
                new Interpreter
                {
                    Trait = traits.Single( s => s.Name == "Intellect" ),
                    Score = scores.Single( s => s.Rank == 4 ),
                    Requirement = 35
                }
            }
        };

        // combined sheet should have values of default, with the appropriately 'overridden' values of the advanced
    }

在这种情况下,组合列表应该是......

[0]
 Trait = Intellect,
 Score = 1,
 Requirement = 10
[1]
 Trait = Intellect,
 Score = 2,
 Requirement = 15
[2]
 Trait = Intellect,
 Score = 3,
 Requirement = 30
[3]
 Trait = Intellect,
 Score = 4,
 Requirement = 35

我确实知道如何通过这个特定的实例来实现它。我可以简单地编写一个方法来检查分数的值等。但我想要一个更加基于约定的方法,我可以用更复杂的方式使用它。有没有人有任何想法?

1 个答案:

答案 0 :(得分:1)

要获得您描述的结果,您可以使用以下方法:

Sheet Combine(Sheet initial, Sheet advanced)
{
    Sheet result = new Sheet();
    result.Interpreters = new List<Interpreter>(
        initial.Interpreters.Select(i =>
            advanced.Interpreters.SingleOrDefault(a => a.Score == i.Score) ?? i)
        );
    return result;
}

当一个Sheet包含不同的Trait s时,我可能有逻辑错误,但您没有指定如何组合它们。

此外,您的代码设计很奇怪。并非每个集合都必须是List<T>。特别是在这种情况下,使用Dictionary<K,V>比使用Single()更干净(更快)。

修改

对于您的更新版本,我更喜欢基于List的解决方案而不是LINQ:

Sheet Combine(Sheet initial, Sheet advanced)
{
  var interpreters = new List<Interpreter>(initial.Interpreters);
  foreach (var interpreter in advanced.Interpreters)
  {
    int index = interpreters.FindIndex(x => x.Score == interpreter.Score);
    if (index < 0)
      interpreters.Add(interpreter);
    else
      interpreters[index] = interpreter;
  }

  return new Sheet { Interpreters = interpreters };
}

编辑2

以下是您要求的LINQ解决方案:

Sheet Combine(Sheet initial, Sheet advanced)
{
  var scores = initial.Interpreters.Select(i => i.Score)
    .Concat(advanced.Interpreters.Select(i => i.Score))
    .Distinct().OrderBy(i => i);
  var interpreters = scores.Select(s =>
    advanced.Interpreters.SingleOrDefault(i => i.Score == s)
    ?? initial.Interpreters.Single(i => i.Score == s));
  return new Sheet { Interpreters = interpreters };
}