说我有一个List<string> listOfStrings
,我想根据某个谓词将此列表分为两个列表。例如,第一个列表应包含所有以字母开头的字符串,第二个列表则应包含不包含字母的字符串。
现在我要这样做:
var firstList = listOfStrings.Where(str => predicate(str));
var secondList = listOfStrings.Where(str => !predicate(str));
有没有一种更好的方法可以做到这一点?
答案 0 :(得分:7)
您可以使用Linq的GroupBy()
:
var splitted = listOfStrings.GroupBy(s => Char.IsLetter(s[0]));
使用您的predicate
,将是:
Func<string, bool> predicate;
var splitted = listOfStrings.GroupBy(predicate);
用法:
最简单的方法是,当键为Dictionary<bool, IEnumerable<string>>
时将分组的数据转换为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
答案 1 :(得分:1)
您可以根据要处理的结果使用“ GroupBy”或“ ToLookup”。 还要检查lookup vs. groupby
答案 2 :(得分:1)
Kotlin 有 partition 函数(如果有兴趣,请参考 here)。它可以在 C# 中看起来像:
var (firstList, secondList) = listOfStrings.Partition(str => predicate(str));
扩展:
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<T>
或使用 GroupBy 或其他东西可能更方便,具体取决于用例。
答案 3 :(得分:0)
我会做这样的事情:
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());
}
}