在IEnumerable中聚合一系列连续的块

时间:2013-04-23 20:31:17

标签: c# ienumerable aggregate

过于简化,人为的问题

我有一个可枚举的实例,它可以包含一系列连续的元素,以及与它们交叉分散的一些其他元素。一个简单的例子

var items = new[]
            {"1","1","1","1","1","varX","1","1","1","1","varY","1","1"};

正如您所看到的,字符串1会重复,然后不时地出现其他内容(非常容易识别)。让我们说我想以一种形成可枚举的方式进行聚合

var aggregated = new[]
          { "11111", "varX", "1111", "varY","11"};

这显然只是“所有1的连接”后跟“var”后跟下一组1连接。等

不要太乱挂字符串细节;将“1”视为对象Word和“var”的实例,将其视为对象Variable的实例。现在我想将Word连接在一起(做一个句子)并以不同的方式处理Variable

我如何使用LINQ编写聚合,或者仅仅使用简单的foreach?

略有简化,同样的问题

我有一个“令牌”的可列表。只有两种类型的令牌,都来自基本令牌:

public abstract class Token{}
public class WordToken : Token {}
public class VariableToken : Token {}

字符串:

  

Hello world {varX}你是怎么{varY}再见

我的代码将对以下可枚举的

进行标记
  var tokens = new[]
    { 
       WordToken, 
       WordToken, 
       VariableToken,  
       WordToken,  
       WordToken,  
       WordToken,  
       VariableToken,  
       WordToken
    };

我希望将其转为

var newList = new [] 
    {
       FragmentToken, 
       VariableToken,  
       FragmentToken,  
       VariableToken,  
       FragmentToken
     };

FragmentToken所有单词串联起来的地方

显而易见的第一步是聚合原始列表以制作

var step = new[]
    { 
          new[]{WordToken, WordToken}, 
          new[]{VariableToken},
          new[]{ WordToken, WordToken, WordToken}, 
          new[]{VariableToken}, 
          new[]{WordToken}
    };

然后我可以轻松地完成下一步,但我无法理解如何进入第一步。

2 个答案:

答案 0 :(得分:3)

这是否接近您想要的解决方案?

public abstract class Token : IComparable
{
    public int CompareTo(object obj)
    {
        if (obj == null)
        {
            return -1;
        }
        return GetType().FullName.CompareTo(obj.GetType().FullName);
    }
}
public class WordToken : Token { }
public class VariableToken : Token { }

public static class ListExtensions
{
    public static IEnumerable<IEnumerable<TEntity>> JoinRepeatedValues<TEntity>(this IEnumerable<TEntity> collection)
        where TEntity : IComparable
    {
        var joinedRepeatedValuesCollection = new List<List<TEntity>>();
        var lastValue = default(TEntity);
        foreach (var item in collection)
        {
            if (item.CompareTo(lastValue) != 0)
            {
                joinedRepeatedValuesCollection.Add(new List<TEntity> { item });
            }
            else
            {
                var lastAddedValue = joinedRepeatedValuesCollection.Last();
                lastAddedValue.Add(item);
            }
            lastValue = item;
        }
        return joinedRepeatedValuesCollection;
    }

}
class Program
{
    static void Main(string[] args)
    {
        var tokens = new Token[]
                            {
                                new WordToken(),
                                new WordToken(),
                                new VariableToken(),
                                new WordToken(),
                                new WordToken(),
                                new WordToken(),
                                new VariableToken(),
                                new WordToken()
                            };

        var joinedValues = tokens.JoinRepeatedValues();
        var items = new[] { "1", "1", "1", "1", "1", "varX", "1", "1", "1", "1", "varY", "1", "1" }.JoinRepeatedValues();
    }
}

答案 1 :(得分:2)

嗯,基于我对问题的理解,这是一次尝试

var initialList;//whatever this contains...

List<List<Object>> retList = new List<List<Object>>();

Type storedType = null;

foreach(Object thing in initialList)
{//we treat this like a simple array of objects, because we DONT know what's in it.
    if(storedType != null)
    {
        if(storedType.Equals(thing.GetType())
            instanceList.Add(thing);
        else
        {//add instanceList to the master return, then re-set stored type and the 
         //list and add the current thing to the new list
            retList.Add(instanceList);
            storedType = thing.GetType();
            instanceList = new List<Object>();
            instanceList.Add(thing);
        }
    }
    else
    {//should be First run only
        storedType = thing.GetType();
        instanceList.Add(thing);
    }
}
return retList;

添加了备注:

如果所有对象都应该是相同的Type,那么不是检查类型,而是检查并存储该值,但基本算法保持不变。此外,您可以使用内容的确切类型而不是Object,如果您正在检查值,这是非常必要的。

===========================================

在保持当前项目顺序的同时,不知道如何使用linq执行此操作。如果这不重要,Linq的OfType<>方法将成为可行的方法,根据类型过滤列表。不幸的是,你不能在类型规范中使用变量,所以你需要提前知道可能在initialList中的所有类型的严格列表。