2011-09-15 21 views
8

cách hiệu quả nhất để viết một phương pháp mà sẽ so sánh n danh sách và trả lại tất cả các giá trị mà không xuất hiện trong tất cả danh sách là gì, do đóLINQ có giá trị không được chia sẻ trên nhiều danh sách

var lists = new List<List<int>> { 
            new List<int> { 1, 2, 3, 4 }, 
            new List<int> { 2, 3, 4, 5, 8 }, 
            new List<int> { 2, 3, 4, 5, 9, 9 }, 
            new List<int> { 2, 3, 3, 4, 9, 10 } 
           }; 


public IEnumerable<T> GetNonShared(this IEnumerable<IEnumerable<T>> lists) 
{ 
    //...fast algorithm here 
} 

nên

rằng

danh sách.GetNonShared();

lợi nhuận 1, 5, 8, 9, 10

tôi đã

public IEnumerable<T> GetNonShared(this IEnumerable<IEnumerable<T>> lists) 
{ 
    return list.SelectMany(item => item) 
      .Except(lists.Aggregate((a, b) => a.Intersect(b)); 
} 

Nhưng tôi không chắc chắn nếu đó là hiệu quả. Đặt hàng không quan trọng. Cảm ơn!

+1

Bạn không chắc chắn nếu đó là "hiệu quả"? Đó không phải là vấn đề. Vấn đề là: ngữ nghĩa có chính xác không và nó có đáp ứng các yêu cầu về hiệu năng của bạn không? Ngữ nghĩa của việc thực hiện của bạn là chính xác. Chỉ bạn mới có thể biết liệu nó có đáp ứng các yêu cầu về hiệu suất của bạn hay không. – jason

Trả lời

5
 public static IEnumerable<T> GetNonShared<T>(this IEnumerable<IEnumerable<T>> list) 
     { 
      return list.SelectMany(x => x.Distinct()).GroupBy(x => x).Where(g => g.Count() < list.Count()).Select(group => group.Key); 
     } 
+0

Thêm một trong 9 danh sách OP được cung cấp và điều này không thành công. –

+0

được sửa bằng .Distinct() – mironych

2

EDIT: Tôi nghĩ rằng tôi muốn nghĩ về nó như thế này ...

Bạn muốn đoàn của tất cả các danh sách, trừ đi ngã tư của tất cả các danh sách. Đó là hiệu quả những gì ban đầu của bạn làm, để lại Except để thực hiện thao tác "đặt" là Union mặc dù đã nhập các mục nhập trùng lặp. Trong trường hợp này tôi nghi ngờ bạn có thể làm điều này một cách hiệu quả hơn chỉ xây dựng hai HashSet s và làm tất cả công việc tại chỗ:

public IEnumerable<T> GetNonShared(this IEnumerable<IEnumerable<T>> lists) 
{   
    using (var iterator = lists.GetEnumerator()) 
    { 
     if (!iterator.MoveNext()) 
     { 
      return new T[0]; // Empty 
     } 

     HashSet<T> union = new HashSet<T>(iterator.Current.ToList()); 
     HashSet<T> intersection = new HashSet<T>(union); 
     while (iterator.MoveNext()) 
     { 
      // This avoids iterating over it twice; it may not be necessary, 
      // it depends on how you use it. 
      List<T> list = iterator.Current.Toist(); 
      union.UnionWith(list); 
      intersection = intersection.IntersectWith(list); 
     } 
     union.ExceptWith(intersection); 
     return union; 
    } 
} 

Lưu ý rằng điều này bây giờ là háo hức, không hoãn.


Dưới đây là một lựa chọn thay thế:

public IEnumerable<T> GetNonShared(this IEnumerable<IEnumerable<T>> lists) 
{ 
    return list.SelectMany(list => list) 
       .GroupBy(x => x) 
       .Where(group => group.Count() < lists.Count) 
       .Select(group => group.Key); 
} 

Nếu nó có thể cho một danh sách để chứa cùng một mục nhiều hơn một lần, bạn muốn một cuộc gọi riêng biệt trong đó:

public IEnumerable<T> GetNonShared(this IEnumerable<IEnumerable<T>> lists) 
{ 
    return list.SelectMany(list => list.Distinct()) 
       .GroupBy(x => x) 
       .Where(group => group.Count() < list.Count) 
       .Select(group => group.Key); 
} 

EDIT: Bây giờ tôi đã sửa chữa điều này, tôi hiểu mã ban đầu của bạn ... và tôi nghi ngờ tôi có thể tìm thấy một cái gì đó tốt hơn ... suy nghĩ ...

+1

Điều này loại trừ 5 & 9. Anh ta chỉ muốn các giá trị chung cho tất cả các danh sách bị loại trừ. –

+0

@Austin: Ah, misread. Dễ dàng sửa chữa mặc dù :) –

+0

Ông flattens tất cả các danh sách, và sau đó loại bỏ các mục có trong tất cả các danh sách (đó là tính toán của các hoạt động tổng hợp). – jason

0

Tôi nghĩ bạn cần tạo một bước trung gian, tìm tất cả các mục mà phổ biến cho tất cả các danh sách. Điều này rất dễ làm với bộ logic - đó chỉ là tập hợp các mục trong danh sách đầu tiên được giao với tập các mục trong mỗi danh sách kế tiếp. Tôi không nghĩ rằng bước của doable trong LINQ, mặc dù.

class Program 
{ 
    static void Main(string[] args) 
    { 
     IEnumerable<IEnumerable<int>> lists = new List<IEnumerable<int>> { 
           new List<int> { 1, 2, 3, 4 }, 
           new List<int> { 2, 3, 4, 5, 8 }, 
           new List<int> { 2, 3, 4, 5, 9, 9 }, 
           new List<int> { 2, 3, 3, 4, 9, 10 } 
          }; 

     Console.WriteLine(string.Join(", ", GetNonShared(lists) 
      .Distinct() 
      .OrderBy(x => x) 
      .Select(x => x.ToString()) 
      .ToArray())); 
     Console.ReadKey(); 
    } 

    public static HashSet<T> GetShared<T>(IEnumerable<IEnumerable<T>> lists) 
    { 
     HashSet<T> result = null; 
     foreach (IEnumerable<T> list in lists) 
     { 
      result = (result == null) 
         ? new HashSet<T>(list) 
         : new HashSet<T>(result.Intersect(list)); 
     } 
     return result; 
    } 

    public static IEnumerable<T> GetNonShared<T>(IEnumerable<IEnumerable<T>> lists) 
    { 
     HashSet<T> shared = GetShared(lists); 
     return lists.SelectMany(x => x).Where(x => !shared.Contains(x)); 
    } 
} 
0
public static IEnumerable<T> GetNonShared<T>(this IEnumerable<IEnumerable<T>> list) 
{ 
    var lstCnt=list.Count(); //get the total number if items in the list         
    return list.SelectMany (l => l.Distinct()) 
     .GroupBy (l => l) 
     .Select (l => new{n=l.Key, c=l.Count()}) 
     .Where (l => l.c<lstCnt) 
     .Select (l => l.n) 
     .OrderBy (l => l) //can be commented 
     ; 
} 

// sử dụng HashSet và SymmetricExceptWith cho .net> = 4,5

+0

hữu ích hơn để giải thích câu trả lời của bạn. –

+1

về cơ bản nó nhận được tất cả các mục riêng biệt từ mỗi danh sách riêng lẻ thành một danh sách phẳng (selectMany) sau đó thực hiện một nhóm từng mục theo giá trị của nó để nhận được bao nhiêu lần (l.cn) (l.n) xảy ra (trong danh sách phẳng). Nếu l.c (cho bất kỳ mục nào) nhỏ hơn tổng số danh sách riêng lẻ (lstCnt) thì chúng ta có thể nói chắc chắn rằng mục đó không tồn tại trong ít nhất một danh sách. – SKG

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