2010-10-01 64 views
8

我有一個列表:計數的重複號碼列表

int list = { 1,1,2,3,4,4,5,7,7,7,10}; 

現在我需要做一個程序,計算出雙號。當它之前的數字相同時,數字是雙倍的。我希望你明白。所以1是雙倍,4是雙打,我們在7,7,7中得到2雙。

+1

你可以提供更多的信息,爲什麼/如何?感覺像一個家庭作業/面試問題。如果找到匹配,只需使用一個循環來解決並比較之前的當前和存儲/重置將是非常簡單的 - 只是一些額外的邏輯來停止7被計數3次。如果你想用linq或其他東西來解決它,那就更有趣了。 – 2010-10-01 13:06:31

回答

26

下面是LINQ的溶液:

var doubles = list.Skip(1) 
        .Where((number, index) => list[index] == number); 

這通過跳過列表的第一個成員創建另一序列,然後發現從具有相同索引和相同的值兩個序列元件。它將以線性時間運行,但只是因爲列表按索引提供了O(1)訪問權限。

+2

絕對+1。答案很簡潔,正確(沒有經過測試,但我承擔風險),非常聰明,並且正確地論證了爲什麼它以線性時間運行。 – Fede 2010-10-01 13:17:45

+2

+1:非常優雅! – RedFilter 2010-10-01 13:18:56

+9

想象一下,把它作爲家庭作業的答案複製,然後必須向班級(和老師)解釋...... mwahahaha – 2010-10-01 13:47:49

2

這樣的事情可能工作:

list.GroupBy (l => l).Where (l => l.Count() > 1).SelectMany (l => l).Distinct(); 

編輯:

上面的代碼中並沒有得到結果的OP通緝。下面是經編輯的版本,在下面,其靈感來自安仁的優雅的解決方案::)

list.GroupBy(l => l).Select(g=>g.Skip(1)).SelectMany (l => l); 
7

這裏有一個方法是比較簡單,只迭代一次在序列,並與任何序列作品(不只是列出):

public IEnumerable<T> FindConsecutiveDuplicates<T>(this IEnumerable<T> source) 
{ 
    using (var iterator = source.GetEnumerator()) 
    { 
     if (!iterator.MoveNext()) 
     { 
      yield break; 
     } 
     T current = iterator.Current; 
     while (iterator.MoveNext()) 
     { 
      if (EqualityComparer<T>.Default.Equals(current, iterator.Current)) 
      { 
       yield return current; 
      } 
      current = iterator.Current; 
     } 
    } 
} 

這裏是另外一個是即使在它只是一個LINQ查詢簡單,但它使用Where子句,這是討厭的副作用:

IEnumerable<int> sequence = ...; 

bool first = true; 
int current = 0; 
var result = sequence.Where(x => { 
    bool result = !first && x == current; 
    current = x; 
    first = false; 
    return result; 
}); 

第三種選擇,這是有點清潔,但使用SelectConsecutive方法基本上是從SelectPairsthis answer,但改名爲稍微清晰的:)

IEnumerable<int> sequence = ...; 
IEnumerable<int> result = sequence.SelectConsecutive((x, y) => new { x, y }) 
            .Where(z => z.x == z.y); 
+2

你是什麼意思「使用副作用」? – 2010-10-01 13:11:45

+2

我的眼睛在流血。 – 2010-10-01 13:16:21

+0

@Lasse:好點。呃,我改變了我的計劃。等一下,我會把副作用的版本備份:) – 2010-10-01 13:16:38

6

每個人似乎都試圖找到這樣做的好方法,所以這是一個非常糟糕的方式,而不是:

List<int> doubles = new List<int>(); 
Dictionary<int, bool> seenBefore = new Dictionary<int, bool>(); 

foreach(int i in list) 
{ 
    try 
    { 
     seenBefore.Add(i, true); 
    } 
    catch (ArgumentException) 
    { 
     doubles.Add(i); 
    } 
} 

return doubles; 

請不要這樣做。

+0

哈哈,幽默感+1。這是星期五畢竟 – 2010-10-01 13:24:44

+0

謝謝。我不確定是否因爲發佈錯誤答案而得票低,或者因爲發表不合格而贊成票。 :-) – teedyay 2010-10-01 13:38:32

+0

+1除了異常之外,它並不是一個完全不好的非Linq答案 - 你可以使用ContainsKey或TryGetValue來避免異常,它會很好。 – 2010-10-01 13:50:28

0

在這裏,你的答案去在C#:)

int[] intarray = new int[] { 1, 1, 2, 3, 4, 4, 5, 7, 7, 7, 10 }; 

int previousnumber = -1; 
List<int> doubleDigits = new List<int>(); 
for (int i = 0; i < intarray.Length; i++) 
{ 
    if (previousnumber == -1) { previousnumber = intarray[i]; continue; } 
    if (intarray[i] == previousnumber) 
    { 
     if (!doubleDigits.Contains(intarray[i])) 
     { 
      doubleDigits.Add(intarray[i]); 
      //Console.WriteLine("Duplicate int found - " + intarray[i]); 
      continue; 
     } 
    } 
    else 
    { 
     previousnumber = intarray[i]; 
    } 
} 
0

是(可能)的性能比使用LINQ更好,雖然一個例子可以說是那麼優雅:

for (int i = 1; i < list.Count; i++) 
    if (list[i] == list[i - 1]) 
     doubles.Add(list[i]); 
0

你可以這樣做:

list.GroupBy(i => i).Where(g => g.Count() > 1).SelectMany(g => g.Skip(1)) 

這有點像@ KJN的回答,除了我認爲它表達了「雙打」和「雙打」條款在這個問題好一點:

  1. 組的所有整數一起
  2. 只在那些出現不止一次興趣(g.Count() > 1
  3. 選擇「雙打」的平面化列表,是與第一後(g.Skip(1)

PS:我們這裏假設,即GroupBy不先排序列表,如果是的話,那那種沒有負面的預排序列表的影響...