【问题标题】:LINQ - Avoid adding empty values to HashSetLINQ - 避免向 HashSet 添加空值
【发布时间】:2018-09-05 17:50:01
【问题描述】:

如何避免在p.Trim() 之后将空 (IsNullOrEmpty) 值添加到以下 linq 的列表中?

    HashSet<string> values;
    string[] value;
    ...  


    get { ... }
    set
    {
        value.ToList().ForEach(i => values.UnionWith(Array.ConvertAll(i.Split(';'), p => p.Trim())));
    }

变量声明仅用于说明目的。

【问题讨论】:

  • value.Where(s =&gt; !string.IsNullOrEmpty(s)).ToList().ForEach...
  • 您不需要调用value.ToList().ForEach - 您可以直接迭代value 或使用Select。使用 Linq 时,从功能上思考! (也就是说,Linq 调用不应该有副作用,因为你执行了values.UnionWith,它直接改变了HashSet)。
  • @Dai 是的。好主意
  • @ParrishHusband 这对输入“abc; ;efg;”有效吗?
  • @JimsonKannantharaJames 查看 Dai 的答案,它非常适合您尝试做的事情。

标签: c# .net linq validation


【解决方案1】:

FWIW,我建议避免使用 List.ForEach,请在此处查看 Eric 的博客文章:https://blogs.msdn.microsoft.com/ericlippert/2009/05/18/foreach-vs-foreach/

  • 您可以简化代码,如果您打算将 Linq 方法添加到调用链中,则无需调用 ToList,因为这将导致对列表进行不必要的额外迭代。
  • 您也可以使用HashSet&lt;T&gt;(IEnumerable&lt;T&gt;) 构造函数,并简单地传入一个构造好的Linq IEnumerable&lt;T&gt;(源数据仍然只会被迭代一次)。
  • 如果您只是想要不同的值,则不需要使用HashSet,您可以使用Linq 的.Distinct() 方法。
  • 我将您的Array.ConvertAll(i.Split(';'), p =&gt; p.Trim()) 转换为.SelectMany 呼叫。

如果您只想要一个不同字符串的列表,我的方法:

String[] stringValues = ...
List<String> distinctValues = stringValues
    .SelectMany( v => v.Split(';') )
    .Select( v => v.Trim() )
    .Where( v => !String.IsNullOrEmpty( v ) )
    .Distinct()
    .ToList();

但是,如果您确实想要 HashSet 作为最终结果,那么您可以省略 .Distinct 步骤(确保您不调用 ToList!):

String[] stringValues = ...
IEnumerable<String> allValues = stringValues
    .SelectMany( v => v.Split(';') )
    .Select( v => v.Trim() )
    .Where( v => !String.IsNullOrEmpty( v ) );

HashSet<String> asHashSet = new HashSet<String>( allValues );

如果您想要不区分大小写的比较或其他比较逻辑,请使用接受自定义比较器的 HashSet 构造函数的其他重载。

【讨论】:

  • 非常干净的方法,我喜欢你将IEnumerable直接传递到HashSet
  • 删除重复值两次是没有意义的。您只是在重复构建两个不同的集合。
  • @Servy 酷我没有意识到构造函数在后台调用UnionWith
  • @Servy 我已经修改了我的答案。
【解决方案2】:

试试这个:

value.Select(s => !string.IsNullOrWhiteSpace(s)).ToList()
      .ForEach(i => values.UnionWith(Array.ConvertAll(i.Split(';'), p => p.Trim())));

【讨论】:

  • @ParrishHusband 没有人。但是如果你想你回答,我会删除我的回答
  • 不,我们可能都错过了额外的括号:)
  • 这不会编译,因为value.Select( ... ) 返回一个IEnumerable&lt;String&gt; 并且Linq 没有为IEnumerable 定义一个.ForEach 扩展方法(它只存在于List&lt;T&gt;)。跨度>
猜你喜欢
  • 2022-11-29
  • 1970-01-01
  • 2019-05-29
  • 1970-01-01
  • 2020-09-23
  • 1970-01-01
  • 2015-09-12
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多