You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何基于另一列表的顺序拆分列表?求LINQ/函数式实现方案

Got it, let's tackle this problem with LINQ and functional programming principles—no iterative queue logic required! The goal is to split a source list into sublists by cycling through a reference order list: each sublist collects elements as we traverse the reference order, and we repeat this until the source list is fully processed.

Ordered List Splitting with LINQ/Functional Style

Solution Code

using System;
using System.Collections.Generic;
using System.Linq;

public class ListSplitter
{
    public static List<List<int>> SplitByOrder(List<int> source, List<int> order)
    {
        // Use Aggregate to accumulate results and track unprocessed elements
        return source.Aggregate(
            new { Results = new List<List<int>>(), Remaining = source.AsEnumerable() },
            (accumulator, _) => 
            {
                // If there's nothing left to process, keep the current state
                if (!accumulator.Remaining.Any()) return accumulator;
                
                // Cycle through the order list to build one sublist
                var (currentSublist, newRemaining) = order.Aggregate(
                    (Sublist: new List<int>(), Remaining: accumulator.Remaining),
                    (currentState, orderItem) =>
                    {
                        if (!currentState.Remaining.Any()) return currentState;
                        
                        // Grab the element if it matches the current order item
                        if (currentState.Remaining.First() == orderItem)
                        {
                            currentState.Sublist.Add(currentState.Remaining.First());
                            return (currentState.Sublist, currentState.Remaining.Skip(1));
                        }
                        return currentState;
                    });
                
                // Add the sublist to results only if it's not empty
                if (currentSublist.Any())
                {
                    accumulator.Results.Add(currentSublist);
                }
                
                return new { accumulator.Results, Remaining = newRemaining };
            },
            finalState => finalState.Results);
    }

    public static void Main()
    {
        // Test with List B from your example
        var orderB = new List<int> { 4, 5, 6, 0, 1, 2, 3 };
        var nums = new List<int> { 2, 5, 6, 2, 2, 4 };
        
        var result = SplitByOrder(nums, orderB);
        
        // Print the output to verify
        foreach (var sublist in result)
        {
            Console.WriteLine($"[{string.Join(", ", sublist)}]");
        }
        // Expected output:
        // [2]
        // [5, 6, 2]
        // [2]
        // [4]
    }
}

How This Works

Let's break down the key parts in plain terms:

  • Outer Aggregate: We use the source list to drive iterations (we don't use the individual elements, just the count to keep going until everything's processed). This tracks two things: the sublists we've already created, and the elements left to process.
  • Inner Aggregate: For each iteration, we loop through the reference order list. If the next unprocessed element from the source matches the current order item, we add it to the sublist and mark it as processed.
  • State Update: After each full pass through the order list (or if we run out of elements early), we add the non-empty sublist to our results and update the remaining elements for the next round.

Alternative Recursive Functional Approach

If you prefer a more pure functional recursive style, here's another version:

public static List<List<int>> SplitByOrderRecursive(List<int> source, List<int> order)
{
    // Base case: nothing left to process
    if (!source.Any()) return new List<List<int>>();
    
    // Process one full pass through the order list
    var (sublist, remaining) = order.Aggregate(
        (Sublist: new List<int>(), Remaining: source.AsEnumerable()),
        (currentState, orderItem) =>
        {
            if (!currentState.Remaining.Any()) return currentState;
            if (currentState.Remaining.First() == orderItem)
            {
                currentState.Sublist.Add(currentState.Remaining.First());
                return (currentState.Sublist, currentState.Remaining.Skip(1));
            }
            return currentState;
        });
    
    // Build the result by adding this sublist and recursing on remaining elements
    var result = new List<List<int>> { sublist };
    result.AddRange(SplitByOrderRecursive(remaining.ToList(), order));
    
    // Filter out any empty sublists (cleanup for final passes that don't collect anything)
    return result.Where(s => s.Any()).ToList();
}

Test with List A

To confirm it works for your first example, just swap in List A:

var orderA = new List<int> {1,2,3,4,5,6,0};
var nums = new List<int> {2,5,6,2,2,4};
var resultA = SplitByOrder(nums, orderA);
// Expected output: [2, 5, 6], [2], [2, 4]

Both implementations will correctly generate the expected sublists for either reference order.

内容的提问来源于stack exchange,提问作者firefly

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.21 03:44:41