【问题标题】:How to keep initializer list order within Select and/or SelectMany如何在 Select 和/或 SelectMany 中保持初始化列表顺序
【发布时间】:2016-10-03 19:38:45
【问题描述】:

我希望这不是重复的,但我无法找到答案。 这似乎是我不希望的行为或缺少知识。

我有一个平台和配置对象列表。两者都包含一个成员字符串 CodeName。 CodeNames 列表如下所示:

dbContext.Platforms.Select(x => x.CodeName) => {"test", "PC", "Nintendo"}
dbContext.Configurations.Select(x => x.CodeName) => {"debug", "release"}

它们是从 MySQL 数据库中获得的,因此是 dbContext 对象。

这是我要在 LINQ 中翻译的简单代码,因为 2 foreach 已成为过去:

var choiceList = new List<List<string>>();
foreach (Platform platform in dbContext.Platforms.ToList())
{
    foreach (Configuration configuration in dbContext.Configurations.ToList())
    {
        choiceList.Add(new List<string>() { platform.CodeName, configuration.CodeName });
    }
}

这段代码给出了我想要的,首先保留平台名称,如下所示:

var results = new List<List<string>>() {
{"test", "debug"},
{"test", "release"},
{"PC", "debug"}
{"PC", "release"}
{"Nintendo", "debug"}
{"Nintendo", "release"}};

但如果我把它翻译成这个,我的列表会以不同的顺序包含项目:

var choiceList = dbContext.Platforms.SelectMany(p => dbContext.Configurations.Select(t => new List<string>() { p.CodeName, t.CodeName })).ToList();

我会这样结束,平台名称并不总是第一个,这不是我们想要的:

var results = new List<List<string>>() {
{"debug", "test"},
{"release", "test"},
{"debug", "PC"}
{"PC", "release"}
{"debug", "Nintendo"}
{"Nintendo", "release"}};

我的问题是,是否有可能使用 LINQ 获得所需的结果?

如果我不清楚或我的问题缺少某些细节,请告诉我。 谢谢

编辑:所以 Ivan 找到了解释,因此我修改了我的代码。 实际上,只有 SelectMany 前面的 Enumerable 需要 .ToList()。 我还应该提到我一直需要一个列表>。

感谢大家的快速输入,非常感谢。

【问题讨论】:

  • @DStanley 您希望在 SQL 中生成代码的有序结构是什么?我希望它会用这两个元素创建一个新包,因为这几乎是 SQL 真正使用的唯一集合,除非明确排序,否则它本质上是无序的。
  • 在没有 ToList 的情况下尝试 2 个 foreach 循环,您将看到相同的行为。

标签: c# linq


【解决方案1】:

当你使用

var choiceList = dbContext.Platforms.SelectMany(p => dbContext.Configurations.Select(t => new List<string>() { p.CodeName, t.CodeName })).ToList();

它实际上被转换为一些 SQL 查询,其中返回记录的顺序在您不使用 ORDER BY 时未定义。

要获得与嵌套循环相同的结果,请执行并具体化两个查询,然后在内存中执行 SelectMany

var platforms = dbContext.Platforms.ToList();
var configurations = dbContext.Configurations.ToList();
var choiceList = platforms.SelectMany(p => configurations,
    (p, c) => new List<string>() { p.CodeName, c.CodeName })
    .ToList();

【讨论】:

  • 我认为 OP 的 2 个 foreach 循环似乎正在工作,因为他在那里有 ToList。
  • @sachin 确实。
  • @IvanStoev 是的,我记得我在别处读过一些关于这个的东西。由于我的字符串列表,我从没想过它可以适用于我的情况。所以我只是做了几个测试,你是完全正确的。事实上,如果我们要精确的话,只有 SelectMany 前面的 Enumerable 需要 ToList。
  • @christ.s 实际上外部查询(platforms)可能只是AsEnumerable(),但内部查询(configurations)确实需要ToList并提前存储到变量中,否则它将为每个外部记录执行 db 查询,这是没有意义的(并且性能会受到影响)。
【解决方案2】:

与其将其投影到数组中,不如将其投影到两个具有两个字段的新对象(可能是匿名对象),然后,如果需要,在检索到后将其投影到两个元素数组中数据库中的对象,如果您确实需要数组中的这些值。

【讨论】:

    【解决方案3】:

    试试这个-

    var platforms= dbContext.Platforms.Select(x=>x.CodeName);
    var configurations=dbContext.Configurations.Select(x=>x.CodeName);
    
    var mix=platforms.SelectMany(num => configurations, (n, a) => new { n, a });
    

    如果你想详细了解-Difference between Select and SelectMany

    【讨论】:

    • 不完全是我想要的,我已经相应地编辑了我的问题。但它解释了其他 cmets 中的匿名类型状态。在其他情况下可能真的很有趣。谢谢。
    猜你喜欢
    • 2012-02-16
    • 2018-11-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-03-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多