usar una tipo son que puede funciones expresión expresiones español delegados delegado cómo convertir consulta aprender anonimos anonimas c# linq lambda linq-to-objects

c# - una - Función de identidad LINQ?



funciones lambda que son (7)

Solo un pequeño problema acerca de la sintaxis LINQ. IEnumerable<IEnumerable<T>> un IEnumerable<IEnumerable<T>> con SelectMany(x => x) .

Mi problema es con la expresión lambda x => x . Se ve un poco feo ¿Hay algún objeto estático de ''función de identidad'' que pueda usar en lugar de x => x ? Algo como SelectMany(IdentityFunction) ?


¿Funciona de la manera que quieres? Me doy cuenta de que Jon publicó una versión de esta solución, pero tiene un segundo parámetro de tipo que solo es necesario si el tipo de secuencia resultante es diferente del tipo de secuencia fuente.

public static IEnumerable<T> Flatten<T>(this IEnumerable<T> source) where T : IEnumerable<T> { return source.SelectMany(item => item); }


A menos que malinterprete la pregunta, lo siguiente parece funcionar bien para mí en C # 4:

public static class Defines { public static T Identity<T>(T pValue) { return pValue; } ...

A continuación, puede hacer lo siguiente en su ejemplo:

var result = enumerableOfEnumerables .SelectMany(Defines.Identity);

Además de usar Defines.Identity cualquier lugar, usaría una lambda que se parece a x => x .


Con C # 6.0 las cosas están mejorando. Podemos definir la función de identidad de la manera sugerida por @Sahuagin:

static class Functions { public static T It<T>(T item) => item; }

y luego usarlo en SelectMany using static constructor using static :

using Functions; ... var result = enumerableOfEnumerables.SelectMany(It);

Creo que se ve muy lacónico de esa manera. También encuentro que la función de Identidad es útil al construir diccionarios:

class P { P(int id, string name) // sad, we are not getting Primary Constructors in C# 6.0 { ID = id; Name = id; } int ID { get; } int Name { get; } static void Main(string[] args) { var items = new[] { new P(1, "Jack"), new P(2, "Jill"), new P(3, "Peter") }; var dict = items.ToDictionary(x => x.ID, It); } }


Con C # 6.0 y si hace referencia a FSharp.Core puede hacer:

using static Microsoft.FSharp.Core.Operators

Y luego eres libre de hacer:

SelectMany(Identity)


Me gustaría ir con una clase simple con una sola propiedad estática y agregar tantas como sea necesario en la línea

internal class IdentityFunction<TSource> { public static Func<TSource, TSource> Instance { get { return x => x; } } } SelectMany(IdentityFunction<Foo>.Instance)


Nota: esta respuesta fue correcta para C # 3, pero en algún momento (C # 4? C # 5?) La inferencia de tipo mejoró para que el método IdentityFunction que se muestra a continuación se pueda usar fácilmente.

No, no hay. Tendría que ser genérico, para empezar:

public static Func<T, T> IdentityFunction<T>() { return x => x; }

Pero luego la inferencia de tipo no funcionaría, por lo que tendrías que hacer:

SelectMany(Helpers.IdentityFunction<Foo>())

que es mucho más feo que x => x .

Otra posibilidad es que envuelva esto en un método de extensión:

public static IEnumerable<T> Flatten<T> (this IEnumerable<IEnumerable<T>> source) { return source.SelectMany(x => x); }

Desafortunadamente, con la varianza genérica de la forma en que es, que bien puede fallar en varios casos en C # 3 ... no sería aplicable a List<List<string>> por ejemplo. Podrías hacerlo más genérico:

public static IEnumerable<TElement> Flatten<TElement, TWrapper> (this IEnumerable<TWrapper> source) where TWrapper : IEnumerable<TElement> { return source.SelectMany(x => x); }

Pero de nuevo, entonces tienes problemas de inferencia tipo, sospecho ...

EDITAR: para responder a los comentarios ... sí, C # 4 lo hace más fácil. O más bien, hace que el primer método Flatten más útil que en C # 3. Aquí hay un ejemplo que funciona en C # 4, pero no funciona en C # 3 porque el compilador no puede convertir desde List<List<string>> a IEnumerable<IEnumerable<string>> :

using System; using System.Collections.Generic; using System.Linq; public static class Extensions { public static IEnumerable<T> Flatten<T> (this IEnumerable<IEnumerable<T>> source) { return source.SelectMany(x => x); } } class Test { static void Main() { List<List<string>> strings = new List<List<string>> { new List<string> { "x", "y", "z" }, new List<string> { "0", "1", "2" } }; foreach (string x in strings.Flatten()) { Console.WriteLine(x); } } }


Puede acercarse a lo que necesita. En lugar de una función estática regular, considere un Método de extensión para su IEnumerable<T> , como si la función de identidad fuera de la colección, no del tipo (una colección puede generar la función de identidad de sus elementos):

public static Func<T, T> IdentityFunction<T>(this IEnumerable<T> enumerable) { return x => x; }

con esto, no tiene que especificar el tipo de nuevo y escribir:

IEnumerable<IEnumerable<T>> deepList = ... ; var flat = deepList.SelectMany(deepList.IdentityFunction());

Sin embargo, esto se siente un poco abusivo, y probablemente iría con x=>x . Además, no puede usarlo con fluidez (en el encadenamiento), por lo que no siempre será útil.