2009-09-23 10 views
30

LINQ वाक्यविन्यास के बारे में बस थोड़ा सा झुकाव। मैं SelectMany(x => x) के साथ flattening हूँ।LINQ पहचान फ़ंक्शन?

मेरी समस्या लैम्ब्डा अभिव्यक्ति x => x के साथ है। यह थोड़ा बदसूरत लग रहा है। क्या कोई स्थिर 'पहचान फ़ंक्शन' ऑब्जेक्ट है जिसका उपयोग मैं x => x के बजाय कर सकता हूं? SelectMany(IdentityFunction) की तरह कुछ?

+6

मैं कभी नहीं समझूंगा कि क्यों वे एसकेआई संयोजक को सी # में शामिल नहीं करते हैं। –

उत्तर

26

नोट: इस उत्तर के लिए सी # 3 सही था, लेकिन कुछ बिंदु (सी # 4 सी # 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); 
} 

सामान्य विचरण जिस तरह से यह है, कि अच्छी तरह से # 3 सी में विभिन्न मामलों की बेईमानी से गिर सकता है के साथ दुर्भाग्य से ... ऐसा नहीं है उदाहरण के लिए List<List<string>> पर लागू हों। आप इसे अधिक सामान्य बना सकता है:

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

लेकिन फिर, आप तो प्रकार निष्कर्ष समस्याओं मिल गया है, मुझे लगता है ...

संपादित करें: टिप्पणी ... हाँ, सी # 4 बनाता है पर प्रतिक्रिया देने के यह आसान है। या बल्कि, यह अधिक उपयोगी तुलना में यह सी # 3. में है पहले Flatten विधि यहाँ एक उदाहरण है जो सी # 4 में काम करता है, लेकिन में काम नहीं करता सी # 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); 
     } 
    } 
} 
+2

धन्यवाद! यह मुझे कुछ दिलचस्प लीड भी दिया गया है। मुझे लगता है कि मैं समय के लिए x => x के साथ रहूंगा ... – Joe

+0

मैंने फ़्लैटन एक्सटेंशन विधि भी बनाने की कोशिश की (जिसे मैंने सिलेमनी कहा था लेकिन लक्ष्य वही था) और भिन्नता के साथ समस्या के कारण यह ' टी वास्तव में उपयोगी है, मुझे कई ओवरलोड की आवश्यकता होगी, इसलिए मैं x => x पर वापस चला गया ... जॉन, सी # 4/वीबी 10 में फ़्लैटन एक्सटेंशन विधि करना आसान होगा? –

+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

आपको 'selectMany'' के साथ काम करने के लिए 'Func >' वापस करने की आवश्यकता है। –

+1

सच है, यह 'चयन' के लिए काम करता है लेकिन' SelectMany' के लिए विफल रहता है - यह प्रकारों को समझ नहीं सकता है। शर्म की बात है। – Kobi

3

क्या यह आपके काम के तरीके में काम करता है? मुझे एहसास हुआ कि जॉन ने इस समाधान का एक संस्करण पोस्ट किया है, लेकिन उसके पास दूसरा प्रकार का पैरामीटर है जो केवल तभी जरूरी है जब परिणामी क्रम प्रकार स्रोत अनुक्रम प्रकार से अलग हो।

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

के रूप में:

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

    ... 

तब आप अपने उदाहरण में निम्न कर सकते हैं:

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

जब तक मैं सवाल नहीं समझ पाते, निम्नलिखित सी # 4 में मेरे लिए अच्छा काम करने लगता है अच्छी तरह से Defines.Identity का उपयोग करें, जहां आप एक लैम्ब्डा का उपयोग करेंगे जो x => x जैसा दिखता है।

+3

मुझे पता है कि यह देर से जमा हो रहा था, लेकिन मुझे वास्तव में ऐसा लगता है कि यह बेहतर प्रश्न का उत्तर देता है। – Anthony

1

सी # 6.0 चीजों के साथ बेहतर हो रहा है। हम जिस तरह से @Sahuagin ने सुझाव दिया में पहचान समारोह को परिभाषित कर सकते हैं:

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

और फिर SelectMany में इसका इस्तेमाल using 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); 
    } 
} 
2

सी # 6.0 और यदि आप FSharp.Core संदर्भ आप कर सकते हैं: मैं भी जब शब्दकोशों के निर्माण पहचान समारोह उपयोगी पाते

using static Microsoft.FSharp.Core.Operators 

और फिर अपने करने के लिए स्वतंत्र:

SelectMany(Identity) 
0

मैं एक स्थिर वर्ग के साथ एक साधारण वर्ग के साथ जाऊंगा और लाइन

लाइन के नीचे जितना आवश्यक हो उतना जोड़ता हूं
संबंधित मुद्दे