2010-04-27 39 views
8

Tôi có một số List<string> có chứa các bản sao và tôi cần tìm các chỉ mục của mỗi mục.Cách thanh lịch nhất để tìm chỉ mục các mục trùng lặp trong C# Danh sách

Cách thanh lịch nhất, hiệu quả hơn là lặp qua tất cả các mục. Tôi đang trên NET 4.0. Vì vậy LINQ là một lựa chọn. Tôi đã thực hiện tấn tìm kiếm và kết nối tìm thấy bất cứ điều gì.

mẫu dữ liệu:

var data = new List<string>{"fname", "lname", "home", "home", "company"}(); 

tôi cần để có được các chỉ số của "nhà".

+11

Có bao nhiêu mục trong danh sách? Nó được sắp xếp? Nó có thể sắp xếp được không? Bạn so sánh bình đẳng như thế nào? Nó có phải làm việc cho bất kỳ loại dữ liệu nào hay chỉ là chuỗi? Tại sao bạn đặt bản sao trong danh sách ở nơi đầu tiên? Bạn yêu cầu cho thanh lịch nhất và hiệu quả nhất nhưng những người thường xuyên đối lập; cái nào thực sự quan trọng hơn? –

+1

Tại sao bạn nói "khác hơn là lặp qua các mục"? Một người nào đó phải lặp qua các mục tại một số điểm - cho dù đó là bạn hay linq mà nó chắc chắn là không liên quan. – Stewart

Trả lời

19

Bạn có thể tạo đối tượng từ mỗi mục chứa chỉ mục của nó, sau đó nhóm trên giá trị và lọc ra các nhóm chứa nhiều đối tượng. Bây giờ bạn có một danh sách nhóm với các đối tượng có chứa các văn bản và chỉ số ban đầu của họ:

var duplicates = data 
    .Select((t,i) => new { Index = i, Text = t }) 
    .GroupBy(g => g.Text) 
    .Where(g => g.Count() > 1); 
+0

Tôi thích giải pháp này! Dễ đọc và nhanh chóng! –

+0

Cảm ơn đây là giải pháp thanh lịch nhất mà tôi có thể tìm thấy –

3
using System; 
using System.Collections.Generic; 

class Program 
{ 
    static void Main(string[] args) 
    { 
     var data = new List<string> { "fname", "lname", "home", "home", "company" }; 
     foreach (var duplicate in FindDuplicates(data)) 
     { 
      Console.WriteLine("Duplicate: {0} at index {1}", duplicate.Item1, duplicate.Item2); 
     } 
    } 

    public static IEnumerable<Tuple<T, int>> FindDuplicates<T>(IEnumerable<T> data) 
    { 
     var hashSet = new HashSet<T>(); 
     int index = 0; 
     foreach (var item in data) 
     { 
      if (hashSet.Contains(item)) 
      { 
       yield return Tuple.Create(item, index); 
      } 
      else 
      { 
       hashSet.Add(item); 
      } 
      index++; 
     } 
    } 
} 
0

Làm thế nào về một cái gì đó như thế này

var data = new List<string>{"fname", "lname", "home", "home", "company"}; 

      var duplicates = data 
          .Select((x, index) => new { Text = x, index}) 
          .Where(x => ( data 
              .GroupBy(i => i) 
              .Where(g => g.Count() > 1) 
              .Select(g => g.Key).ToList() 
             ).Contains(x.Text)); 
+0

Interresting, nhưng rất kém hiệu quả. Bạn nên tạo tra cứu một lần thay vì một lần cho mỗi mục trong danh sách. Để có hiệu quả tra cứu phải là một HashSet, không phải là một danh sách. – Guffa

0

Bản thân tôi cần phải tìm và loại bỏ các bản sao từ danh sách dây. Lần đầu tiên tôi tìm kiếm các chỉ mục của các mục trùng lặp và sau đó lọc danh sách theo cách chức năng bằng LINQ mà không làm thay đổi danh sách gốc:

public static IEnumerable<string> RemoveDuplicates(IEnumerable<string> items) 
{ 
    var duplicateIndexes = items.Select((item, index) => new { item, index }) 
          .GroupBy(g => g.item) 
          .Where(g => g.Count() > 1) 
          .SelectMany(g => g.Skip(1), (g, item) => item.index); 
    return items.Where((item, index) => !duplicateIndexes.Contains(index)); 
} 
Các vấn đề liên quan