【问题标题】:C# split list into two lists using bool function [duplicate]C# 使用 bool 函数将列表拆分为两个列表
【发布时间】:2019-10-27 18:38:13
【问题描述】:

假设我有一个List<string> listOfStrings,我想根据某个谓词将此列表分成两个列表。例如,第一个列表应该包含所有以字母开头的字符串,第二个是不包含的字符串列表。

现在我会这样做:

var firstList = listOfStrings.Where(str => predicate(str));
var secondList = listOfStrings.Where(str => !predicate(str));

有没有更好的方法在一行中做到这一点?

【问题讨论】:

    标签: c# list filter


    【解决方案1】:

    你可以使用Linq的GroupBy()

    var splitted = listOfStrings.GroupBy(s => Char.IsLetter(s[0]));
    

    如果你的predicate 是:

    Func<string, bool> predicate;
    
    var splitted = listOfStrings.GroupBy(predicate);
    

    用法:

    最简单的方法是将分组数据转换为Dictionary&lt;bool, IEnumerable&lt;string&gt;&gt;,此时键为bool,表示其中的项目是否以字母开头:

    var splitted = list.GroupBy(x => Char.IsLetter(x[0]))
                       .ToDictionary(x => x.Key, z => z.ToArray());  
    
    var startWithLetter = splitted[true];
    var dontStartWithLetter = splitted[false];
    

    当然,有很多方法可以将数据处理成您想要的结构,但我认为以上内容非常简洁。

    MSDN

    【讨论】:

    • 谢谢,但为了完整起见,您能否添加一个示例,说明如何从splitted 中检索两个列表?
    • @eddyP23,完成。
    【解决方案2】:

    您可以使用“GroupBy”或“ToLookup”,具体取决于您将对结果执行的操作。 还要检查lookup vs. groupby

    【讨论】:

      【解决方案3】:

      我会这样做:

      class Program
      {
          static void Main(string[] args)
          {
              Func<string, bool> startsWithA = s => s[0] == 'a';
      
              List<string> listOfStrings = new List<string>()
              {
                  "abc",
                  "acb",
                  "bac",
                  "bca",
                  "cab",
                  "cba"
              };
      
              Dictionary<bool, List<string>> dictionaryOfListsOfStrings = listOfStrings.GroupBy(startsWithA).ToDictionary(x => x.Key, x => x.ToList());
          }
      }
      

      【讨论】:

        【解决方案4】:

        Kotlin 有 partition 函数 (sources)。 C#版本:

        var (first, second) = list.Partition(x => x.IsTrue);
        

        扩展名:

        public static (IEnumerable<T> first, IEnumerable<T> second) Partition<T>(this IEnumerable<T> list, Func<T, bool> predicate)
        {
            var lookup = list.ToLookup(predicate);
            return (lookup[true], lookup[false]);
        }
        

        可能更方便返回List&lt;T&gt;,或者使用 GroupBy 或其他东西,具体取决于用例。

        【讨论】: