F# has a bunch of standard sequence operators I have come to know and love from my experience with Mathematica. F# is getting lots of my attention now, and when it is in general release, I intend to use it frequently.
F#有一堆标准的序列运算符,我从Mathematica的经验中了解和喜爱。 F#现在得到了很多关注,当它一般发布时,我打算经常使用它。
Right now, since F# isn't yet in general release, I can't really use it in production code. LINQ implements some of these operators using SQL-like names (e.g. 'select' is 'map', and 'where' is 'filter'), but I can find no implementation of 'fold', 'iter' or 'partition'.
现在,由于F#尚未普遍发布,我无法在生产代码中真正使用它。 LINQ使用类似SQL的名称来实现其中一些运算符(例如'select'是'map','where'是'filter'),但是我找不到'fold','iter'或'partition'的实现。
Has anyone seen any C# implementation of standard sequence operators? Is this something someone should write?
有没有人见过标准序列运算符的C#实现?这是某人应该写的东西吗?
6 个解决方案
#1
If you look carefully, many Seq operations have a LINQ equivalent or can be easily derived. Just looking down the list...
如果仔细观察,许多Seq操作都具有LINQ等效或可以轻松派生。只是看下面的清单......
-
Seq.append = Concat<TSource>(IEnumerable<TSource> second)
Seq.append = Concat
(IEnumerable second) -
Seq.concat = SelectMany<IEnumerable<TSource>, TResult>(s => s)
Seq.concat = SelectMany
,TResult>(s => s) -
Seq.distinct_by = GroupBy(keySelector).Select(g => g.First())
Seq.distinct_by = GroupBy(keySelector).Select(g => g.First())
-
Seq.exists = Any<TSource>(Func<TSource, bool> predicate)
Seq.exists =任何
(Func 谓词) ,bool> -
Seq.mapi = Select<TSource, TResult>(Func<TSource, Int32, TResult> selector)
Seq.mapi =选择
(Func ,tresult>selector) ,int32,tresult> -
Seq.fold = Aggregate<TSource, TAccumulate>(TAccumulate seed, Func<TAccumulate, TSource, TAccumulate> func)
Seq.fold = Aggregate
(TAccumulate seed,Func ,taccumulate>func) ,tsource,taccumulate>
List.partition
is defined like this:
List.partition定义如下:
Split the collection into two collections, containing the elements for which the given predicate returns
true
andfalse
respectively将集合拆分为两个集合,其中包含给定谓词分别返回true和false的元素
Which we can implement using GroupBy and a two-element array as a poor-man's tuple:
我们可以使用GroupBy和一个双元素数组作为穷人的元组来实现:
public static IEnumerable<TSource>[] Partition<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate)
{
return source.GroupBy(predicate).OrderByDescending(g => g.Key).ToArray();
}
Element 0 holds the true values; 1 holds the false values. GroupBy is essentially Partition on steroids.
元素0保存真实值; 1保存虚假值。 GroupBy基本上是类固醇的分区。
And finally, Seq.iter
and Seq.iteri
map easily to foreach:
最后,Seq.iter和Seq.iteri很容易映射到foreach:
public static void Iter<TSource>(this IEnumerable<TSource> source, Action<TSource> action)
{
foreach (var item in source)
action(item);
}
public static void IterI<TSource>(this IEnumerable<TSource> source, Action<Int32, TSource> action)
{
int i = 0;
foreach (var item in source)
action(i++, item);
}
#2
- fold =
Aggregate
fold =聚合
Tell use what iter
and partition
do, and we might fill in the blanks. I'm guessing iter=SelectMany
and partition might involve Skip
/Take
?
告诉我们使用iter和partition做什么,我们可以填写空白。我猜iter = SelectMany和分区可能涉及Skip / Take?
(update) I looked up Partition - here's a crude implementation that does some of it:
(更新)我查找分区 - 这是一个粗略的实现,它做了一些:
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;
}
}
}
#3
iter exists as a method in the List class which is ForEach
iter作为List类中的方法存在,即ForEach
otherwise :
public static void iter<T>(this IEnumerable<T> source, Action<T> act)
{
foreach (var item in source)
{
act(item);
}
}
#4
ToLookup would probably be a better match for List.partition:
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];
#5
Rolling your own in C# is an interesting exercise, here are a few of mine. (See also here)
在C#中滚动你自己是一个有趣的练习,这里有一些我的。 (另见这里)
Note that iter/foreach on an IEnumerable is slightly controversial - I think because you have to 'finalise' (or whatever the word is) the IEnumerable in order for anything to actually happen.
请注意,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);
}
#6
Here is an update to dahlbyk's partition
solution.
以下是dahlbyk分区解决方案的更新。
It returned an array[]
where "element 0 holds the true values; 1 holds the false values" — but this doesn't hold when all the elements match or all fail the predicate, in which case you've got a singleton array and a world of pain.
它返回一个array [],其中“element 0保存真值; 1保存false值” - 但是当所有元素匹配或者所有谓词都失败时,这不成立,在这种情况下你有一个单例数组痛苦的世界。
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);
}
#1
If you look carefully, many Seq operations have a LINQ equivalent or can be easily derived. Just looking down the list...
如果仔细观察,许多Seq操作都具有LINQ等效或可以轻松派生。只是看下面的清单......
-
Seq.append = Concat<TSource>(IEnumerable<TSource> second)
Seq.append = Concat
(IEnumerable second) -
Seq.concat = SelectMany<IEnumerable<TSource>, TResult>(s => s)
Seq.concat = SelectMany
,TResult>(s => s) -
Seq.distinct_by = GroupBy(keySelector).Select(g => g.First())
Seq.distinct_by = GroupBy(keySelector).Select(g => g.First())
-
Seq.exists = Any<TSource>(Func<TSource, bool> predicate)
Seq.exists =任何
(Func 谓词) ,bool> -
Seq.mapi = Select<TSource, TResult>(Func<TSource, Int32, TResult> selector)
Seq.mapi =选择
(Func ,tresult>selector) ,int32,tresult> -
Seq.fold = Aggregate<TSource, TAccumulate>(TAccumulate seed, Func<TAccumulate, TSource, TAccumulate> func)
Seq.fold = Aggregate
(TAccumulate seed,Func ,taccumulate>func) ,tsource,taccumulate>
List.partition
is defined like this:
List.partition定义如下:
Split the collection into two collections, containing the elements for which the given predicate returns
true
andfalse
respectively将集合拆分为两个集合,其中包含给定谓词分别返回true和false的元素
Which we can implement using GroupBy and a two-element array as a poor-man's tuple:
我们可以使用GroupBy和一个双元素数组作为穷人的元组来实现:
public static IEnumerable<TSource>[] Partition<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate)
{
return source.GroupBy(predicate).OrderByDescending(g => g.Key).ToArray();
}
Element 0 holds the true values; 1 holds the false values. GroupBy is essentially Partition on steroids.
元素0保存真实值; 1保存虚假值。 GroupBy基本上是类固醇的分区。
And finally, Seq.iter
and Seq.iteri
map easily to foreach:
最后,Seq.iter和Seq.iteri很容易映射到foreach:
public static void Iter<TSource>(this IEnumerable<TSource> source, Action<TSource> action)
{
foreach (var item in source)
action(item);
}
public static void IterI<TSource>(this IEnumerable<TSource> source, Action<Int32, TSource> action)
{
int i = 0;
foreach (var item in source)
action(i++, item);
}
#2
- fold =
Aggregate
fold =聚合
Tell use what iter
and partition
do, and we might fill in the blanks. I'm guessing iter=SelectMany
and partition might involve Skip
/Take
?
告诉我们使用iter和partition做什么,我们可以填写空白。我猜iter = SelectMany和分区可能涉及Skip / Take?
(update) I looked up Partition - here's a crude implementation that does some of it:
(更新)我查找分区 - 这是一个粗略的实现,它做了一些:
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;
}
}
}
#3
iter exists as a method in the List class which is ForEach
iter作为List类中的方法存在,即ForEach
otherwise :
public static void iter<T>(this IEnumerable<T> source, Action<T> act)
{
foreach (var item in source)
{
act(item);
}
}
#4
ToLookup would probably be a better match for List.partition:
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];
#5
Rolling your own in C# is an interesting exercise, here are a few of mine. (See also here)
在C#中滚动你自己是一个有趣的练习,这里有一些我的。 (另见这里)
Note that iter/foreach on an IEnumerable is slightly controversial - I think because you have to 'finalise' (or whatever the word is) the IEnumerable in order for anything to actually happen.
请注意,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);
}
#6
Here is an update to dahlbyk's partition
solution.
以下是dahlbyk分区解决方案的更新。
It returned an array[]
where "element 0 holds the true values; 1 holds the false values" — but this doesn't hold when all the elements match or all fail the predicate, in which case you've got a singleton array and a world of pain.
它返回一个array [],其中“element 0保存真值; 1保存false值” - 但是当所有元素匹配或者所有谓词都失败时,这不成立,在这种情况下你有一个单例数组痛苦的世界。
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);
}