【问题标题】:Linq Combine two statements into one big statement (optimization)Linq 将两条语句合并为一条大语句(优化)
【发布时间】:2016-12-06 11:47:57
【问题描述】:

我有一个方法使用大量 LINQ 来设置和匹配Tuple<string, int> 列表中的一些值。

现在我仍然被两个嵌套在彼此中的 foreach 循环所困扰,我认为可以将它们组合成一个巨大的 LINQ 查询。我想知道以优化为大条件的最佳方法是什么。

这就是我说的函数:

private async void AddLocalChangesFromPendingOperations()
{
    var pendingOperations = await this.operationsStorage.GetOperationsAsync();
    var list = pendingOperations.
        SelectMany(pendingOperation =>
                           pendingOperation.Settings, (pendingOperation, setting) =>
                           new { pendingOperation, setting })
        .Where(a => a.setting.Key == "selection")
        .Select(a => new Tuple<string, int>(
                                             a.pendingOperation.DefinitionId,
                                             Convert.ToInt32(a.setting.Value.ValueObject)))
        .ToList();

    foreach (var pendingChange in list)
    {
        var selection = await this.selectionsStorage.GetSelectionByIdAsync(pendingChange.Item2);
        foreach (var selectionsViewModel in this.SelectionsList.Where(a => a.Name == selection.Name))
        {
            if (pendingChange.Item1 == "selection-add-animals")
            {
                selectionsViewModel.IsActive = true;
            }
            else if (pendingChange.Item1 == "selection-remove-animals")
            {
                selectionsViewModel.IsActive = false;
            }
        }
    }
}

如果可能的话,我想在使用 linq 时优化最后两个 foreaches。我已经尝试了一些东西,但我一直坚持在当前列表中设置值...

我正在这样做:

this.SelectionsList = this
    .SelectionsList
    .Where(a => a.Name == selection.Name)
    .SingleOrDefault(
        a => pendingChange.Item1 == "selection-add-animals" ? a.IsActive = true : a.IsActive = false
    );

【问题讨论】:

  • 你不能改变GetSelectionByIdAsync方法来接受一个id列表,这样你就可以摆脱第一个foreach了吗?

标签: c# linq


【解决方案1】:

通常,LINQ 用于查询项目(语言集成Query)。但是你可以做一个查询,然后在最后做一个 foreach:

private async void AddLocalChangesFromPendingOperations()
{
    var pendingOperations = await this.operationsStorage.GetOperationsAsync();

    (await Task.WhenAll(pendingOperations
        .SelectMany(pendingOperation =>
                           pendingOperation.Settings, (pendingOperation, setting) =>
                           new { pendingOperation, setting })
        .Where(a => a.setting.Key == "selection")
        .Select(a => Tuple.Create(a.pendingOperation.DefinitionId, Convert.ToInt32(a.setting.Value.ValueObject)))
        .Select(async pendingChange => Tuple.Create(await this.selectionsStorage.GetSelectionByIdAsync(pendingChange.Item2)), pendingChange))
        .SelectMany(tuple => this.SelectionsList.Where(a => a.Name == tuple.Item1.Name)
                                                .Select(selectionsViewModel => Tuple.Create(selectionsViewModel, tuple.Item2))
        .Select(tuple => Tuple.Create(tuple.Item1, tuple.Item2.Item1 == "selection-add-animals"))
        .ToList()
        .ForEach(tuple => tuple.Item1.IsActive = tuple.Item2);
}

这是否比您的原始实现更清晰有待讨论(我认为不是),但这将是一种方法。

注意:这是直接在编辑器中输入的,可能存在一些小的语法错误。

【讨论】:

    【解决方案2】:

    你可以这样做:

    this.SelectionsList = this.SelectionsList
        .Where(a => a.Name == selection.Name)
        .Select(a => 
        {
            a.IsActive = a.Name == selection.Name ? true:false;
            return a;
        }).ToList();
    

    【讨论】:

    • 你知道,由于 LINQ 延迟执行,这没有任何作用。
    • 是的,很抱歉,您应该使用 ToList() 执行查询。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-09-07
    • 1970-01-01
    • 2014-06-18
    • 2018-08-28
    相关资源
    最近更新 更多