2010-10-01 75 views
8

Tôi có một danh sách:Đếm số trùng lặp trong danh sách

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

Bây giờ tôi cần phải thực hiện một chương trình mà sẽ tính toán các con số gấp đôi. Một con số là gấp đôi khi số trước khi nó là như nhau. Tôi hy vọng bạn hiểu. Vì vậy, 1 là gấp đôi, 4 là tăng gấp đôi và chúng tôi có 2 đôi trong 7,7,7.

+1

Bạn có thể xem thêm một chút thông tin về lý do/cách thực hiện không? Cảm thấy như một bài tập về nhà/phỏng vấn. Nó sẽ rất đơn giản để giải quyết chỉ bằng cách sử dụng một vòng lặp và so sánh trước đó với hiện tại và lưu trữ/thiết lập lại nếu phù hợp được tìm thấy - chỉ cần một chút logic thêm để ngăn chặn 7 được tính 3 lần. Nếu bạn muốn nó được giải quyết trong linq hoặc một cái gì đó thì đó là thú vị hơn. –

Trả lời

26

Dưới đây là một giải pháp trong LINQ:

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

Điều này tạo ra chuỗi khác bằng cách bỏ qua các thành viên đầu tiên của danh sách, và sau đó phát hiện các yếu tố từ cả hai chuỗi có chỉ số giống nhau và cùng giá trị. Nó sẽ chạy trong thời gian tuyến tính, nhưng chỉ vì một danh sách cung cấp truy cập O(1) theo chỉ mục.

+2

Chắc chắn +1. Câu trả lời là ngắn gọn, chính xác (không được kiểm tra, nhưng tôi đang dùng rủi ro), rất thông minh, và chính xác lập luận tại sao nó chạy trong thời gian tuyến tính. – Fede

+2

+1: Rất thanh lịch! – RedFilter

+9

Hãy tưởng tượng sao chép đó như là một câu trả lời bài tập về nhà, sau đó phải giải thích cho lớp học (và giáo viên) ... mwahahaha –

2

một cái gì đó như thế này có thể làm việc:

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

EDIT:

mã trên không có được kết quả OP muốn. Dưới đây là một phiên bản được chỉnh sửa là được lấy cảm hứng từ giải pháp thanh lịch của Ani dưới đây: :)

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

Dưới đây là một cách tiếp cận đó là tương đối đơn giản, chỉ lặp một lần trong suốt chuỗi, và làm việc với bất kỳ chuỗi (không chỉ liệt kê):

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

Dưới đây là một số khác mà thậm chí còn đơn giản hơn ở chỗ nó chỉ là một truy vấn LINQ, nhưng nó sử dụng tác dụng phụ trong mệnh đề ở đâu, đó là khó chịu:

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

Một lựa chọn thứ ba, trong đó có phần sạch hơn nhưng sử dụng một phương pháp SelectConsecutive mà về cơ bản là SelectPairs từ this answer, nhưng đổi tên thành thể hơi rõ ràng hơn :)

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

Ý của bạn là "sử dụng tác dụng phụ"? –

+2

Mắt tôi đang chảy máu. –

+0

@Lasse: Điểm tốt. Um, tôi đã thay đổi kế hoạch của mình. Chờ đã, và tôi sẽ đặt phiên bản tác dụng phụ lên :) –

6

Mọi người dường như được cố gắng tìm những cách tốt để làm việc đó, vì vậy dưới đây là một cách thực sự xấu:

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; 

Xin đừng làm như vậy.

+0

haha, +1 cho cảm giác hài hước. Thứ sáu sau tất cả –

+0

Cảm ơn. Tôi đã không chắc chắn nếu tôi nhận được xuống phiếu bầu cho một câu trả lời xấu hoặc lên phiếu bầu cho rằng nó là xấu. :-) – teedyay

+0

+1 Nó không phải là một câu trả lời hoàn toàn không phải là Linq ngoài ngoại lệ - bạn có thể sử dụng ContainsKey hoặc TryGetValue để tránh ngoại lệ và nó sẽ là tốt. –

0

Ở đây bạn đi với câu trả lời trong 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

Một ví dụ đó (có lẽ) thực hiện tốt hơn so với sử dụng LINQ, mặc dù được cho là ít thanh lịch:

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

Bạn có thể làm điều này :

Câu trả lời này giống như câu trả lời của @ KJN, ngoại trừ tôi nghĩ nó thể hiện mệnh đề "tăng gấp đôi" và "gấp đôi" trong câu hỏi tốt hơn một chút:

  1. nhóm tất cả các số nguyên với nhau
  2. chỉ quan tâm đến những người xuất hiện nhiều hơn một lần (g.Count() > 1)
  3. chọn một danh sách phẳng của "đôi", là những người sau khi người đầu tiên (g.Skip(1))

PS: Chúng tôi giả định ở đây, rằng GroupBy không đầu tiên sắp xếp danh sách và nếu có, mà loại đó là không bị ảnh hưởng tiêu cực bởi một danh sách được sắp xếp trước ...

Các vấn đề liên quan