Apakah NET memiliki cara untuk memeriksa apakah Daftar a berisi semua item dalam Daftar b?


98

Saya memiliki metode berikut:

namespace ListHelper
{
    public class ListHelper<T>
    {
        public static bool ContainsAllItems(List<T> a, List<T> b)
        {
            return b.TrueForAll(delegate(T t)
            {
                return a.Contains(t);
            });
        }
    }
}

Tujuannya adalah untuk menentukan apakah sebuah List berisi semua elemen dari list lain. Tampaknya bagi saya bahwa sesuatu seperti ini akan dibangun ke dalam .NET, apakah itu masalahnya dan apakah saya menggandakan fungsionalitas?

Sunting: Mohon maaf karena tidak menyatakan sebelumnya bahwa saya menggunakan kode ini pada Mono versi 2.4.2.



Algoritme Anda adalah kuadrat O (nm). Jika daftar diurutkan, pengujian jika salah satu adalah bagian dari yang lain harus mungkin dalam waktu O (n + m).
Kolonel Panic

Jawaban:


177

Jika Anda menggunakan .NET 3.5, itu mudah:

public class ListHelper<T>
{
    public static bool ContainsAllItems(List<T> a, List<T> b)
    {
        return !b.Except(a).Any();
    }
}

Ini memeriksa apakah ada elemen byang tidak masuka - dan kemudian membalikkan hasilnya.

Perhatikan bahwa akan sedikit lebih konvensional untuk membuat metode generik daripada kelas, dan tidak ada alasan untuk mengharuskan List<T>daripada IEnumerable<T>- jadi ini mungkin lebih disukai:

public static class LinqExtras // Or whatever
{
    public static bool ContainsAllItems<T>(this IEnumerable<T> a, IEnumerable<T> b)
    {
        return !b.Except(a).Any();
    }
}

1
Ini belum diuji, tetapi tidak akan mengembalikan b.Except (a) .Empty (); jauh lebih mudah dibaca?
Nils

7
Kecuali Empty () tidak mengembalikan boolean. Ini mengembalikan IEnumerable <T> tanpa item.
Peter Stephens

2
Anda dapat menggunakan LINQ ke Objek di Mono, saya yakin ... tetapi akan sangat membantu jika Anda menyatakan persyaratan dalam pertanyaan untuk memulai. Versi Mono mana yang Anda gunakan?
Jon Skeet

1
Jika daftarnya panjang n dan m, berapa kompleksitas waktu dari algoritma ini?
Kolonel Panic

1
@ColonelPanic: Dengan asumsi tidak ada tabrakan hash, O (n + m).
Jon Skeet

38

Disertakan dalam .NET 4: Enumerable.All

public static bool ContainsAll<T>(IEnumerable<T> source, IEnumerable<T> values)
{
    return values.All(value => source.Contains(value));
}

35

Hanya untuk bersenang-senang, jawaban @ JonSkeet sebagai metode perpanjangan:

/// <summary>
/// Does a list contain all values of another list?
/// </summary>
/// <remarks>Needs .NET 3.5 or greater.  Source:  https://stackoverflow.com/a/1520664/1037948 </remarks>
/// <typeparam name="T">list value type</typeparam>
/// <param name="containingList">the larger list we're checking in</param>
/// <param name="lookupList">the list to look for in the containing list</param>
/// <returns>true if it has everything</returns>
public static bool ContainsAll<T>(this IEnumerable<T> containingList, IEnumerable<T> lookupList) {
    return ! lookupList.Except(containingList).Any();
}

2
serupa: Berisi Setiap = public static bool ContainsAny<T>(this IEnumerable<T> haystack, IEnumerable<T> needle) { return haystack.Intersect(needle).Count() > 0; }. Saya mencoba beberapa perbandingan kinerja yang cepat haystack.Count() - 1 >= haystack.Except(needle).Count();dan Intersectsepertinya selalu melakukannya dengan lebih baik.
drzaus

4
Sheesh ... Any()jangan gunakan Count() > 0: public static bool ContainsAny<T>(this IEnumerable<T> haystack, IEnumerable<T> needle) { return haystack.Intersect(needle).Any(); }
drzaus

0

Anda juga bisa menggunakan cara lain. Ganti sama dan gunakan ini

public bool ContainsAll(List<T> a,List<T> check)
{
   list l = new List<T>(check);
   foreach(T _t in a)
   {
      if(check.Contains(t))
      {
         check.Remove(t);
         if(check.Count == 0)
         {
            return true;
         }
      }
      return false;
   }
}

2
list l = new List<T>(check);Saya tidak berpikir ini akan dikompilasi dan jika ya, itu sama sekali tidak perlu karena checksudah ada daftar
Rohit Vipin Mathews
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.