LINQ等效于F#List.partition

使用LINQ,如何以与F#的List.parition函数等效的方式对IEnumerable进行分区?结果应将源序列基于谓词划分为两个序列,每个源项对该谓词进行一次评估。

sophiezelmani927 回答:LINQ等效于F#List.partition

Enumerable.ToLookup接近。

var l = new int[]{1,2,3,4,5};

var split = l.ToLookup( i => i > 2);

var a = split[true]; // 3,5
var b = split[false]; // 1,2

将其包装在函数中并不难。

public static (IEnumerable<TSource> Yeses,IEnumerable<TSource> Nos) Partition<TSource>(IEnumerable<TSource> source,Func<TSource,bool> predicate)
{
    //Null handling?
    var s = source.ToLookup(i => predicate(i));
    return (s[true],s[false]);
}

public static void Main(string[] args)
{
    var l = new int[] { 1,5 };

    var s = Partition(l,i => { Console.WriteLine($"Called: {i}"); return i > 2;});

    Console.WriteLine(string.Join(",",s.Yeses));
    Console.WriteLine(string.Join(",s.Nos));
}
Called: 1
Called: 2
Called: 3
Called: 4
Called: 5
3,5
1,2
,

我会这样建议:​​

F#(测试用例)

let list1 = [ 1 .. 10 ]
let listEven,listOdd = List.partition (fun elem -> elem % 2 = 0) list1
printfn "Evens: %A\nOdds: %A" listEven listOdd
/* Result:
Evens: [2; 4; 6; 8; 10]
Odds: [1; 3; 5; 7; 9]
*/

C#(测试用例)

var list1 = Enumerable.Range(1,10);

var (listEven,listOdd) = list1
    .GroupBy(key => key % 2 == 0)
    .Aggregate(
        (part1: Enumerable.Empty<int>(),part2: Enumerable.Empty<int>()),(accumulator,value) => {
            if (value.Key)
            {
                accumulator.part1 = value.ToArray();    
            }
            else
            {
                accumulator.part2 = value.ToArray();
            }

            return accumulator;
        });

Console.WriteLine($"Evens: [{string.Join("; ",listEven)}]\nOdds: [{string.Join("; ",listOdd)}]");
/* Result:
Evens: [2; 4; 6; 8; 10]
Odds: [1; 3; 5; 7; 9]
*/

要重用和通用化此方法,请定义扩展方法:

public static class EnumerableExtensions
{
    public static (T[] part1,T[] part2) Partition<T>(this IEnumerable<T> self,Func<T,bool> predicate)
    {
        return self
            .GroupBy(predicate)
            .Aggregate(
                (part1: Array.Empty<T>(),part2: Array.Empty<T>()),value) => {
                    if (value.Key)
                    {
                        accumulator.part1 = value.ToArray();
                    }
                    else
                    {
                        accumulator.part2 = value.ToArray();
                    }

                    return accumulator;
                });
    }
}

像这样使用它:

var list1 = Enumerable.Range(1,10);
var (listEven,listOdd) = list1.Partition(v => v % 2 == 0);

Console.WriteLine($"Evens: [{string.Join("; ",listOdd)}]"); 
/* Result:
Evens: [2; 4; 6; 8; 10]
Odds: [1; 3; 5; 7; 9]
*/

var str = "aAbbBcCddD";
var (lowers,uppers) = str.Partition(v => char.IsLower(v));

Console.WriteLine($"Lowers: [{string.Join("; ",lowers)}]\nUppers: [{string.Join("; ",uppers)}]"); 
/* Result:
Lowers: [a; b; b; c; d; d]
Uppers: [A; B; C; D]
*/
本文链接:https://www.f2er.com/3164951.html

大家都在问