2009-01-04 13 views
11

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.F # Seq módulo implementado en C# para IEnumerable?

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 usando nombres similares a SQL (por ejemplo, 'seleccionar' es 'mapa' y 'donde' es 'filtro'), pero no puedo encontrar implementación de 'doblar', 'iter' o 'partición'.

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

Respuesta

6
  • veces = Aggregate

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


(actualización) Miré hacia arriba Partition - he aquí una aplicación crudo que hace parte de ella: existe

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

iter como un método en la clase de lista que es ParaCada

de otro modo:

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

rodar su propia en C# es un ejercicio interesante, aquí son AF ¿ew mío? (Consulte también here)

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

A MAPI equivalente existe como una sobrecarga de Seleccionar. Además, parece un poco pesado convertir tu enumerable a una lista en lugar de hacer un ciclo foreach normal y llamar a la acción cada vez ... –

+0

No sabía sobre la sobrecarga Select, gracias por eso. ToList fue lo primero que pensé, supongo. – Benjol

14

Si se fijan bien, muchas operaciones Seq tienen un equivalente LINQ o se pueden derivar fácilmente. Solo mirando el list ...

  • 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í:

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

Qué podemos implementar el uso de 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(); 
} 

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

Y, por último, Seq.iter y Seq.iteri mapa fácilmente a 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); 
} 
+0

Problema con su 'partición' cuando todos los elementos coinciden o todos fallan el predicado: se obtiene una matriz singleton. Por favor vea [mi respuesta] (http://stackoverflow.com/a/8931453/97846), inspirada en la suya. –

1

ToLookup probablemente sería 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]; 
+0

... excepto que no es flojo. –

0

Aquí es una actualización de dahlbyk'spartition solución.

Devolvió 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 tiene un singleton matriz 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); 
} 
Cuestiones relacionadas