2009-06-18 16 views
7

मान लीजिए कि मेरे पास Value प्रकार की वस्तुओं के साथ एक सूची है। Value एक Name संपत्ति है:लगातार दोहराने वाले तत्वों को खोजने के लिए लिंक का उपयोग करें

private List<Value> values = new List<Value> { 
    new Value { Id = 0, Name = "Hello" }, 
    new Value { Id = 1, Name = "World" }, 
    new Value { Id = 2, Name = "World" }, 
    new Value { Id = 3, Name = "Hello" }, 
    new Value { Id = 4, Name = "a" }, 
    new Value { Id = 5, Name = "a" }, 
}; 

अब मैं सभी की एक सूची "दोहरा" मूल्यों (तत्वों जहां नाम संपत्ति पिछले तत्व के नाम संपत्ति के साथ समान था) प्राप्त करना चाहते हैं।
इस उदाहरण में मैं दो तत्वों "दुनिया" और "ए" (आईडी = 2 और 5) के साथ एक सूची वापस लौटना चाहता हूं।

क्या यह घटना linq के साथ संभव है? बेशक मैं इतना smth सकता था। इस तरह:

List<Value> tempValues = new List<Value>(); 
String lastName = String.Empty(); 
foreach (var v in values) 
{ 
    if (v.Name == lastName) tempValues.Add(v); 
    lastName = v.Name; 
} 

लेकिन चूंकि मैं इस प्रश्न का अधिक जटिल संदर्भ में उपयोग करना चाहता हूं, शायद एक "linqish" समाधान है।

उत्तर

7

वहाँ कुछ भी उन पंक्तियों के साथ में बनाया नहीं किया जाएगा, लेकिन यह बार-बार आप कुछ bespoke लेकिन काफी सामान्य रोल सकता है अगर आप की जरूरत:

static IEnumerable<TSource> WhereRepeated<TSource>(
    this IEnumerable<TSource> source) 
{ 
    return WhereRepeated<TSource,TSource>(source, x => x); 
} 
static IEnumerable<TSource> WhereRepeated<TSource, TValue>(
    this IEnumerable<TSource> source, Func<TSource, TValue> selector) 
{ 
    using (var iter = source.GetEnumerator()) 
    { 
     if (iter.MoveNext()) 
     { 
      var comparer = EqualityComparer<TValue>.Default; 
      TValue lastValue = selector(iter.Current); 
      while (iter.MoveNext()) 
      { 
       TValue currentValue = selector(iter.Current); 
       if (comparer.Equals(lastValue, currentValue)) 
       { 
        yield return iter.Current; 
       } 
       lastValue = currentValue; 
      } 
     } 
    } 
} 

उपयोग:

foreach (Value value in values.WhereRepeated(x => x.Name)) 
    { 
     Console.WriteLine(value.Name); 
    } 

आप चाहते हो सकता है ट्रिपलेट इत्यादि के साथ क्या करना है इसके बारे में सोचने के लिए - वर्तमान में सब कुछ छोड़कर सब कुछ मिलेगा (जो आपके विवरण से मेल खाता है), लेकिन यह काफी सही नहीं हो सकता है।

+0

यह ज़िप विधि है कि यह अधिक कुशल है। लेकिन मुझे लगता है कि ज़िप विधि थोड़ा बेहतर पढ़ती है (यह बहुत स्पष्ट है कि यह क्या करता है) –

+0

+1 वैसे, यह एक अच्छा जवाब है –

+0

एक आकर्षण की तरह काम करता है –

4

आप Zip extension लागू कर सकते हैं, फिर अपनी सूची को ज़िप के साथ ज़िप करें। (1) और फिर पंक्तियों का चयन करें।

यह काम करते हैं और काफी आसान बनाए रखने के लिए किया जाना चाहिए:

values 
    .Skip(1) 
    .Zip(items, (first,second) => first.Name==second.Name?first:null) 
    .Where(i => i != null); 

इस विधि का मामूली नुकसान यह है कि आप सूची के माध्यम से दो बार पुनरावृति है।

+0

महान समाधान है, भी एक समारोह प्रदान करते हैं। प्रदर्शन मेरे मामले में समस्या नहीं है (केवल कुछ सौ तत्व)। –

-1

आप ऐसा करने के लिए ग्रुपबी एक्सटेंशन का उपयोग कर सकते हैं।

+1

क्या आप कुछ कोड के साथ विस्तृत कर सकते हैं, कृपया? –

1

मुझे लगता है कि यह काम करेगा (अनचाहे) - यह आपको बार-बार शब्द और इसकी अनुक्रमणिका दोनों देगा। कई दोहराने के लिए आप इस सूची को पार कर सकते हैं और लगातार सूचकांक की जांच कर सकते हैं।

var query = values.Where((v,i) => values.Count > i+1 && v == values[i+1]) 
        .Select((v,i) => new { Value = v, Index = i }); 
+1

यह मुझे LINQy महसूस नहीं करता है ... और एक सामान्य IENumerable के खिलाफ काम नहीं करता है ... –

+0

नाइस - मुझे पसंद है :) @ सैम: क्या मतलब है कि टी LINQy नहीं है? यह मेरे लिए बहुत अच्छी तरह से LINQy है :) (या यदि आप वास्तव में तकनीकी, लम्बे दिन प्राप्त करना चाहते हैं .. जिसे LINQy को एक विभाजित सेक में बनाया जा सकता है) :) –

+0

@ शुद्ध, यदि मान पूरी तरह से एक आईनेमरेबल (और नहीं है) तो यह करता है काम नहीं करते, इसलिए यह एक असली विशिष्ट समाधान है जो केवल आईलीस्ट के साथ काम करता है। हालांकि यह कल्पना से मेल खाता है और काम पूरा करता है। –

-1

कुछ इस

var dupsNames = 
    from v in values 
    group v by v.Name into g 
    where g.Count > 1 // If a group has only one element, just ignore it 
    select g.Key; 

की तरह काम करना चाहिए।

dupsNames.Select(d => values.Where(v => v.Name == d)) 

यह कुंजी = नाम, मूल्यों = {नाम के साथ तत्वों}

अस्वीकरण के साथ एक समूहीकरण लौटना चाहिए: फिर आप एक दूसरे प्रश्न में परिणाम का उपयोग कर सकते ऊपर मैं परीक्षण नहीं किया था, इसलिए मैं रास्ता बंद हो सकता है।

+1

यह डुप्लिकेट के साथ कुछ भी खींच देगा, न केवल लगातार दोहराएगा। – tvanfosson

1

यहाँ एक और सरल दृष्टिकोण है कि आईडी आपकी नमूने में हमेशा की तरह अनुक्रमिक हैं, तो काम करना चाहिए है:

var data = from v2 in values 
      join v1 in values on v2.Id equals v1.Id + 1 
      where v1.Name == v2.Name 
      select v2; 
1

मैं जानता हूँ कि इस सवाल का प्राचीन है, लेकिन मैं सिर्फ इतना ही बात पर काम कर रहा था ....

static class utils 
{ 
    public static IEnumerable<T> FindConsecutive<T>(this IEnumerable<T> data, Func<T,T,bool> comparison) 
    { 
     return Enumerable.Range(0, data.Count() - 1) 
     .Select(i => new { a=data.ElementAt(i), b=data.ElementAt(i+1)}) 
     .Where(n => comparison(n.a, n.b)).Select(n => n.a); 
    } 
} 

कुछ भी के लिए काम करना चाहिए - बस तत्वों की तुलना करने के

संबंधित मुद्दे