2009-09-23 12 views
30

LINQの構文についてちょっと憂慮しています。私はIEnumerable<IEnumerable<T>>SelectMany(x => x)としています。LINQアイデンティティ関数?

私の問題はラムダ式x => xです。それは少し醜いようです。 x => xの代わりに使用できる静的な「アイデンティティ関数」オブジェクトがありますか? SelectMany(IdentityFunction)のようなもの?

+6

SKIコンビネータがC#に組み込まれていない理由はわかりません。 –

答えて

26

注:(?C#4 C#5)は、この答えはC#3について正しかったが、いくつかの点で、以下に示すIdentityFunction方法は容易に使用できるように推論を向上入力。


いいえ、ありません。あなたがしなければならないと思いますので、動作しないでしょう推論を入力し

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

:しかしそれはで開始する、汎用的でなければならないであろう

x => xより多くの醜いです
SelectMany(Helpers.IdentityFunction<Foo>()) 

別の可能性は、あなたが拡張メソッドでこれをラップすることです:

残念ながら、一般的な分散だけでなくC#3に、様々な例ファウルを落ちることがあり、それは方法、と
public static IEnumerable<T> Flatten<T> 
    (this IEnumerable<IEnumerable<T>> source) 
{ 
    return source.SelectMany(x => x); 
} 

...それはないだろう例えば、List<List<string>>に該当します。

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

しかし、再び、あなたはその後、型推論の問題を持って、私は...

EDIT疑う:あなたはそれをより汎用的にすることができたコメントに対応するために...はい、C#4になりこれは簡単です。コンパイラがList<List<string>>からIEnumerable<IEnumerable<string>>

に変換できないため、C#3では動作しませんが、C#3では動作しません。
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); 
     } 
    } 
} 
+2

ありがとう!それは私にも面白いリードを与えてくれました。私はx => xのままでいると思います... – Joe

+0

Flatten拡張メソッドを作成しようとしましたが(これはSelectManyと呼ばれましたが、目標は同じでした)、分散の問題のため、 x => xに戻ってきました... Jon、Flatten拡張メソッドはC#4/VB10でやりやすいでしょうか? –

+0

@MetaKnight:投稿を編集します... –

1

あなたは必要なものに近づくことができます。代わりに、通常の静的関数の恒等関数はコレクションではなく、型であるかのように、(コレクションは、そのアイテムのアイデンティティ関数を生成することができます)、あなたの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で行くと思います。また、それを流暢に(連鎖的に)使用することはできないので、必ずしも有用ではありません。

+0

'Func >'を返して、 'SelectMany'で動作させる必要があります。 –

+1

True、 'Select'では動作しますが、' SelectMany'では失敗します。タイプを特定できません。恥。 – Kobi

3

これはどのように機能しますか?私はJonがこのソリューションのバージョンを投稿したことを認識していますが、結果のシーケンスタイプがソースシーケンスタイプと異なる場合にのみ必要な第2タイプのパラメータを持っています。

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

私は質問を誤解していない限り、次はC#4で私のために正常に動作するようです:

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

    ... 

あなたは、あなたの例では、次の操作を行うことができます。

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

として、よくDefines.Identityを使用してください。x => xのようなラムダを使用します。

+3

私はこれが遅れて提出されたことを知っていますが、私は本当にそれがより良い質問に答えるように感じています。 – Anthony

1

C#6.0では状況が改善しています。

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

、その後SelectManyusing staticコンストラクタを使用します:私たちは@Sahuaginによって提案された方法でアイデンティティ関数を定義することができ、私はそれがこのように非常に簡潔に見えると思います

using Functions; 

... 

var result = enumerableOfEnumerables.SelectMany(It); 

を。 C#6.0では

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

、あなたがFSharp.Coreを参照する場合は行うことができます:辞書を構築するとき、私は便利なアイデンティティ機能をも見つける

using static Microsoft.FSharp.Core.Operators 

そして行うことがあなたの自由:

SelectMany(Identity) 
0

私は単一の静的なプロパティを持つ単純なクラスに行き、必要な数を行の下に追加します。

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

    SelectMany(IdentityFunction<Foo>.Instance) 
関連する問題