Quantifiers - Any & All & Contains

Quantifiers - Any & All & Contains

原始文章將記錄於此
https://github.com/s0920832252/LinQ-Note

Any , All and Contains 均是非常容易會使用到的方法 , 另外需要注意的是這三個方法都不具有延遲執行的特性.

Any

判斷序列的任何項目是否符合條件或包含任何項目

Any 有兩個多載方法如下

  1.  public static bool Any<TSource> (this IEnumerable<TSource> source);
    
    • 判斷序列中包含的項目數是否不為零
  2.  public static bool Any<TSource> (this IEnumerable<TSource> source, Func<TSource,bool> predicate);
    
    • 判斷序列中的任何項目是否有任何一個符合條件
    • 實作上與 First 類似 , 差別在於回傳值. First 會回傳第一個符合條件的項目 , Any 則是發現第一個符合條件的項目時會回傳 true , 反之若沒有任何項目符合條件會回傳 false

使用時機

  • 需要判斷集合是否包含任何項目.
  • 需要使用 predicate 表達指定的項目 , 以判斷集合中是否存在某個指定項目

Any 的用法

// 列出每個人持有的電話 , 若是他沒有電話則不要列出.
static void Main(string[] args)
{
    var people = new[]
    {
        new  { Name="大名" , CellPhone = new string[]{"0989112266","03-29007536"}},
        new  { Name="小黃" , CellPhone = new string[]{"0961334475"}},
        new  { Name="大龍" , CellPhone = new string[]{}},
        new  { Name="包子" , CellPhone = new string[]{"0953793211", "0961751112", "0975362475"}}
    };

    // 使用 Where 篩選出有電話的人 , 透過 Any 判斷這個人是否有電話
    var query = people.Where(person => person.CellPhone.Any())
                      .SelectMany((person) => person.CellPhone, (person, phone) => $"{person.Name} 持有的手機號碼是 {phone}");

    // 阿龍沒有手機 , 所以不會 print 阿龍出來
    foreach (var item in query)
    {
        Console.WriteLine(item);
    }

    Console.ReadKey();
}
輸出結果

大名 持有的手機號碼是 0989112266
大名 持有的手機號碼是 03-29007536
小黃 持有的手機號碼是 0961334475
包子 持有的手機號碼是 0953793211
包子 持有的手機號碼是 0961751112
包子 持有的手機號碼是 0975362475

// 找出持有 03- 的電話的人所持有的手機號碼
static void Main(string[] args)
{
    var people = new[]
    {
        new  { Name="大名" , CellPhone = new string[]{"0989112266","03-29007536"}},
        new  { Name="小黃" , CellPhone = new string[]{"0961334475"}},
        new  { Name="大龍" , CellPhone = new string[]{}},
        new  { Name="包子" , CellPhone = new string[]{"0953793211", "0961751112", "0975362475"}}
    };
    // 透過 Any 判斷這個人是否持有 03- 開頭的手機
    var query = people.Where(person => person.CellPhone.Any(num => num.Contains("03-")))
                      .SelectMany((person) => person.CellPhone, (person, phone) => $"{person.Name} 持有的手機號碼是 {phone}");

    foreach (var item in query)
    {
        Console.WriteLine(item);
    }

    Console.ReadKey();
}
輸出結果

大名 持有的手機號碼是 0989112266
大名 持有的手機號碼是 03-29007536


簡單實作自己的 Any

public static bool MyAny<TSource>(this IEnumerable<TSource> source)
{
    if (source is null)
    {
        throw new Exception("source is null");
    }

    return source.GetEnumerator().MoveNext();
}
public static bool MyAny<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate)
{
    if (source is null || predicate is null)
    {
        throw new Exception("either source or predicate is null");
    }

    foreach (var item in source)
    {
        if (predicate(item))
        {
            return true;
        }
    }
    return false;
}

All

判斷序列的所有項目是否全都符合條件

public static bool All<TSource> (this IEnumerable<TSource> source, Func<TSource,bool> predicate);

使用時機

  • 需要使用 predicate 表達指定的項目 , 以判斷集合中項目是否全都滿足這個指定項目

All 的用法

class Pet
{
    public string Name { get; set; }
    public int Age { get; set; }
}

static void Main(string[] args)
{
    // Create an array of Pets.
    Pet[] pets = {  new Pet { Name="Barley", Age=10 },
                    new Pet { Name="Boots", Age=4 },
                    new Pet { Name="Whiskers", Age=6 }
                 };

    // Determine whether all pet names 
    // in the array start with 'B'.
    bool allStartWithB = pets.All(pet => pet.Name.StartsWith("B"));

    Console.WriteLine("{0} pet names start with 'B'.", allStartWithB ? "All" : "Not all");

    Console.ReadKey();
}
輸出結果

Not all pet names start with ‘B’.

簡單實作自己的 All

public static bool MyAll<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate)
{
    if (source is null || predicate is null)
    {
        throw new Exception("source or predicate is null");
    }

    foreach (var element in source)
    {
        if (!predicate(element))
        {
            return false;
        }
    }
    return true;
}

Contains

判斷序列是否包含指定的項目

Contains 有兩個多載方法

  1. public static bool Contains<TSource> (this IEnumerable<TSource> source, TSource value);
    • 使用預設的相等比較子 (Comparer) 來判斷序列是否包含指定的項目。
  2. public static bool Contains<TSource> (this IEnumerable<TSource> source, TSource value, IEqualityComparer<TSource> comparer);
    • 使用指定的 IEqualityComparer<T> 來判斷序列是否包含指定的項目。

使用時機

  • 想要找到指定的某個項目是否已存在於集合中.

Contains 的用法

// 判斷 fruits 中是否存在 mango
static void Main(string[] args)
{
     string[] fruits = { "apple", "banana", "mango", "orange", "passionfruit", "grape" };

     string fruit = "mango";

     bool hasMango = fruits.Contains(fruit);

     Console.WriteLine("The array {0} contain '{1}'.", hasMango ? "does" : "does not", fruit);

     Console.ReadKey();
}
輸出結果

The array does contain ‘mango’.

class EqualityComparer<TSource> : IEqualityComparer<TSource> where TSource : class
{
     private PropertyInfo[] properties = null;
     public bool Equals(TSource x, TSource y)
     {
          if (properties == null)
               properties = x.GetType().GetProperties();
          return properties.Aggregate(true, (result, item) =>
          {
               return result && item.GetValue(x).Equals(item.GetValue(y));
          });
     }

     public int GetHashCode(TSource obj)
     {
          if (properties == null)
               properties = obj.GetType().GetProperties();
          return properties.Aggregate(0, (result, item) =>
          {
               return result ^ item.GetValue(obj).GetHashCode();
          });
     }
}

public class Product
{
     public string Name { get; set; }
     public int Code { get; set; }
}

static void Main(string[] args)
{
     Product[] fruits = { 
         new Product { Name = "apple", Code = 9 },
         new Product { Name = "orange", Code = 4 },
         new Product { Name = "lemon", Code = 12 } 
     };

     Product apple = new Product { Name = "apple", Code = 9 };
     Product kiwi = new Product { Name = "kiwi", Code = 8 };

     EqualityComparer<Product> prodc = new EqualityComparer<Product>();

     bool hasApple = fruits.Contains(apple, prodc);
     bool hasKiwi = fruits.Contains(kiwi, prodc);

     Console.WriteLine("Apple? " + hasApple);
     Console.WriteLine("Kiwi? " + hasKiwi);

     Console.ReadKey();
}
輸出結果

Apple? True
Kiwi? False

簡單實作自己的 Contains

public static bool MyContains<TSource>(this IEnumerable<TSource> source, TSource value)
{
     if (source is null)
     {
          throw new Exception("source is null");
     }

     foreach (var element in source)
     {
          if (element.Equals(value))
          {
               return true;
          }
     }
     return false;
}

public static bool MyContains<TSource>(this IEnumerable<TSource> source, TSource value, IEqualityComparer<TSource> comparer)
{
     if (source is null || comparer is null)
     {
          throw new Exception("source or comparer is null");
     }

     foreach (var element in source)
     {
          if (comparer.Equals(element, value))
          {
               return true;
          }
     }
     return false;
}

Summary

  • Any 和 Contains 均可以用來判斷集合中是否包含指定的項目 , 其差別在於 Any 是透過 predicate 表達指定的項目 , 而 Contains 則是直接丟入指定的項目.

Thank you!

You can find me on

若有謬誤 , 煩請告知 , 新手發帖請多包涵

:100: :muscle: :tada: :sheep: