Linq获取并置的相等对象的集合

时间:2011-06-03 14:08:23

标签: c# linq collections

以下代码显示了我想要做的事情:

public static IEnumerable<IEnumerable<T>> DoIt<T>(this IEnumerable<T> that)
{
    if (that == null)
        throw new ArgumentNullException();

    if (that.Count() > 1)
    {
        var result = new Collection<IEnumerable<T>>();
        var collection = new Collection<T>();

        collection.Add(that.ElementAt(0));
        for (int i = 1; i < that.Count(); ++i)
        {
            if (!that.ElementAt(i).Equals(that.ElementAt(i - 1)))
            {
                result.Add(collection);
                collection = new Collection<T>();
            }

            collection.Add(that.ElementAt(i));
        }

        result.Add(collection);
        return result;
    }

    return new Collection<IEnumerable<T>>() { that };
}

如果没有适当的实现,我只使用像那样的自定义实现。有没有办法对标准框架做同样的事情?

4 个答案:

答案 0 :(得分:3)

使用标准框架没有传统的方法。不过,我的解决方案确实存在一些问题。

  1. ElementAt(i)的使用非常低效,可能导致that集合被多次迭代。这可能会导致性能问题
  2. Count的使用也可能代价高昂,因为它可能导致that
  3. 的完整枚举
  4. 与大多数LINQ方法不同,它不使用延迟执行。要解决此问题,您需要使用yield return样式解决方案。
  5. 这是另一种解决方案

    public static IEnumerable<IEnumerable<T>> DoIt<T>(this IEnumerable<T> that) {
      using (var e = that.GetEnumerator()) {
        if (!e.MoveNext()) {
          yield break;
        }
    
        bool hasMore;
        do {
          var item = e.Current;
          var list = new List<T>();
          list.Add(item);
    
          hasMore = e.MoveNext();
          while (hasMore && item.Equals(e.Current)) {
            list.Add(e.Current);
            hasMore = e.MoveNext();
          }
    
          yield return list;
        } while (hasMore);
      }
    }
    

答案 1 :(得分:3)

您可以使用SequenceEqual,“如果您正在处理有序集合http://msdn.microsoft.com/en-us/library/bb348567.aspx

,则通过使用类型的默认相等比较器来比较元素,确定两个序列是否相等”

否则collection1.Intersect(collection2).Count()== collection1.Count

会做的伎俩

答案 2 :(得分:0)

可以在链式声明中进行。我不确定我是否会建议这样的代码!

public static IEnumerable<IEnumerable<T>> DoIt<T>(this IEnumerable<T> that) {        
    return that.Zip(that.Skip(1), (a, b) => a.Equals(b) ? 1 : 0)
        .Aggregate(
            (IEnumerable<int>)new []{1, 0}, 
            (c, x) => (new []{c.First() + 1}).Concat(c.Skip(x)), 
            _ => _.Zip(_.Skip(1), (to, skip) => new {skip, take = to - skip}))
        .Reverse()
        .Select(_ => that.Skip(_.skip).Take(_.take));
}

答案 3 :(得分:-2)

使用Any()扩展方法