【问题标题】:Aggregate a series of contiguous blocks in an IEnumerable在 IEnumerable 中聚合一系列连续的块
【发布时间】:2013-04-24 05:50:38
【问题描述】:

过分简化、做作的问题

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

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?

稍微简化,同样的问题

我有一个可枚举的“令牌”列表。令牌只有 2 种类型,都继承自基础令牌:

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

字符串:

你好世界{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}
    };

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

【问题讨论】:

  • 对我来说看起来像是一种奇怪的压缩操作形式。所有重复的字符是否总是一个字符,或者我们是否也希望将更大的集合组合在一起。示例 varX varX varX 是否会出现在集合中,需要缩小为单个条目?如果是这样,那会让事情变得复杂......
  • @Nevyn - 啊哈,你已经发现我认为这个简化的例子可能会发生什么:所以我更新了问题以说明你为什么不应该赶上“字符串”的详细信息
  • 有道理。所以我们正在查看类型,它可能是任何东西,并且需要用这些类型的集合替换?所有这些还需要被更大的集合绑定到单个实例中吗?
  • 这些类型的集合就可以了,是的。归根结底,我很简单地将Words 与一个空格连接起来造句!

标签: c# ienumerable aggregate


【解决方案1】:

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

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();
    }
}

【讨论】:

  • 我认为这已经为我指明了正确的方向。谢谢
  • 与我想出的算法几乎相同,但对 Linq 和 Extensions 的使用更漂亮,而且更具体到解决方案......但这就是拥有更多设计信息的原因: -)。我喜欢它:-)
【解决方案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&lt;&gt; 方法将是可行的方法,根据类型过滤列表。不幸的是,您不能在类型规范中为此使用变量,因此您需要提前知道可能在 initialList 中的所有类型的严格列表。

【讨论】:

  • 感谢您的回答,但请查看更新 - 列表中只有 2 种类型的对象;连接和不连接。 WordVariable.
  • 嗯,有证据表明,更多信息可以为您提供更具体和信息丰富的答案:-)。很高兴我至少可以提供帮助,即使它不是您要寻找的最终产品。
猜你喜欢
  • 2023-03-21
  • 1970-01-01
  • 2021-02-19
  • 2018-03-03
  • 1970-01-01
  • 1970-01-01
  • 2013-08-25
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多