. NET มีวิธีตรวจสอบว่า List a มีรายการทั้งหมดใน List b หรือไม่?


100

ฉันมีวิธีการดังต่อไปนี้:

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

จุดประสงค์เพื่อตรวจสอบว่ารายการมีองค์ประกอบทั้งหมดของรายการอื่นหรือไม่ สำหรับฉันดูเหมือนว่าสิ่งนี้จะถูกสร้างขึ้นใน. NET อยู่แล้วนั่นเป็นกรณีนี้และฉันกำลังทำซ้ำฟังก์ชันหรือไม่

แก้ไข: ขออภัยที่ไม่ได้แจ้งล่วงหน้าว่าฉันใช้รหัสนี้ใน Mono เวอร์ชัน 2.4.2



อัลกอริทึมของคุณคือกำลังสอง O (นาโนเมตร) หากมีการจัดเรียงรายการการทดสอบว่ารายการใดรายการหนึ่งเป็นส่วนย่อยของรายการอื่นควรเป็นไปได้ในเวลา O (n + m)
พันเอก Panic

คำตอบ:


178

หากคุณใช้. NET 3.5 ก็ทำได้ง่ายๆ:

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

สิ่งนี้จะตรวจสอบว่ามีองค์ประกอบใดบ้างbที่ไม่ได้อยู่ในa- แล้วสลับผลลัพธ์

โปรดทราบว่ามันจะธรรมดากว่าเล็กน้อยในการสร้างวิธีการทั่วไปแทนที่จะเป็นคลาสและไม่มีเหตุผลที่จะต้องใช้List<T>แทนIEnumerable<T>- ดังนั้นจึงอาจเป็นที่ต้องการ:

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

1
นี่ยังไม่ทดสอบ แต่จะไม่ส่งคืน b ยกเว้น (a) .Empty (); น่าอ่านมากขึ้น?
Nils

7
ยกเว้นว่า Empty () ไม่ส่งคืนบูลีน ส่งคืน IEnumerable <T> โดยไม่มีรายการ
Peter Stephens

2
คุณสามารถใช้ LINQ กับ Objects ใน Mono ฉันเชื่อว่า ... แต่จะมีประโยชน์ถ้าคุณระบุข้อกำหนดในคำถามเพื่อเริ่มต้นด้วย คุณกำลังใช้ Mono เวอร์ชันใดอยู่
Jon Skeet

1
หากรายการมีความยาว n และ m ความซับซ้อนของเวลาของอัลกอริทึมนี้เป็นเท่าใด
พันเอก Panic

1
@ColonelPanic: สมมติว่าไม่มีการชนกันของแฮช O (n + m)
Jon Skeet


35

เพื่อความสนุกสนานคำตอบของ @JonSkeet เป็นวิธีการขยาย:

/// <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
ในทำนองเดียวกัน: ประกอบด้วย Any = public static bool ContainsAny<T>(this IEnumerable<T> haystack, IEnumerable<T> needle) { return haystack.Intersect(needle).Count() > 0; }. ฉันลองเปรียบเทียบประสิทธิภาพอย่างรวดเร็วhaystack.Count() - 1 >= haystack.Except(needle).Count();และIntersectดูเหมือนว่าจะทำได้ดีกว่าเกือบตลอดเวลา
drzaus

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

0

คุณสามารถใช้วิธีอื่น แทนที่เท่ากับและใช้สิ่งนี้

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);ฉันไม่คิดว่าสิ่งนี้จะรวบรวมและถ้าเป็นเช่นนั้นมันก็ไม่จำเป็นโดยสิ้นเชิงตามที่checkมีอยู่ในรายการ
Rohit Vipin Mathews
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.