【问题标题】:what would be the equivalent this for loop in linq在 linq 中,这个 for 循环的等价物是什么?
【发布时间】:2013-08-25 18:33:49
【问题描述】:

我有这个 for 循环,它在列表中搜索特定值并用新值替换它们。

for (int i = 0; i < Data.Count; i++) {

if (Data[i] > 0 && Data[i] <= 10) {Data[i] = 1;}
else if (Data[i] > 10 && Data[i] < 20) {Data[i] = 2;}      
...
}

我一直在尝试用 linq 编写这个函数,我知道它可以这样写:

var Data2 = Data.Where(x=> x > 0 && x <= 10).Select(y=> y=1).ToList();

我的问题是,有什么方法可以将此 for 循环转换为 linq 形式而无需声明新列表?我的意思是一个 linq 表单,它在列表中搜索这些值,当它找到它们时,它会相应地替换它们。

【问题讨论】:

  • 为什么要用Linq重写?
  • 我想使用Linq的原因只是代码清晰,实际上我想在数据挖掘中使用它,我有大量需要处理的嘈杂数据。我也很好奇 linq 解决方案
  • 就地修改数据并不是 Linq 的强项。 Linq 方法通常没有副作用。这就是为什么 .ForEach() 方法不是 Linq 方法并且只为列表定义的原因。

标签: linq


【解决方案1】:

无论如何,我建议不要使用 LINQ:

Enumerable.Range(0,Data.Count)
          .ForEach(x=>{ 
              if (Data[x] > 0 && Data[x] <= 10) {Data[x] = 1;}
              else if (Data[x] > 10 && Data[i] < 20) {Data[x] = 2;} 
          });

这样您就不必声明第二个列表,但代码看起来不如原始列表可读。

【讨论】:

  • 为什么不只是 Data.ForEach(...); ?
  • 因为您无法在 foreach 调用中更改元素值。这个 List l = new List { 1, 1, 1 };l.ForEach(x => x=2);Console.WriteLine(l[1]);打印 1,而不是您建议的 2
  • 是的,因为需要索引。
  • 附注:ForEach 在普通 LINQ 中不存在,它是 MoreLinq extension
【解决方案2】:

确切的等价物是:

Data
  .Select((e,i) => new { Element = e, Index = i })
  .Where(ei => ei.Element > 0 && ei.Element < 20)
  .ToList()
  .ForEach(ei => Data[ei.Index] = (ei.Element <= 10) ? 1 : 2);

或者第二种可能性:看Save的回答。

但是它仍然在中间创建一个列表(ForEach 仅适用于List&lt;T&gt;)。它的可读性不是很好,最好使用不可变的方法并根据给定的标准生成新的列表。

【讨论】:

    【解决方案3】:

    比其他解决方案简单得多:

    Data = Data.Select(d => (d / 10) + 1)
    

    如果你想要一个上限,只需使用Math.Min((d / 10) + 1, topLimit)

    【讨论】:

    • 您不知道列表中是否不包含大于 20 且不应更改的元素。
    • @BartoszKP 我假设大于 20 他有一个最大值可以回退。如果不是,那么可以肯定,其他答案更好。
    • 请注意,如问题中所述,10 映射到 1,但 20 不映射到 2。当然,这可能是问题中的错误。
    • @MatthewStrawbridge 哎呀,我还以为是&lt;=:P
    【解决方案4】:

    就地修改数据不是 Linq 的强项。 Linq 方法通常没有副作用。这就是为什么 .ForEach() 方法不是 Linq 方法并且只为列表定义的原因。

    但是,没有什么可以阻止您使用具有副作用的 Linq 函数。 所以我不推荐这个解决方案,但是你可以在 select 语句中做任何事情,甚至修改底层列表。还有一个选择重载,它使用元素及其索引作为参数( Select( (element,index) => ... )。

    所以你可以用 select 做任何你可以在 for 循环中做的事情。但我会推荐 for 循环以提高可读性。

    data.Select((d,i)=>
        {if (d > 0 && d <= 10) data[i]=1 else if (d>10 && d<20 data[i]=2;})
        .All(d=>true); // <-- note that you do need some way to consume the IEnumerable
                       // in order to execute the .Select(). You can use ToList(), Count(), ..
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-03-22
      • 2011-03-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多