【问题标题】:Nested foreach to change list items嵌套 foreach 以更改列表项
【发布时间】:2012-05-26 21:12:25
【问题描述】:

我需要使用嵌套的 for/foreach 循环更改列表中的项目。 问题是我无法使用带或不带点符号的 LINQ 使其工作。 传统的方式是这样工作的:

foreach (MapObjectLayer mapObjectLayer in map.Objects)
{
    foreach (MapObject mapObject in mapObjectLayer.MapObjects)
    {
        for (int i = 0; i < mapObject.Points.Count; i++)
        {
            mapObject.Points[i] = new Vector2(
                mapObject.Points[i].X * map.Scale,
                mapObject.Points[i].Y * map.Scale);
        }
    }
}

使用 LINQ,失败了:

var test = (from mol in map.Objects
           from mo in mol.MapObjects
           from p in mo.Points
           select p).ToList();

for (int i = 0; i < test.Count(); i++)
{
    test[i] = new Vector2(
        test[i].X * map.Scale,
        test[i].Y * map.Scale);
}

这失败了:

map.Objects.ForEach(l => l.MapObjects.ForEach(t => t.Points.ForEach(p => p = p * map.Scale)));

如果我能让点符号变体工作,我会非常高兴,但我不知道它为什么会失败。 使用调试器,通过检查点列表很明显,向量没有使用两个 LINQ 变体相乘。

更新:Vector2 是一个结构体

更新:这是我发现的另外两个单行代码(工作行):

map.Objects.SelectMany(m => m.MapObjects).ToList().ForEach(o => o.Points = o.Points.Select(p => p * 2).ToList());
map.Objects.ForEach(l => l.MapObjects.ForEach(t => t.Points = t.Points.Select(p => p * 2).ToList()));

【问题讨论】:

  • 为什么要转成LINQ?
  • 为什么要使用 LINQ? LINQ 用于查询,而不是更新
  • 我认为 LINQ 实际上可能更慢,您是否正在寻找“酷单行”?
  • 好吧,我只是想知道是否可以通过使用 LINQ 获取实际列表,然后对其执行 foreach 来使代码更优雅。但是不要把这个问题看得太严重,它不是必须使用 LINQ ......我只是好奇我是否能让它工作。是的,一个很酷的单线会很棒:)
  • 是否需要修改原始列表中的元素,还是只返回一个带有新元素的新列表?

标签: c# linq .net-3.5 foreach linq-to-objects


【解决方案1】:

常规的foreach 是最好的方法。 LINQ 是为查询而设计的。您可以在一行中完成它,但它不会优雅或可读。方法如下:

map.Objects.ForEach(l => l.MapObjects.ForEach(t => Enumerable.Range(0, t.Points.Count).ToList().ForEach(i => t.Points[i] *= map.Scale)));

您的版本不起作用的原因是因为Vector2 是一个值类型。在查询中,它的值被复制,因此当您执行p =&gt; p = ... 时,您将分配给变量的副本。

使用原始代码。 LINQ 不是循环的替代品。

【讨论】:

  • 这很好地回答了我的问题,并感谢单行:)我把自己搞得一团糟,我可能会为此使用 for/foreach 循环,谢谢。
【解决方案2】:

您也可以使用 Linq 来收集项目(实际上 Resharper 将提供从嵌套 foreach 到 linq 的重构),但您必须注意收集的内容和更新的内容。

最初的 linq 查询语法示例将 Points 的副本收集到一个新列表中,然后将这个新列表的每个元素替换为 Vector2 的一个新实例。即使 Vector2 是一个引用类型,也只有新的列表会改变,而不是原来的 map.Objects-substructure。

它会按照你想要的方式工作

  • 您使用引用而不是值类型和
  • 您将分配而不是 Vector2 项的属性:

    test[i].X *= map.Scale

【讨论】:

    猜你喜欢
    • 2018-05-21
    • 1970-01-01
    • 2018-03-06
    • 2021-06-17
    • 2017-03-14
    • 2015-05-03
    • 1970-01-01
    • 1970-01-01
    • 2013-09-22
    相关资源
    最近更新 更多