使用Where和ForEach修改列表中的特定元素

时间:2015-03-20 21:19:04

标签: c# linq

如果我有一个包含属性fruitNamenumFruits的对象列表,并且我希望复数fruitName numFruits大于1,那么它是否可能通过将WhereForeach链接在一起,在一个声明中做到这一点?

类似的东西:

fruitList.Where(fl => fl.numFruits > 1).ForEach(fl => fl.fruitName = fl.fruitName + "s");

我尝试了以上操作并且无法正常工作。它抱怨System.Collections.Generic.IEnumerable不包含ForEach的定义。

6 个答案:

答案 0 :(得分:3)

通常,您希望尽可能使用foreach语言构造。 Eric Lippert有blog post详细说明原因。

当您进行修改时循环很好,因为它可以更容易地找到这些修改。

foreach (var fl in fruitList.Where(fl => fl.numFruits > 1))
{
    fl.fruitName = fl.fruitName + "s";
}

更直接,完成同样的任务。

答案 1 :(得分:2)

如果你真的想要一个单行(它将更难维护)并且想要保持原始列表完整但只修改一些元素,那么你必须使用完整的匿名函数。如果你需要多个语句(一个代码块),你需要包括大括号和语句终止分号,如下所示:

fruitList.ForEach(fl => { fl.fruitName = fl.numFruits > 1 ? fl.fruitName + "s" : fl.fruitName; });

这适用于原始列表(没有子集),并且基本上与结构化foreach完全相同。

答案 2 :(得分:1)

为什么没有“ForEach”序列运算符扩展方法有一个很好的blog post by Eric Lippert,原因是:

  

第一个原因是这样做违反了函数式编程   所有其他序列运算符所基于的原则。   显然,调用这种方法的唯一目的是引起副作用   效果。表达式的目的是计算值,而不是计算值   引起副作用。声明的目的是引起一方   影响。这个东西的呼叫网站看起来很像   表达式(但是,诚然,因为该方法是无效的,   表达式只能用在“语句表达式”中   上下文。)与我合作并不合适   序列运算符仅对其副作用有用。

如果您想在一个语句中执行此操作,则可以使用.Select()

var newFruitList = fruitList.Where(fl => fl.numFruits > 1).Select(fl => fl.fruitName + "s");

答案 3 :(得分:0)

与@Tim Schmelter建议的一样,您可以使用ToList()转换为列表,然后对返回的结果使用ForEach方法。虽然ToList()可能会根据过滤器返回一个较短的列表,但原始对象本身会被更改,而fruitList将保持不变。

fruitList.Where(fl => fl.numFruits > 1).ToList().ForEach(fl => fl.fruitName = fl.fruitName + "s");
// fruitList still has all elements

答案 4 :(得分:0)

您可以使用静态Array.ForEach方法更新列表。

Array.ForEach(fruitList.Where(fl => fl.numFruits > 1).ToArray(), x => { x.fruitName += "s"; });

答案 5 :(得分:0)

鉴于"追加s"实际上并没有给你许多成果的正确答案,任何做到这一点的方法都会给你一个错误的答案,无论它做得多好。

考虑使用查找表将单数字映射到复数(反之亦然):

using System;
using System.Collections.Generic;
using System.Linq;

public class Test
{
    private static Dictionary<string, string> fruitLookup = 
        new Dictionary<string, string>
    {
        {"blueberry", "blueberries"},
        {"peach", "peaches"},
        {"apple", "apples"}
    };

    public static void Main()
    {
        var fruitList = new List<string> {"blueberry", "peach", "apple"};

        // Here is your one-line conversion:
        var plurals = fruitList.Select(f => fruitLookup[f]).ToList();

        foreach (var p in plurals)
        {
            Console.WriteLine(p);
        }
    }
}