LINQ身份的功能?(LINQ identity function?)

2019-07-19 04:44发布

只是LINQ语法有点挑剔。 我压扁的IEnumerable<IEnumerable<T>>SelectMany(x => x)

我的问题是与lambda表达式x => x 。 它看起来有点丑。 有一些静态的“身份功能”的对象,我可以使用,而不是x => x ? 类似SelectMany(IdentityFunction)

Answer 1:

注意:此答案是正确的C#3,但在某些时候(C#4 C#5?)类型改善推论使得IdentityFunction以下所示方法可以很容易地使用。


不,没有。 它必须是通用的,下手:

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

但后来类型推断是行不通的,所以你必须要做到:

SelectMany(Helpers.IdentityFunction<Foo>())

这比丑陋很多x => x

另一种可能性是,你在扩展方法把这个包:

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

不幸的是与一般的方差事情是这样的,那很可能落入各种情况下的犯规在C#3 ......它并不适用于List<List<string>>例如。 你可以使它更通用的:

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

但同样,你再有类型推断的问题,我怀疑...

编辑:为了给意见作出回应......是的,C#4,使这更容易。 或者更确切地说,它使第一Flatten方法比在C#3,更加有用的下面是其在C#4工作的例子,但C#3,因为编译器不能转换不起作用在List<List<string>>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);
        }
    }
}


Answer 2:

除非我误解了问题,下面似乎在C#4至正常工作对我来说:

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

   ...

那么你可以做你的榜样如下:

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

除了使用Defines.Identity任何地方,你会使用lambda看起来像x => x



Answer 3:

在C#6.0,如果引用FSharp.Core你可以这样做:

using static Microsoft.FSharp.Core.Operators

然后,你可以自由地做:

SelectMany(Identity)


Answer 4:

请问在您希望的方式工作的呢? 我知道乔恩发布了版本的解决方案,但他有一个第二类参数,只需要如果产生的序列类型与源序列类型不同。

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


Answer 5:

你可以接近你所需要的。 而不是常规的静态函数,可以考虑扩展方法为您IEnumerable<T>因为如果身份功能是收集的,而不是类型(集合可以生成其项目的标识功能):

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

这一点,你就不必再指定类型,并写:

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

这确实觉得有点滥用虽然,我可能会去与x=>x 。 此外,您还不能流利地使用它(以链接),所以它不会总是有用的。



Answer 6:

用C#6.0的东西越来越好。 我们可以定义由@Sahuagin建议的方式确定身份的功能:

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

然后在使用它SelectManyusing static构造函数:

using Functions;

...

var result = enumerableOfEnumerables.SelectMany(It);

我认为它看起来的这样的方式非常简洁。 我也觉得身份非常有用的功能构建字典时:

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


Answer 7:

我会去用一个简单的类单一静态属性,并根据需要上下行添加尽可能多

    internal class IdentityFunction<TSource>
    {
        public static Func<TSource, TSource> Instance
        {
            get { return x => x; }
        }
    }

    SelectMany(IdentityFunction<Foo>.Instance)


文章来源: LINQ identity function?