Equity Sequence Group Fee

If I have some collection, for example: a collection of integers:

1 1 2 2 3 3 1 2 3 4 4 1 1 2 3

and I need to group only sequential elements in this example:

1 1
2 2
3 3
1
2
3
4 4
1 1
2
3

I built the LINQ expression by creating an anonymous collection with the index of the item in the collection, an equality marker, then I joined the collection, with which it is pushed forward by one position, and then groups the elements. But this algorithm, I think, is too redundant.

Are there any more elegant solutions?

+4
source share
4 answers

Here is an implementation that uses LINQ:

//Input sequence
int[] input = new int[] { 1, 1, 2, 2, 3, 3, 1, 2, 3, 4, 4, 1, 1, 2, 3 };
//Group number
int i = 0;
//Result array [<group number>][]
int[][] values = 
    //Select new anonymous object, which contains the source value from input and its group number
    input.Select((item, index) => new { Key = index > 0 ? (item == input[index - 1] ? i : ++i) : 0, Value = item })
    //Group anonymous objects by group number
    .GroupBy(pair => pair.Key)
    //Select values for each group
    .Select(g => g.Select(x => x.Value).ToArray())
    .ToArray();
+1
source

: Linq , Aggregate. , Func lambda. :

static List<List<int>> Group2(List<int> data)
{
    return data.Aggregate(new List<List<int>>(), (list, item) => 
    {
        if (list.Count == 0 || list[list.Count - 1][0] != item)
        {
            list.Add(new List<int> { item });
        }
        else
        {
            list[list.Count - 1].Add(item);
        }
        return list;
    });
}

Linq , , . , :

static IEnumerable<List<T>> Group<T>(IEnumerable<T> list, IEqualityComparer<T> comp)
{
    T previous = default(T);
    bool previousExists = false;
    var eee = list.GetEnumerator();
    List<T> result = null;

    while(eee.MoveNext())
    {
        T current = eee.Current;
        if (previousExists && comp.Equals(current, previous))
        {
            result.Add(current);
        }
        else
        {
            if (result != null)
                yield return result;
            result = new List<T> { current };
        }
        previous = current;
        previousExists = true;
    }

    if (result != null)
        yield return result;
}
+3

, LINQ - :

var res = new List<List<int>>();
foreach(int i in data)
{
    var c = res.Count;
    if (c == 0 || res[c - 1][0] != i)
        res.Add(new List<int>() { i });
    else
        res[c - 1].Add(i);
}

linq , , ,

+1

, LINQ Select, .

, - :

var sequences = items
    .SelectWithPreviousResult(
        new { Item = -1, GroupNumber = 0 }, // default result (used for first item)
        (item, previous) => new
        {
            Item = item,
            GroupNumber = previous.Item == x
                ? previous.GroupNumber
                : previous.GroupNumber + 1 })
    .GroupBy(x => x.GroupNumber, x => x.Item);

, GroupNumber, 0 , . GroupNumber .

, , SelectWithPrevious . LINQ , . SelectWithPreviousResult :

public static class LinqExtensions
{
    public static IEnumerable<TResult> SelectWithPreviousResult<TSource, TResult>(
        this IEnumerable<TSource> items,
        TResult defaultResult,
        Func<TSource, TResult, TResult> func)
    {
        var previousResult = defaultResult;
        foreach (var item in items)
        {
            var result = func(item, previousResult);
            previousResult = result;
            yield return result;
        }
    }
}

, , Aggregate.

+1
source

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


All Articles