c# f#

El módulo F#Seq implementado en C#para IEnumerable?



(6)

F # tiene un grupo de operadores de secuencia estándar que he llegado a conocer y amar desde mi experiencia con Mathematica. F # está recibiendo mucha atención ahora, y cuando está en lanzamiento general, tengo la intención de usarlo con frecuencia.

En este momento, dado que F # aún no está en su versión general, realmente no puedo usarlo en el código de producción. LINQ implementa algunos de estos operadores utilizando nombres similares a SQL (por ejemplo, ''select'' es ''map'' y ''where'' es ''filter''), pero no puedo encontrar la implementación de ''fold'', ''iter'' o ''partition''.

¿Alguien ha visto alguna implementación C # de operadores de secuencia estándar? ¿Es esto algo que alguien debería escribir?


iter existe como un método en la clase List que es ForEach

de lo contrario:

public static void iter<T>(this IEnumerable<T> source, Action<T> act) { foreach (var item in source) { act(item); } }


  • fold = Aggregate

Dile a usar lo que hacen iter y partition , y podríamos completar los espacios en blanco. Supongo que iter = SelectMany y la partición podría implicar Skip / Take ?

(actualización) Busqué Partition - aquí hay una implementación cruda que hace algo de esto:

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; } } }


Si observa cuidadosamente, muchas operaciones Seq tienen un equivalente LINQ o pueden derivarse fácilmente. Solo mirando la lista ...

  • 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 se define así:

Divida la colección en dos colecciones, que contengan los elementos para los cuales el predicado dado devuelve true y false respectivamente

Que podemos implementar usando GroupBy y una matriz de dos elementos como tupla de un pobre:

public static IEnumerable<TSource>[] Partition<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate) { return source.GroupBy(predicate).OrderByDescending(g => g.Key).ToArray(); }

El elemento 0 contiene los valores verdaderos; 1 contiene los valores falsos. GroupBy es esencialmente partición en esteroides.

Y finalmente, Seq.iter y Seq.iteri trazan fácilmente 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); }


ToLookup probablemente sea una mejor coincidencia para 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];


Aquí hay una actualización de la solución de partition de dahlbyk .

Devolvió una array[] donde "el elemento 0 contiene los valores verdaderos; 1 contiene los valores falsos" - pero esto no se cumple cuando todos los elementos coinciden o todos fallan el predicado, en cuyo caso usted tiene una matriz singleton y un mundo de dolor

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); }


Rodar uno mismo en C # es un ejercicio interesante, aquí hay algunos de los míos. (Ver también aquí )

Tenga en cuenta que iter / foreach en un IEnumerable es un poco controvertido, creo que porque tiene que ''finalizar'' (o lo que sea la palabra) el IEnumerable para que realmente suceda algo.

//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); }