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