分组连续的相同物品:IEnumerable的< T>到了IEnumerable< IEnumerable的< T>> [英] Grouping consecutive identical items: IEnumerable<T> to IEnumerable<IEnumerable<T>>

查看:163
本文介绍了分组连续的相同物品:IEnumerable的< T>到了IEnumerable< IEnumerable的< T>>的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个interresting问题:给定一个的IEnumerable<字符串> ,是有可能产生的IEnumerable℃的序列的IEnumerable<字符串&GT ;> ,在一个通组相同的相邻字符串

I've got an interresting problem: Given an IEnumerable<string>, is it possible to yield a sequence of IEnumerable<IEnumerable<string>> that groups identical adjacent strings in one pass?

让我来解释一下。

1。基本说明示例:

考虑以下的IEnumerable&LT;字符串&GT; (伪重presentation):

Considering the following IEnumerable<string> (pseudo representation):

{"a","b","b","b","c","c","d"}

如何获得的IEnumerable&LT; IEnumerable的&LT;字符串&GT;&GT; ,将产生什么形式的:<​​/ P>

How to get an IEnumerable<IEnumerable<string>> that would yield something of the form:

{ // IEnumerable<IEnumerable<string>>
    {"a"},         // IEnumerable<string>
    {"b","b","b"}, // IEnumerable<string>
    {"c","c"},     // IEnumerable<string>
    {"d"}          // IEnumerable<string>
}

该方法的原型是:

The method prototype would be:

public IEnumerable<IEnumerable<string>> Group(IEnumerable<string> items)
{
    // todo
}

但是,它也可以是:

But it could also be :

public void Group(IEnumerable<string> items, Action<IEnumerable<string>> action)
{
    // todo
}

...其中,动作将被要求每个子序列。

...where action would be called for each subsequence.

2。更复杂的样品

好了,第一个样品是非常简单的,只有目的是使高层次的意图明确。

Ok, the first sample is very simple, and only aims to make the high level intent clear.

现在假设我们正在处理的的IEnumerable&LT;凡是&GT; ,其中任何是这样定义的类型:

Now imagine we are dealing with IEnumerable<Anything>, where Anything is a type defined like this:

public class Anything
{
    public string Key {get;set;}
    public double Value {get;set;}
}

我们现在要生成基于密钥(组每个连续任何具有相同的密钥)的子序列以后使用它们,以计算出总价值按组:

We now want to generate the subsequences based on the Key, (group every consecutive Anything that have the same key) to later use them in order to calculate the total value by group:

public void Compute(IEnumerable<Anything> items)
{
    Console.WriteLine(items.Sum(i=>i.Value));
}

// then somewhere, assuming the Group method 
// that returns an IEnumerable<IEnumerable<Anything>> actually exists:
foreach(var subsequence in Group(allItems))
{
    Compute(subsequence);
}

3。重要提示

  • 只有一个迭代在原始序列
  • 否中介集合分配(我们可以假设数以百万计的原始序列的项目,以及数以百万计consecutives各组的项目)
  • 在保持普查员和 DEFERED执行的行为
  • 我们可以假设得到的子序列将被迭代仅一次,并且为了将被迭代。
  • Only one iteration over the original sequence
  • No intermediary collections allocations (we can assume millions of items in the original sequence, and millions consecutives items in each group)
  • Keeping enumerators and defered execution behavior
  • We can assume that resulting subsequences will be iterated only once, and will be iterated in order.

是否有可能,你会怎么写呢?

Is it possible, and how would you write it?

推荐答案

这是你正在寻找什么?

  • 在迭代列表只有一次。
  • 推迟执行。
  • 在没有中间集合(我的其他职位未能在此标准)。

该解决方案依赖于对象的状态,因为它很难使用收益率(无ref或OUT参数,)二IEnumerable的方法之间共享状态。

This solution relies on object state because it's difficult to share state between two IEnumerable methods that use yield (no ref or out params).

internal class Program
{
    static void Main(string[] args)
    {
        var result = new[] { "a", "b", "b", "b", "c", "c", "d" }.Partition();
        foreach (var r in result)
        {
            Console.WriteLine("Group".PadRight(16, '='));
            foreach (var s in r)
                Console.WriteLine(s);
        }
    }
}

internal static class PartitionExtension
{
    public static IEnumerable<IEnumerable<T>> Partition<T>(this IEnumerable<T> src)
    {
        var grouper = new DuplicateGrouper<T>();
        return grouper.GroupByDuplicate(src);
    }
}

internal class DuplicateGrouper<T>
{
    T CurrentKey;
    IEnumerator<T> Itr;
    bool More;

    public IEnumerable<IEnumerable<T>> GroupByDuplicate(IEnumerable<T> src)
    {
        using(Itr = src.GetEnumerator())
        {
            More = Itr.MoveNext();

            while (More)
                yield return GetDuplicates();
        }
    }

    IEnumerable<T> GetDuplicates()
    {
        CurrentKey = Itr.Current;
        while (More && CurrentKey.Equals(Itr.Current))
        {
            yield return Itr.Current;
            More = Itr.MoveNext();
        }
    }
}

编辑:添加了扩展方法更清洁的使用。固定回路测试逻辑,这样的更多先求。

Added extension method for cleaner usage. Fixed loop test logic so that "More" is evaluated first.

编辑:完成后处置枚举

这篇关于分组连续的相同物品:IEnumerable的&LT; T&GT;到了IEnumerable&LT; IEnumerable的&LT; T&GT;&GT;的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆