例如,我有一个整数序列
1122211121
我想得到一些词典/匿名课程:
item | count
1 | 2
2 | 3
1 | 3
2 | 1
1 | 1
答案 0 :(得分:6)
var test = new[] { 1, 2, 2, 2, 2, 1, 1, 3 };
int previous = test.First();
int idx = 0;
test.Select(x =>
x == previous ?
new { orig = x, helper = idx } :
new { orig = previous = x, helper = ++idx })
.GroupBy(x => x.helper)
.Select(group => new { number = group.First().orig, count = group.Count() });
如果你想要更加Linqy,可以在previous
子句中完成idx
和let
的初始化。
from whatever in new[] { "i want to use linq everywhere" }
let previous = test.First()
let idx = 0
from x in test
...
函数式编程很不错,但是在这种情况下,在C#中我肯定会选择相当程序化的方法。
答案 1 :(得分:2)
您希望在morelinq项目中执行类似“批处理”操作符的操作,然后输出组的计数。
不幸的是,来自morelinq的批处理操作符只需要一个大小并返回按该大小批量处理的桶(或者当我查看morelinq时它会执行)。为了纠正这个缺陷,我必须编写自己的批处理实现。
private static IEnumerable<TResult> BatchImplementation<TSource, TResult>(
this IEnumerable<TSource> source,
Func<TSource, TSource, int, bool> breakCondition,
Func<IEnumerable<TSource>, TResult> resultSelector
)
{
List<TSource> bucket = null;
var lastItem = default(TSource);
var count = 0;
foreach (var item in source)
{
if (breakCondition(item, lastItem, count++))
{
if (bucket != null)
{
yield return resultSelector(bucket.Select(x => x));
}
bucket = new List<TSource>();
}
bucket.Add(item);
lastItem = item;
}
// Return the last bucket with all remaining elements
if (bucket.Count > 0)
{
yield return resultSelector(bucket.Select(x => x));
}
}
这是我公开了各种验证输入参数的公共重载的私有版本。你希望你的breakCondition具有以下形式:
Func<int, int, int, bool> breakCondition = x, y, z => x != y;
对于您的示例序列,这应该为您提供:{1, 1}, {2, 2, 2}, {1, 1, 1}, {2}, {1}
从这里开始,抓住每个序列的第一项然后计算序列是微不足道的。
编辑:协助实施 -
public static IEnumerable<IEnumerable<TSource>> Batch<TSource>(
this IEnumerable<TSource> source,
Func<TSource, TSource, int, bool> breakCondition
)
{
//Validate that source, breakCondition, and resultSelector are not null
return BatchImplemenatation(source, breakCondition, x => x);
}
您的代码将是:
var sequence = {1, 1, 2, 2, 2, 1, 1, 1, 2, 1};
var batchedSequence = sequence.batch((x, y, z) => x != y);
//batchedSequence = {{1, 1}, {2, 2, 2}, {1, 1, 1}, {2}, {1}}
var counts = batchedSequence.Select(x => x.Count());
//counts = {2, 3, 3, 1, 1}
var items = batchedSequence.Select(x => x.First());
//items = {1, 2, 1, 2, 1}
var final = counts.Zip(items. (c, i) => {Item = i, Count = c});
除了私有方法及其在我自己的代码库中使用的重载之外,我没有编译和测试过任何这个,但是这应该可以解决你的问题以及你遇到的任何类似问题。
答案 2 :(得分:0)
Wel ...稍微短一些(请注意双重独立调用以处理偶数/奇数事件计数):
static void Main(string[] args)
{
string separatedDigits = Separate(Separate("1122211121"));
foreach (var ano in separatedDigits.Split('|').Select(block => new { item = block.Substring(0, 1), count = block.Length }))
Console.WriteLine(ano);
Console.ReadKey();
}
static string Separate(string input)
{
return Regex.Replace(input, @"(\d)(?!\1)(\d)", "$1|$2");
}
}