拆分基于对象类型的对象列表

时间:2016-06-01 16:08:20

标签: c# .net linq extension-methods

我有以下对象列表 - “Text1”,“Text2”,新的UndefinedInfo(“Undfined1”),新的UndefinedInfo(“Undfined2”),新的UndefinedInfo(“Undefined3”),“Text3”

我需要输出如下:

输出 //列表> 0 - Text1,Text2 1 - 未定义1,未定义2,未定义3 2 - Text3

我设法写下面的功能很糟糕,但不知何故工作正常。有没有办法使用LINQ扩展来实现相同的功能 - TakeWhile或SkipWhile或使用yield。任何帮助高度赞赏:

public static List<List<object>> PartitionByTypes(List<object> values)
{
List<List<object>> partitionedList = new List<List<object>>();

        int j;
        for (int i = 0; i < values.Count; i++)
        {
            j = i;
            List<object> subList = new List<object>();
            Type t = values[j].GetType();
            do
            {
                subList.Add(values[j]);
                j++;
                if (j == values.Count)
                {
                    break;
                }
            } while (values[j].GetType() == t);
            partitionedList.Add(subList);
            i = j - 1;
        }

        return partitionedList;
    }

3 个答案:

答案 0 :(得分:2)

以下内容将使用yield执行您想要的操作。因此,返回将是IEnumerable<List<object>>

public static IEnumerable<List<object>> PartitionByTypes(List<object> values)
{
    Type prevType = null;
    List<object> cache = new List<object>();
    foreach (var value in values)
    {
        if(prevType != null && value.GetType() != prevType)
        {
            yield return cache;
            cache = new List<object>();
        }

        cache.Add(value);
        prevType = value.GetType();
    }

    if(cache.Count > 0)
        yield return cache;
}

或者,您可以使用以下Linq查询

public static IEnumerable<List<object>> PartitionByTypes(List<object> values)
{
    int count = 0;
    return values.Select((o, i) => new 
        { 
            Object = o, 
            Group = (i == 0 || o.GetType() == values[i - 1].GetType()) ? count : ++count 
        })
        .GroupBy(x => x.Group)
        .Select(g => g.Select(x => x.Object).ToList());
}

答案 1 :(得分:0)

你可以用LINQ和TakeWhile做到这一点,但我怀疑这比普通的foreach更好。例如:

public static List<List<object>> LinqPartitionByTypes(List<object> values)
{
    var batches = new List<List<object>>();
    while (true)
    {
         object prev = null;
         var batch = values.Skip(batches.Sum(c => c.Count)).TakeWhile(c => {
              var result = prev == null || prev.GetType() == c.GetType();
              prev = c;
              return result;
         }).ToList();
         if (batch.Count == 0)
              break;
         batches.Add(batch);
     }
     return batches;
}

但是,我最好做一些更简单,更干净的事情:

public static List<List<object>> PartitionByTypes(List<object> values) {
    var batches = new List<List<object>>();
    object prev = null;
    var batch = new List<object>();
    foreach (var value in values) {
        if (prev != null && prev.GetType() != value.GetType()) {
            batches.Add(batch);
            batch = new List<object>();
        }
        batch.Add(value);
        prev = value;
    }
    if (batch.Count > 0)
        batches.Add(batch);

    return batches;
}

答案 2 :(得分:0)

static Type GetObjectTypeOrNull(object o)
{
    return o == null ? null : o.GetType();
}

static IEnumerable<List<object>> PartitionByTypes(List<object> values)
{
    if (values == null) throw new ArgumentNullException("values");
    if (values.Count == 0) yield break;

    Type currentType = GetObjectTypeOrNull(values);
    List<object> buffer = new List<object>();
    foreach (object value in values)
    {
        Type valueType = GetObjectTypeOrNull(value);
        if (valueType != currentType)
        {
            currentType = valueType;
            yield return buffer;
            buffer = new List<object>();
        }

        currentType = valueType;
        buffer.Add(value);
    }

    if (buffer.Count > 0)
    {
        yield return buffer;
    }
}

示例:

List<object> input = new List<object> { "Text1", "Text2", new UndefinedInfo("Undefined1"), new UndefinedInfo("Undefined2"), new UndefinedInfo("Undefined3"), "Text3" };
PartitionByTypes(input).ToList();

结果:

{ List<object>(2) { "Text1", "Text2" }, List<object>(3) { [Undefined1], [Undefined2], [Undefined3] }, List<object>(1) { "Text3" }

另一个例子 - 使用nulls:

List<object> input = new List<object> { null, "Text1", "Text2", null, null, new UndefinedInfo("Undefined1"), null, null, new UndefinedInfo("Undefined2"), new UndefinedInfo("Undefined3"), "Text3" };
PartitionByTypes(input).ToList();

结果:

List<object>(1) { null }, List<object>(2) { "Text1", "Text2" }, List<object>(2) { null, null }, List<object>(1) { [Undefined1] }, List<object>(2) { null, null }, List<object>(2) { [Undefined2], [Undefined3] }, List<object>(1) { "Text3" }