拆分列表,使重复项属于同一个子列表

时间:2015-01-05 13:26:29

标签: c# list data-structures

我有一个项目列表,我想将其划分为大小合适的子列表以进行异步处理。但是,它要求同步处理相同值的项目,因此我需要一种有效的机制来确保将相同值的项目分组到同一个子列表中,最好按照它们出现在来源清单。

所以这个例子......

public class ListItem
{
    public ListItem(string key)
    {
        this.Key = key;
    }

    public string Key;
}

private void Sample()
{
    List<ListItem> list = new List<ListItem>()
    {
        new ListItem("A"),
        new ListItem("B"),
        new ListItem("C"),
        new ListItem("D"),
        new ListItem("A"),
        new ListItem("B"),
        new ListItem("E"),
        new ListItem("F"),
        new ListItem("G"),
    };

    List<List<ListItem>> sublists = Partition(list, 3);
}

private List<List<ListItem>> Partition(List<ListItem> list, int batchSize)
{
    // Split list logic
}

分区方法会生成三个与

类似的子列表
  • A,A,C
  • B,B,D
  • E,F,G

如果代码足够灵活,允许对多个列表项属性进行分组,那么它也会非常有用。

由于

1 个答案:

答案 0 :(得分:0)

试试这个:

public class ListItem
{
    public ListItem(string key) { Key=key; }
    public string Key { get; private set; }
    // ...
}

class Program
{
    static void Main(string[] args)
    {
        var list=new List<ListItem>() 
        {
            new ListItem("A"),
            new ListItem("B"),
            new ListItem("C"),
            new ListItem("D"),
            new ListItem("A"),
            new ListItem("B"),
            new ListItem("E"),
            new ListItem("F"),
            new ListItem("G"),
        };

        var sublists=Partition(list, 3);
        // 0: A, A, C
        // 1: B, B, D
        // 3: E, F, G
    }

    static List<List<ListItem>> Partition(IEnumerable<ListItem> list, int batchSize)
    {
        // create empty lists of batches
        var partitions=new List<List<ListItem>>();
        // group items with same key together
        var lookup=list.ToLookup((item) => item.Key);
        foreach(var group in lookup)
        {
            // Get array of same items (called a flock)
            ListItem[] flock=lookup[group.Key].ToArray();
            if(flock.Length>batchSize)
            {
                throw new ArgumentException("Batch Size is too small for grouping", "batchSize");
            }
            //Find first batch with available space from existing ones
            var batch=partitions.FirstOrDefault((part) => (batchSize-part.Count)>=flock.Length);
            if(batch!=null)
            {
                batch.AddRange(flock);
            }
            else // otherwise create a new batch
            {
                partitions.Add(new List<ListItem>(flock));
            }
        }
        return partitions;
    }
}