LINQ to count在int数组中继续重复项(int)?

san*_*eep 5 .net c# linq algorithm

这是我的问题的一个场景:我有一个数组,说:

{ 4, 1, 1, 3, 3, 2, 5, 3, 2, 2 }
Run Code Online (Sandbox Code Playgroud)

结果应该是这样的(数组元素=>它的计数):

4 => 1
1 => 2
3 => 2
2 => 1
5 => 1
3 => 1
2 => 2
Run Code Online (Sandbox Code Playgroud)

我知道这可以通过实现for loop.

但是谷歌使用LINQ使用较少的代码行没有成功,这使得这成为可能.

Mar*_*age 8

我相信最好的方法是使用迭代器块创建一个"LINQ-like"扩展方法.这使您可以对数据进行一次传递来执行计算.请注意,如果您只想对一小组数字执行计算,那么性能根本不重要.当然,这实际上是你的伪装循环.

static class Extensions {

  public static IEnumerable<Tuple<T, Int32>> ToRunLengths<T>(this IEnumerable<T> source) {
    using (var enumerator = source.GetEnumerator()) {
      // Empty input leads to empty output.
      if (!enumerator.MoveNext())
        yield break;

      // Retrieve first item of the sequence.
      var currentValue = enumerator.Current;
      var runLength = 1;

      // Iterate the remaining items in the sequence.
      while (enumerator.MoveNext()) {
        var value = enumerator.Current;
        if (!Equals(value, currentValue)) {
          // A new run is starting. Return the previous run.
          yield return Tuple.Create(currentValue, runLength);
          currentValue = value;
          runLength = 0;
        }
        runLength += 1;
      }

      // Return the last run.
      yield return Tuple.Create(currentValue, runLength);
    }
  }

}
Run Code Online (Sandbox Code Playgroud)

请注意,扩展方法是通用的,您可以在任何类型上使用它.使用相等的值比较值Object.Equals.但是,如果您愿意,可以传递一个IEqualityComparer<T>允许自定义值的比较方式.

你可以使用这样的方法:

var numbers = new[] { 4, 1, 1, 3, 3, 2, 5, 3, 2, 2 };
var runLengths = numbers.ToRunLengths();
Run Code Online (Sandbox Code Playgroud)

对于输入数据,结果将是这些元组:

4 1 
1 2 
3 2 
2 1 
5 1 
3 1 
2 2