C# F#Seq模块在C中实现#用于IEnumerable?
F#有一组标准序列运算符,我从Mathematica的经验中了解并喜爱它们。F#现在得到了我很多的关注,当它正式发布时,我打算经常使用它 现在,由于F#还没有正式发布,我无法在生产代码中真正使用它。LINQ使用类似SQL的名称实现其中一些运算符(例如,“select”是“map”,而“where”是“filter”),但我找不到“fold”、“iter”或“partition”的实现 有人见过标准序列运算符的C#实现吗?这是应该有人写的吗?C# F#Seq模块在C中实现#用于IEnumerable?,c#,f#,C#,F#,F#有一组标准序列运算符,我从Mathematica的经验中了解并喜爱它们。F#现在得到了我很多的关注,当它正式发布时,我打算经常使用它 现在,由于F#还没有正式发布,我无法在生产代码中真正使用它。LINQ使用类似SQL的名称实现其中一些运算符(例如,“select”是“map”,而“where”是“filter”),但我找不到“fold”、“iter”或“partition”的实现 有人见过标准序列运算符的C#实现吗?这是应该有人写的吗? 折叠=聚合 告诉我们使用iter和分区所做的事情,我
- 折叠=
聚合
SelectMany
和分区可能涉及Skip
/Take
(更新)我查了一下-下面是一个粗略的实现,它完成了一些工作:
using System;
using System.Collections.Generic;
static class Program { // formatted for space
// usage
static void Main() {
int[] data = { 1, 2, 3, 4, 5, 6 };
var qry = data.Partition(2);
foreach (var grp in qry) {
Console.WriteLine("---");
foreach (var item in grp) {
Console.WriteLine(item);
}
}
}
static IEnumerable<IEnumerable<T>> Partition<T>(
this IEnumerable<T> source, int size) {
int count = 0;
T[] group = null; // use arrays as buffer
foreach (T item in source) {
if (group == null) group = new T[size];
group[count++] = item;
if (count == size) {
yield return group;
group = null;
count = 0;
}
}
if (count > 0) {
Array.Resize(ref group, count);
yield return group;
}
}
}
使用系统;
使用System.Collections.Generic;
静态类程序{//格式化为空格
//用法
静态void Main(){
int[]数据={1,2,3,4,5,6};
var qry=数据分区(2);
foreach(qry中的var grp){
Console.WriteLine(“--”);
foreach(grp中的var项目){
控制台写入线(项目);
}
}
}
静态可数划分(
此IEnumerable源(整数大小){
整数计数=0;
T[]group=null;//使用数组作为缓冲区
foreach(源中的T项){
如果(group==null)group=newt[size];
组[计数++]=项目;
如果(计数==大小){
收益率-收益率组;
组=空;
计数=0;
}
}
如果(计数>0){
调整数组大小(参考组、计数);
收益率-收益率组;
}
}
}
iter作为一种方法存在于ForEach的List类中
否则:
public static void iter<T>(this IEnumerable<T> source, Action<T> act)
{
foreach (var item in source)
{
act(item);
}
}
publicstaticvoiditer(此IEnumerable源代码,ActionAct)
{
foreach(源中的var项)
{
法案(项目);
}
}
用C#滚动你自己的是一个有趣的练习,下面是我的一些。(另见)
请注意,关于IEnumerable的iter/foreach有点争议——我认为这是因为你必须“敲定”(或不管是什么词)IEnumerable才能真正发生任何事情
//mimic fsharp map function (it's select in c#)
public static IEnumerable<TResult> Map<T, TResult>(this IEnumerable<T> input, Func<T, TResult> func)
{
foreach (T val in input)
yield return func(val);
}
//mimic fsharp mapi function (doens't exist in C#, I think)
public static IEnumerable<TResult> MapI<T, TResult>(this IEnumerable<T> input, Func<int, T, TResult> func)
{
int i = 0;
foreach (T val in input)
{
yield return func(i, val);
i++;
}
}
//mimic fsharp fold function (it's Aggregate in c#)
public static TResult Fold<T, TResult>(this IEnumerable<T> input, Func<T, TResult, TResult> func, TResult seed)
{
TResult ret = seed;
foreach (T val in input)
ret = func(val, ret);
return ret;
}
//mimic fsharp foldi function (doens't exist in C#, I think)
public static TResult FoldI<T, TResult>(this IEnumerable<T> input, Func<int, T, TResult, TResult> func, TResult seed)
{
int i = 0;
TResult ret = seed;
foreach (T val in input)
{
ret = func(i, val, ret);
i++;
}
return ret;
}
//mimic fsharp iter function
public static void Iter<T>(this IEnumerable<T> input, Action<T> action)
{
input.ToList().ForEach(action);
}
//模拟fsharp映射函数(在c#中选择)
公共静态IEnumerable映射(此IEnumerable输入,Func Func)
{
foreach(输入中的T val)
收益回报函数(val);
}
//模拟fsharp mapi函数(我认为C#中不存在)
公共静态IEnumerable MapI(此IEnumerable输入,Func Func)
{
int i=0;
foreach(输入中的T val)
{
收益回报函数(i,val);
i++;
}
}
//模拟fsharp fold函数(它在c#中聚合)
公共静态TResult折叠(此IEnumerable输入、Func Func、TResult种子)
{
TResult ret=种子;
foreach(输入中的T val)
ret=func(val,ret);
返回ret;
}
//模拟fsharp foldi函数(我认为C#中不存在)
公共静态TResult FoldI(此IEnumerable输入、Func Func、TResult种子)
{
int i=0;
TResult ret=种子;
foreach(输入中的T val)
{
ret=func(i,val,ret);
i++;
}
返回ret;
}
//模拟fsharp iter功能
公共静态无效Iter(此IEnumerable输入,动作)
{
input.ToList().ForEach(操作);
}
如果仔细观察,许多Seq操作都具有LINQ等价物,或者可以很容易地派生出来。只是往下看
Seq.append=Concat(IEnumerable秒)
Seq.concat=SelectMany(s=>s)
Seq.distinct\u by=GroupBy(keySelector)。选择(g=>g.First())
Seq.exists=Any(Func谓词)
Seq.mapi=Select(函数选择器)
Seq.fold=聚合(tacumulate seed,Func Func)
List.partition
的定义如下:
将集合拆分为两个集合,其中包含给定谓词分别返回true
和false
的元素
我们可以使用GroupBy和两元素数组作为穷人元组来实现:
public static IEnumerable<TSource>[] Partition<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate)
{
return source.GroupBy(predicate).OrderByDescending(g => g.Key).ToArray();
}
ToLookup可能更适合List.partition:
IEnumerable<T> sequence = SomeSequence();
ILookup<bool, T> lookup = sequence.ToLookup(x => SomeCondition(x));
IEnumerable<T> trueValues = lookup[true];
IEnumerable<T> falseValues = lookup[false];
IEnumerable sequence=SomeSequence();
ILookup lookup=sequence.ToLookup(x=>SomeCondition(x));
IEnumerable trueValues=查找[true];
IEnumerable falseValues=查找[false];
这里是对分区
解决方案的更新
它返回了一个数组[]
,其中“元素0保存真值;元素1保存假值”-但当所有元素都匹配谓词或所有元素都未通过谓词时,这并不成立,在这种情况下,您将得到一个单例数组和一个痛苦的世界
public static Tuple<IEnumerable<T>, IEnumerable<T>> Partition<T>(this IEnumerable<T> source, Func<T, bool> predicate)
{
var partition = source.GroupBy(predicate);
IEnumerable<T> matches = partition.FirstOrDefault(g => g.Key) ?? Enumerable.Empty<T>();
IEnumerable<T> rejects = partition.FirstOrDefault(g => !g.Key) ?? Enumerable.Empty<T>();
return Tuple.Create(matches, rejects);
}
公共静态元组分区(此IEnumerable源,Func谓词)
{
var partition=source.GroupBy(谓词);
IEnumerable matches=partition.FirstOrDefault(g=>g.Key)??Enumerable.Empty();
IEnumerable rejects=partition.FirstOrDefault(g=>!g.Key)??Enumerable.Empty();
返回Tuple.Create(匹配、拒绝);
}
Select的重载确实存在mapi等效项。此外,将枚举转换为列表似乎有点繁重,而不是执行普通的foreach循环并每次调用操作……我不知道选择重载,谢谢。我想ToList是我想到的第一件事……除了它不是懒惰。当所有元素匹配或
public static Tuple<IEnumerable<T>, IEnumerable<T>> Partition<T>(this IEnumerable<T> source, Func<T, bool> predicate)
{
var partition = source.GroupBy(predicate);
IEnumerable<T> matches = partition.FirstOrDefault(g => g.Key) ?? Enumerable.Empty<T>();
IEnumerable<T> rejects = partition.FirstOrDefault(g => !g.Key) ?? Enumerable.Empty<T>();
return Tuple.Create(matches, rejects);
}