将列表拆分为多个列表,其中序列递增

M.S*_*.S. 18 c# linq lambda list

我有一个int列表,我希望在找到较低或相同的数字后拆分原始列表后创建多个List.数字不按排序顺序排列.

 List<int> data = new List<int> { 1, 2, 1, 2, 3, 3, 1, 2, 3, 4, 1, 2, 3, 4, 5, 6 };
Run Code Online (Sandbox Code Playgroud)

我希望结果如下:

 { 1, 2 }
 { 1, 2, 3 }
 { 3 }
 { 1, 2, 3, 4 }
 { 1, 2, 3, 4, 5, 6 }
Run Code Online (Sandbox Code Playgroud)

目前,我正在使用以下linq来做到这一点,但没有帮助我:

List<int> data = new List<int> { 1, 2, 1, 2, 3, 3, 1, 2, 3, 4, 1, 2, 3, 4, 5, 6 };
List<List<int>> resultLists = new List<List<int>>();
var res = data.Where((p, i) =>
{
    int count = 0;
    resultLists.Add(new List<int>());
    if (p < data[(i + 1) >= data.Count ? i - 1 : i + 1])
    {
        resultLists[count].Add(p);
    }
    else
    {
        count++;
        resultLists.Add(new List<int>());
    }
    return true;
}).ToList();
Run Code Online (Sandbox Code Playgroud)

Mat*_*son 10

我只想做一些简单的事情:

public static IEnumerable<List<int>> SplitWhenNotIncreasing(List<int> numbers)
{
    for (int i = 1, start = 0; i <= numbers.Count; ++i)
    {
        if (i != numbers.Count && numbers[i] > numbers[i - 1])
            continue;

        yield return numbers.GetRange(start, i - start);
        start = i;
    }
}
Run Code Online (Sandbox Code Playgroud)

您可以这样使用:

List<int> data = new List<int> { 1, 2, 1, 2, 3, 3, 1, 2, 3, 4, 1, 2, 3, 4, 5, 6 };

foreach (var subset in SplitWhenNotIncreasing(data))
    Console.WriteLine(string.Join(", ", subset));
Run Code Online (Sandbox Code Playgroud)

如果你真的需要合作IEnumerable<T>,那么我能想到的最简单的方法是这样的:

public sealed class IncreasingSubsetFinder<T> where T: IComparable<T>
{
    public static IEnumerable<IEnumerable<T>> Find(IEnumerable<T> numbers)
    {
        return new IncreasingSubsetFinder<T>().find(numbers.GetEnumerator());
    }

    IEnumerable<IEnumerable<T>> find(IEnumerator<T> iter)
    {
        if (!iter.MoveNext())
            yield break;

        while (!done)
            yield return increasingSubset(iter);
    }

    IEnumerable<T> increasingSubset(IEnumerator<T> iter)
    {
        while (!done)
        {
            T prev = iter.Current; 
            yield return prev;

            if ((done = !iter.MoveNext()) || iter.Current.CompareTo(prev) <= 0)
                yield break;
        }
    }

    bool done;
}
Run Code Online (Sandbox Code Playgroud)

您可以这样称呼:

List<int> data = new List<int> { 1, 2, 1, 2, 3, 3, 1, 2, 3, 4, 1, 2, 3, 4, 5, 6 };

foreach (var subset in IncreasingSubsetFinder<int>.Find(data))
    Console.WriteLine(string.Join(", ", subset));
Run Code Online (Sandbox Code Playgroud)

  • @casperOne当然不会 - 但OP有一个列表,所以这没问题.如果它需要在`IEnumerable <int>`上运行,那么你必须采用不同的方式.但是,此代码假定为YAGNI (3认同)

Iva*_*oev 5

这不是典型的LINQ操作,所以在这种情况下(当一个人坚持使用LINQ时)我会建议使用Aggregate方法:

var result = data.Aggregate(new List<List<int>>(), (r, n) =>
{
    if (r.Count == 0 || n <= r.Last().Last()) r.Add(new List<int>());
    r.Last().Add(n);
    return r;
});
Run Code Online (Sandbox Code Playgroud)

  • @sam,听起来你不理解`Aggregate`方法.@Ivan,这与我放在一起的答案类似.Linq操作通常不记得他们已经看过的项目,所以使用累加器对你有利是一个好主意. (2认同)

Pat*_*man 3

您可以使用索引来获取前一项并通过比较值来计算组 ID。然后对组 ID 进行分组并获取值:

List<int> data = new List<int> { 1, 2, 1, 2, 3, 1, 2, 3, 4, 1, 2, 3, 4, 5, 6 };

int groupId = 0;
var groups = data.Select
                 ( (item, index)
                   => new
                      { Item = item
                      , Group = index > 0 && item <= data[index - 1] ? ++groupId : groupId
                      }
                 );

List<List<int>> list = groups.GroupBy(g => g.Group)
                             .Select(x => x.Select(y => y.Item).ToList())
                             .ToList();
Run Code Online (Sandbox Code Playgroud)

  • +1,只需将计算“Group”逻辑修改为 *index &gt; 0 &amp;&amp; item **&lt;=** data[index - 1] ?++组ID : 组ID* (2认同)