Divide the list in the sublist by checking the condition on the items

Suppose I have an array of integers, and I want to split it into several parts, and I want to use zero as a condition when I need to break it. Something like that:

[1,2,3,0,4,5,0,6,7] => [[1,2,3,0], [4,5,0], [6,7]]

Well, this can be easily done using two for loops, but I wanted to know if this is possible with LINQ.

There are a couple of questions like [1] , [2] but in contrast, they rely on a condition that was provided outside the list.

Note: I know that it is not polite to ask a few questions in the stream, but if someone there is familiar with functional programming (since it is the essence, it really is a FP question), I would also like to see their perspectives and possible solutions to this Problems.

+4
source share
3 answers

You have a relationship between the individual elements of your collection, in particular for each element that you want to know, "was the previous element equal to zero?". As soon as your request depends on the previous element (or, in general, as soon as your request depends on other elements of the same sequence), you should achieve for Aggregate(or in more general functional terms of programming fold). This is due to the fact that Aggregate, unlike other LINQ statements, it allows you to transfer the state with you from one iteration to the next.

, , LINQ.

// assume our list of integers it called values
var splitByZero = values.Aggregate(new List<List<int>>{new List<int>()},
                                   (list, value) => {
                                       list.Last().Add(value);
                                       if (value == 0) list.Add(new List<int>());
                                       return list;
                                   });

, .

values.Aggregate(new List<List<int>>{new List<int>()},

, , . List<List<int>>, .

(list, value) => {...}

, - ( Func<List<List<int>>, int, List<List<int>>), , : List<List<int>> .

list.Last().Add(value);

List<int>, Last() ( - ).

if (value == 0) list.Add(new List<int>());

- Last() .

return list;

, , .


SplitOn :

public static IEnumerable<IEnumerable<T>> SplitOn<T>(this IEnumerable<T> source, Func<T, bool> predicate)
{
    return source.Aggregate(new List<List<T>> {new List<T>()},
                            (list, value) =>
                                {
                                    list.Last().Add(value);
                                    if (predicate(value)) list.Add(new List<T>());
                                    return list;
                                });
}

, IEnumerable List, - , Enumerables, - , ( ):

public static IEnumerable<IEnumerable<T>> SplitOn<T>(this IEnumerable<T> source, Func<T, bool> predicate)
{
    return source.Aggregate(Enumerable.Repeat(Enumerable.Empty<T>(), 1),
                            (list, value) =>
                                {
                                    list.Last().Concat(Enumerable.Repeat(value, 1));
                                    return predicate(value) ? list.Concat(Enumerable.Repeat(Enumerable.Empty<T>(), 1)) : list;
                                });
}

Haskell splitOn, , . ( ).

+10

, :

public static IEnumerable<Tuple<TIn, int>> MarkWithLabels<TIn>(this IEnumerable<TIn> src, Predicate<TIn> splittingCondition)
{
    int label = 0;
    foreach (TIn item in src)
    {
        yield return new Tuple<TIn, int>(item, label);
        if (splittingCondition(item))
            label++;
    }
}

int breakingValue = 0;
var subseq = seq.MarkWithLabels(i => i == breakingValue)
    .GroupBy(tup => tup.Item2)
    .Select(group => group.Select(tup => tup.Item1).ToArray())
    .ToArray();

FP , foreach.

+1

, Zack.

public static IEnumerable<List<T>> SplitBefore<T>(this IEnumerable<T> source, Func<T, bool> predicate)
{
    return source.Aggregate(
        Enumerable.Repeat(new List<T>(), 1),
        (list, value) =>
        {
            if (predicate(value))
                list = list.Concat(Enumerable.Repeat(new List<T>(), 1));
            list.Last().Add(value);
            return list;
        }
    )
    .Where(list => list.Any());
}


public static IEnumerable<List<T>> SplitAfter<T>(this IEnumerable<T> source, Func<T, bool> predicate)
{
    return source.Aggregate(
        Enumerable.Repeat(new List<T>(), 1),
        (list, value) =>
        {
            list.Last().Add(value);
            return predicate(value)
                ? list.Concat(Enumerable.Repeat(new List<T>(), 1))
                : list;
        }
    )
    .Where(list => list.Any());
}
0
source

Source: https://habr.com/ru/post/1534912/


All Articles