2011-02-16 38 views
9

Tôi đang làm việc trên một yếu tố chung lớn nhất và ít nhất là nhiều nhiệm vụ và tôi phải liệt kê các yếu tố chung. Giao lộ() sẽ không hoạt động vì điều đó sẽ xóa các mục trùng lặp. Chứa() sẽ không hoạt động vì nếu nó thấy int trong danh sách thứ hai, nó trả về tất cả các int tương ứng từ danh sách đầu tiên. Có cách nào để làm một Giao lộ không khác biệt?Làm cách nào để thực hiện giao điểm danh sách số nguyên trong khi vẫn giữ nguyên bản sao?

chỉnh sửa: xin lỗi vì đã không cung cấp một ví dụ, đây là những gì tôi muốn nói:

nếu tôi có các bộ:

{1, 2, 2, 2, 3, 3, 4, 5} 
{1, 1, 2, 2, 3, 3, 3, 4, 4} 

tôi muốn đầu ra

{1, 2, 2, 3, 3, 4} 
+3

Nếu một là {3,3,3,3} và b là {3,3}, bạn mong đợi bao nhiêu 3s trong đầu ra? 2, 4 hoặc 6? – Ani

+0

Tôi nghĩ rằng các câu trả lời dưới đây gây nhầm lẫn cho câu hỏi. Câu hỏi đúng là 'Tìm giao điểm của hai bộ'. Vấn đề là toán tử 'Intersect' loại bỏ các bản sao - giải quyết vấn đề mà không loại bỏ các bản sao. –

+1

hai 3s ở đầu ra – DuckReconMajor

Trả lời

7
ILookup<int, int> lookup1 = list1.ToLookup(i => i); 
ILookup<int, int> lookup2 = list2.ToLookup(i => i); 

int[] result = 
(
    from group1 in lookup1 
    let group2 = lookup2[group1.Key] 
    where group2.Any() 
    let smallerGroup = group1.Count() < group2.Count() ? group1 : group2 
    from i in smallerGroup 
    select i 
).ToArray(); 

Biểu thức ở đâu là tùy chọn về mặt kỹ thuật, tôi cảm thấy nó làm cho mục đích rõ ràng hơn.


Nếu bạn muốn mã ngắn gọn hơn:

ILookup<int, int> lookup2 = list2.ToLookup(i => i); 

int[] result = 
(
    from group1 in list1.GroupBy(i => i) 
    let group2 = lookup2[group1.Key] 
    from i in (group1.Count() < group2.Count() ? group1 : group2) 
    select i 
).ToArray(); 
+0

Điều này làm việc cho tôi. Cảm ơn bạn! – DuckReconMajor

+0

+1 Tôi được nhắc nhở rất nhiều về câu hỏi này, mà cả hai chúng tôi đã trả lời. :) http://stackoverflow.com/questions/4460940/mastermind-scoring-algorithm-in-c-using-linq – Ani

+0

@DuckReconMajor, câu trả lời của tôi tránh hoàn toàn đếm cả hai nhóm phù hợp, điều này phải tốt hơn, tuy nhiên nó là ba năm muộn :-) http://stackoverflow.com/a/21776543/659190 – Jodrell

1

Bạn đang tìm kiếm một cái gì đó như thế này? Nó phải là khá nhiều O (n + m), trong đó n là số mục trong số firstm là số lượng mục trong second.

public static IEnumerable<T> Overlap<T>(this IEnumerable<T> first, 
    IEnumerable<T> second, IEqualityComparer<T> comparer = null) 
{ 
    // argument checking, optimisations etc removed for brevity 

    var dict = new Dictionary<T, int>(comparer); 

    foreach (T item in second) 
    { 
     int hits; 
     dict.TryGetValue(item, out hits); 
     dict[item] = hits + 1; 
    } 

    foreach (T item in first) 
    { 
     int hits; 
     dict.TryGetValue(item, out hits); 
     if (hits > 0) 
     { 
      yield return item; 
      dict[item] = hits - 1; 
     } 
    } 
} 
0
  • Tìm giao điểm của hai danh sách.
  • Nhóm danh mục do các mặt hàng giao nhau
  • Tham gia vào nhóm, và chọn Min (Đếm) cho từng hạng mục
  • Flatten vào một danh sách mới.

Xem dưới đây:

var intersect = list1.Intersect(list2).ToList(); 
var groups1 = list1.Where(e => intersect.Contains(e)).GroupBy(e => e); 
var groups2 = list2.Where(e => intersect.Contains(e)).GroupBy(e => e); 

var allGroups = groups1.Concat(groups2); 

return allGroups.GroupBy(e => e.Key) 
    .SelectMany(group => group 
     .First(g => g.Count() == group.Min(g1 => g1.Count()))) 
    .ToList(); 
0

Dưới đây là một cách để làm điều đó. Để công bằng, nó rất giống với câu trả lời của David B ngoại trừ việc nó sử dụng một sự tham gia để làm hiệp hội.

IEnumerable<Foo> seqA = ... 
IEnumerable<Foo> seqB = ... 

var result = from aGroup in seqA.GroupBy(x => x) 
      join bGroup in seqB.GroupBy(x => x) 
         on aGroup.Key equals bGroup.Key 
      let smallerGroup = aGroup.Count() < bGroup.Count() 
           ? aGroup : bGroup 
      from item in smallerGroup 
      select item; 
0

Bạn có thể sử dụng tiện ích mở rộng chung này mà tôi đã viết cho another answer, về bản chất nó là một câu lệnh LINQ duy nhất. Lưu ý rằng nó sử dụng Zip để tránh việc liệt kê đầy đủ các nhóm phù hợp không cần thiết.

public static IEnumerable<T> Commom<T>(
     this IEnumerable<T> source, 
     IEnumerable<T> sequence, 
     IEqualityComparer<T> comparer = null) 
{ 
    if (sequence == null) 
    { 
     return Enumerable.Empty<T>(); 
    } 

    if (comparer == null) 
    { 
     comparer = EqualityComparer<T>.Default; 
    } 

    return source.GroupBy(t => t, comparer) 
     .Join(
      sequence.GroupBy(t => t, comparer), 
      g => g.Key, 
      g => g.Key, 
      (lg, rg) => lg.Zip(rg, (l, r) => l), 
      comparer) 
     .SelectMany(g => g); 
} 

này cho phép,

new[] {1, 2, 2, 2, 3, 3, 4, 5}.Common(
    new[] {1, 1, 2, 2, 3, 3, 3, 4, 4}).ToArray() 

duy trì trật tự của dãy nguồn, như mong muốn.

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