【问题标题】:Using LINQ in C# to find and update values in a list of lists在 C# 中使用 LINQ 在列表列表中查找和更新值
【发布时间】:2021-03-05 06:15:05
【问题描述】:

我有下面列出的三个类:

class OuterObjects
{
    string name;
    List<InnerObjects> myList;
}

class InnerObjects
{
    float small;
    float big;
}

class CorrectValues
{
    string name;
    float correctValue;
}

所以我的代码遍历所有内容并到达一个点,我映射了所有 OuterObjects 和 InnerObjects,然后我通过数据库调用分别加载 CorrectValues。

所以我有:

List<OuterObjects> theList = [loaded up with many names and InnerObjects]

所以我需要写一些东西,通过 OuterObjects 进入 InnerObjects 并找到所有小的 > 大的并修复它们。 (float) big 将替换为 CorrectValues 和 OuterObjects 中的名称匹配的正确值。名称也可以在它的每个对象中出现多次,但正确的值将始终匹配相同的名称(即,如果在 CorrectValues 中有 2 个“鲍勃”的名称,那么正确的值将是相同的)。

我有类似的东西:

outerObjects.Select(q => q.InnerObjects).Where(q => (q.small > q.big) ... then update the big with the correctValue

有没有一种好的、优雅的方式来做到这一点?我也不想使用 forEach 语句。

【问题讨论】:

  • Linq 是一个查询(q 是查询),它读取数据并且不用于更新值
  • 我看到这样的事情:customers.Where(c => c.IsValid).Select(c => { c.CreditLimit = 1000; return c; }).ToList();我在网上找到的
  • 在哪里更新现有项目?代码正在创建一个新列表。你有一个 where 所以新列表只包含一些原始数据。而且您的代码只返回一个属性。
  • 那么最好的方法是什么?我假设使用单独的 linq 来获得所需的正确部分,然后使用某些东西来查找和更新值。
  • “我不想使用 forEach” - 为什么不呢?

标签: c# .net entity-framework linq .net-core


【解决方案1】:

我知道您不想为此使用 forEach 循环,但在这种情况下,它可能是合适的。

例如,您可以执行以下操作:

public void UpdateTheList(List<OuterObjects> theList) {
    theList.ForEach(x => {
       x.name = "John";
       x.myList.ForEach(x => {
       x.big = updateBigDbCall();
       x.small = updateSmallDbCall();
       });
    });
}

您在单独的数据库调用中更新大小,并将所有名称更新为“John”。

另一种方法是使用嵌套的 select 语句:

theList = theList.Select(e => {
   e.name = "John";
   e.myList.Select(x => {
      x.big = updateBigDbCall();
      x.small = updateSmallDbCall();
      return x;
    }).ToList();
    return e;
}).ToList();

说实话,我更喜欢将这些操作分解为单独的简短方法,每个方法做一件事。

因此,获取要更新的对象列表可能是一种方法,即从您的集合中仅选择您需要修复的那些项目。

第二种方法将迭代集合并进行任何更新。

第三种方法是进行更新所需的工作。

例如,您可以将这三个方法包装在上层方法 UpdateList 中,这样任何其他开发人员都可以清楚地了解代码的用途。

【讨论】:

    【解决方案2】:

    如果您要在 Linq 语句中修改对象(例如在您链接到的博客显示的 Select() 中),那么您将遇到麻烦。

    Select() 用于投影对象,这意味着您要将它们映射到新对象中。

    var customerNames = allCustomers.Select(c => c.Firstname + " " + c.Lastname).ToList();
    

    如果您打算滥用该方法来修改通过它的对象,那么您将不再进行纯粹的、函数式的、面向集合的编程,而这不是 Linq 的意思为了。这也会修改源集合中的项目,这通常不是您想要的,并且会在以后引起头疼。

    Where() 用于过滤集合中的对象。您要将它们减少为一个新集合,如下所示:

    var activeCustomers = allCustomers.Where(c => c.IsActive).ToList();
    

    使用foreach() 做您想做的事情的粗略、惯用的方式如下所示:

    foreach (var outerObject in theList)
    {
        var correction = correctValues.FirstOrDefault(c => c.Name == outerObject.Name);
        if (correction == null)
        {
            // We can't fix this outerObject
            continue;
        }
        
        // Look, Linq!
        foreach (var innerObject in outerObject.InnerObjects.Where(o => o.Small > o.Big))
        {
            // Here you're assuming that the correction will have the correct value
            innerObject.Big = correction.CorrectValue;
        }
    }
    

    现在可以肯定,您可以将其转换为带有 .Where().Join() 的内容,但这不会使代码更具可读性或性能,并且您仍然需要进行对象操作来修改每个 @ 987654330@ where Small &gt; Big,你不想在Select()中这样做,所以无论如何你都必须调用.Where(...).ToList().ForEach(/* do the update */),并且ForEach()操作中的代码或多或少是与我上面代码中的内部foreach() 完全相同。

    【讨论】:

      猜你喜欢
      • 2014-11-20
      • 2014-09-09
      • 2014-11-12
      • 2020-11-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多