【问题标题】:C# - Populate a list using lambda expressions or LINQC# - 使用 lambda 表达式或 LINQ 填充列表
【发布时间】:2011-03-24 12:08:14
【问题描述】:

自从我使用 lambda 表达式或 LINQ 以来已经有一段时间了,我想知道如何使用这两种方法来执行以下操作(我知道我可以使用 foreach 循环,这只是出于好奇)。

我有一个字符串路径数组(这里是数组还是列表有区别吗?),我想从中返回一个仅包含文件名的新列表。

即使用 foreach 循环将是:

string[] paths = getPaths();
List<string> listToReturn = new List<string>();
foreach (string path in paths)
{
    listToReturn.add(Path.GetFileName(path));
}

return listToReturn;

我如何对 lambda 和 LINQ 做同样的事情?

编辑:在我的例子中,我使用返回的列表作为 ListBox (WPF) 的 ItemsSource,所以我假设它需要是一个列表而不是 IEnumerable ?

【问题讨论】:

  • 也许SO中已经有类似的问题了?
  • 重新编辑:是的,在最后阶段使用 .ToList()。

标签: c# linq lambda


【解决方案1】:

您的主要工具是 .Select() 方法。

string[] paths = getPaths();
var fileNames = paths.Select(p => Path.GetFileName(p));

这里是数组还是列表有区别吗?

不,数组也实现了IEnumerable&lt;T&gt;


请注意,这种最小方法涉及延迟执行,这意味着fileNamesIEnumerable&lt;string&gt;,并且仅在您从源数组中获取元素时才开始迭代源数组。

如果您想要一个列表(为了安全起见),请使用

string[] paths = getPaths();
var fileNames = paths.Select(p => Path.GetFileName(p)).ToList();

但是当有很多文件时,您可能希望通过使用延迟执行源来反方向(获得交错的结果,更快):

var filePaths = Directory.EnumerateFiles(...);  // requires Fx4
var fileNames = filePaths.Select(p => Path.GetFileName(p));

这取决于您接下来要使用fileNames 做什么。

【讨论】:

  • +1 表示未显式迭代结果并将其转换为List&lt;string&gt;
  • @Henk:不,另一个被赞成的帖子以ToList() 电话结束。我喜欢你的样本没有这样做的事实。
  • @Fredrik:我认为当问题明确要求一个列表时,答案可能应该创建一个列表或说明他们为什么不这样做。
  • 你真的可以用Path.GetFileName替换p =&gt; Path.GetFileName(p)
  • @Jon:你有一个很好的观点(我同意;一个简短的解释会代替它),但我经常看到人们使用 List&lt;T&gt; 只是因为他们不知道替代方案,所以我倾向于喜欢“及时停止”的答案。我并不是说 OP 不知道这一点,但帖子中没有任何内容表明确实需要 IEnumerable&lt;T&gt; 未提供的任何东西(除了变量声明)。
【解决方案2】:

我认为“LINQ”实际上是指“查询表达式”,但是:

// Query expression
var listToReturn = (from path in paths
                    select Path.GetFileName(path)).ToList();

// Extension methods and a lambda
var listToReturn = paths.Select(path => Path.GetFileName(path))
                        .ToList();

// Extension methods and a method group conversion
var listToReturn = paths.Select(Path.GetFileName)
                        .ToList();

通过从方法组构造投影委托来注意最后一个是如何工作的,如下所示:

Func<string, string> projection = Path.GetFileName;
var listToReturn = paths.Select(projection).ToList();

(以防万一不清楚。)

请注意,if 您不需要将其用作列表 - 如果您 只是 想要迭代它,换句话说 - 您可以删除 @ 987654323@ 来自每种方法的调用。

【讨论】:

    【解决方案3】:

    只是:

    var listToReturn = getPaths().Select(x => Path.GetFileName(x)).ToList();
    

    正如其他答案中所述,如果您实际上不需要List&lt;string&gt;,则可以省略ToList() 并简单地返回IEnumerable&lt;string&gt;(例如,如果您只需要迭代它,IEnumerable&lt;&gt; 更好因为避免了创建另一个字符串列表)

    另外,鉴于Select() 方法接受一个委托,并且方法组和具有相同签名的委托之间存在隐式转换,您可以跳过 lambda 并执行以下操作:

    getPaths().Select(Path.GetFileName)
    

    【讨论】:

    • 当你可以传递函数时,lambda 是没有意义的。另外,我认为声明Select 返回的IEnumerable 足以用于枚举并且可能不需要列表转换是有道理的。
    • @gaeron:是的,没有必要使用 lambda。无论如何,我认为这比 lambda 快得可以忽略不计,而后者在 IMO 上更具可读性。顺便说一句,已编辑:)
    【解决方案4】:

    你可以这样做:

    return getPaths().Select(Path.GetFileName);
    

    【讨论】:

      【解决方案5】:
      listToReturn = paths.ToList().Select(p => Path.GetFileName(p));
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2015-05-26
        • 1970-01-01
        • 1970-01-01
        • 2013-06-15
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多