Модуль F # Seq реализован в С# для IEnumerable?
F # имеет кучу стандартных операторов последовательности, которые я узнал и полюбил из своего опыта работы с Mathematica. F # сейчас уделяет много внимания, и когда он вообще выпущен, я намерен часто его использовать.
Прямо сейчас, поскольку F # еще не выпущена в общем выпуске, я не могу использовать его в производственном коде. LINQ реализует некоторые из этих операторов, используя SQL-подобные имена (например, "select" - "map", "where" - "фильтр" ), но я не могу найти реализацию "fold", "iter" или "partition".
Кто-нибудь видел реализацию С# стандартных операторов последовательности? Это что-то кто-то должен написать?
Ответы
Ответ 1
Если вы внимательно посмотрите, многие операции Seq имеют эквивалент LINQ или могут быть легко получены. Просто посмотрев вниз список...
-
Seq.append = Concat<TSource>(IEnumerable<TSource> second)
-
Seq.concat = SelectMany<IEnumerable<TSource>, TResult>(s => s)
-
Seq.distinct_by = GroupBy(keySelector).Select(g => g.First())
-
Seq.exists = Any<TSource>(Func<TSource, bool> predicate)
-
Seq.mapi = Select<TSource, TResult>(Func<TSource, Int32, TResult> selector)
-
Seq.fold = Aggregate<TSource, TAccumulate>(TAccumulate seed, Func<TAccumulate, TSource, TAccumulate> 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();
}
Элемент 0 содержит истинные значения; 1 содержит ложные значения. GroupBy - это, по сути, раздел на стероидах.
И, наконец, 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
Расскажите, что делать iter
и partition
, и мы можем заполнить пробелы. Я предполагаю, что iter = SelectMany
и раздел может включать Skip
/Take
?
(обновление) Я посмотрел Partition - здесь грубая реализация, которая делает некоторые из них:
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 существует как метод класса List, который является ForEach
в противном случае:
public static void iter<T>(this IEnumerable<T> source, Action<T> act)
{
foreach (var item in source)
{
act(item);
}
}
Ответ 4
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
Роллинг на С# - интересное упражнение, вот несколько моих. (См. Также здесь)
Обратите внимание, что iter/foreach в IEnumerable несколько противоречиво - я думаю, потому что вы должны "финализировать" (или что бы то ни было слово) IEnumerable, чтобы что-то действительно произошло.
//mimic fsharp map function (it 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 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
Ниже приведено решение dahlbyk partition
.
Он возвратил array[]
, где "элемент 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);
}