C# 如何使用linq计算列表中的连续值

C# 如何使用linq计算列表中的连续值,c#,linq,list,indexing,C#,Linq,List,Indexing,我有一张这样的清单: var query = Enumerable.Range(0, 999).Select((n, index) => { if (index <= 333 || index >=777) return 0; else if (index <= 666) return 1; else

我有一张这样的清单:

var query = Enumerable.Range(0, 999).Select((n, index) =>
        {
            if (index <= 333 || index >=777)
                return 0;
            else if (index <= 666)
                return 1;
            else
                return 2;
        });
var query=Enumerable.Range(0999)。选择((n,索引)=>
{
如果(索引=777)
返回0;
else if(index
public static IEnumerable GetContinguousCounts(此IEnumerable l,IEqualityComparer cmp)
{
var last=默认值(T);
var计数=0;
foreach(l中的变量e)
{
如果(计数>0&!cmp.等于(e,最后一个))
{
收益回报计数;
计数=0;
}
计数++;
last=e;
}
如果(计数>0)
收益回报计数;
}
公共静态IEnumerable GetContinguousCounts(此IEnumerable l)
{
返回GetContinguousCounts(l,EqualityComparer.Default);
}
静态void Main(字符串[]参数)
{
var a=新[]{1,2,2,3,3,3};
var b=a.GetContiguousCounts();
foreach(b中的变量x)
控制台写入线(x);
}

对于简单的测试用例,它输出1、2、3。对于您的用例334、333、110、222(最后一个值不是您在问题中所问的223,因为您只有999个元素,而不是1000个)。

使用
groupcontinuoused
扩展方法,您可以从中获得每个组的计数:

query.GroupConsecutive((n1, n2) => n1 == n2)
     .Select(g => new {Number = g.Key, Count = g.Count()})

您可以通过某些键为项目的连续分组创建扩展名:

public static IEnumerable<IGrouping<TKey, T>> GroupConsecutive<T, TKey>(
    this IEnumerable<T> source, Func<T, TKey> keySelector)
{
    using (var iterator = source.GetEnumerator())
    {
        if (!iterator.MoveNext()) 
            yield break;            
        else 
        {
            List<T> list = new List<T>();
            var comparer = Comparer<TKey>.Default;
            list.Add(iterator.Current);
            TKey groupKey = keySelector(iterator.Current);

            while (iterator.MoveNext())
            {
                var key = keySelector(iterator.Current);
                if (!list.Any() || comparer.Compare(groupKey, key) == 0)
                {
                    list.Add(iterator.Current);
                    continue;
                }

                yield return new Group<TKey, T>(groupKey, list);
                list = new List<T> { iterator.Current };
                groupKey = key;
            }

            if (list.Any())
                yield return new Group<TKey, T>(groupKey, list);
        }
    }
}
结果:

[
  { Key: 0, Count: 334 },
  { Key: 1, Count: 333 },
  { Key: 2, Count: 110 },
  { Key: 0, Count: 222 }
]

呃,这是我能想到的最有效的实现方式

 IEnuemrable<KeyValuePair<T, int>> RepeatCounter<T>(
         IEnumerable<T> source,
         IEqualityComparer<T> comparer = null)
{
    var e = source.GetEnumerator();
    if (!e.MoveNext())
    {
        yield break;
    }

    comparer = comparer ?? EqualityComparer<T>.Default;

    var last = e.Current;
    var count = 1;
    while (e.MoveNext())
    {
        if (comparer.Equals(last, e.Current))
        {
            count++;
            continue;
        }

        yield return new KeyValuePair<T, int>(last, count);
        last = e.Current;
        count = 1;
    }

    yield return new KeyValuePair<T, int>(last, count);
}
IEnuemrable重复计数器(
IEnumerable来源,
IEqualityComparer比较器=空)
{
var e=source.GetEnumerator();
如果(!e.MoveNext())
{
屈服断裂;
}
比较器=比较器??相等比较器。默认值;
var last=e.电流;
var计数=1;
while(如MoveNext())
{
if(比较器等于(最后一个,即当前))
{
计数++;
继续;
}
返回新的KeyValuePair(最后一个,计数);
最后=e.电流;
计数=1;
}
返回新的KeyValuePair(最后一个,计数);
}

只枚举一次序列,并且只在必要时分配变量。

@SonerGönül,我回滚了编辑,因为它们改变了问题的含义……也许你应该保留语法和格式的修复程序?@Magus我太懒了,无法将你的编辑合并成正确的。@l.B嗯,我同意。谢谢。当相同的值存在于多个段中,它们是分开的结果,是求和还是忽略较低的计数?我得到了这样一个错误:扩展方法必须在非泛型静态类中定义。我无法解决这个问题。@team16sah完全按照错误所说的做-在非泛型静态类中定义扩展方法。您的类不是静态的或是泛型的(或两者兼有)非常感谢。现在,没有错误。此外,我已经根据您的答案编辑了我的问题。您能帮助我解决这个问题吗?@team16sah我的方法中有一个小问题。保留默认值作为初始键值是一个非常糟糕的主意。现在一切正常。我也会将您的问题恢复到以前的编辑,因为更新这真的是一个不同的问题(或者应该是我提出的评论来回答)
var groups =  query.GroupConsecutive(i => i) // produces groups
                   .Select(g => new { g.Key, Count = g.Count() }); // projection
[
  { Key: 0, Count: 334 },
  { Key: 1, Count: 333 },
  { Key: 2, Count: 110 },
  { Key: 0, Count: 222 }
]
 IEnuemrable<KeyValuePair<T, int>> RepeatCounter<T>(
         IEnumerable<T> source,
         IEqualityComparer<T> comparer = null)
{
    var e = source.GetEnumerator();
    if (!e.MoveNext())
    {
        yield break;
    }

    comparer = comparer ?? EqualityComparer<T>.Default;

    var last = e.Current;
    var count = 1;
    while (e.MoveNext())
    {
        if (comparer.Equals(last, e.Current))
        {
            count++;
            continue;
        }

        yield return new KeyValuePair<T, int>(last, count);
        last = e.Current;
        count = 1;
    }

    yield return new KeyValuePair<T, int>(last, count);
}