2009-05-18 23 views
320

在集合上使用Linq,以下幾行代碼有什麼區別?Linq。所有VS.Exists - 有什麼區別?

if(!coll.Any(i => i.Value)) 

​​

更新1

當我拆開.Exists它看起來像有沒有代碼。

更新2

任何人都知道爲什麼沒有代碼中有這一個?

+9

如何代碼編譯你看起來像?你是如何拆解的? ILDASM?你期望找到什麼,但沒有? – Meinersbur 2010-02-06 14:54:46

回答

335

見文檔

List.Exists(對象方法 - MSDN)

確定列表(T)是否含有匹配由指定的謂詞所定義的條件的元素。

從.NET 2.0開始就存在,所以在LINQ之前。意圖與謂詞代表一起使用,但lambda表達式向後兼容。此外,只列出了這一點(甚至沒有的IList)

IEnumerable.Any(擴展方法 - MSDN)

確定序列中的任何元素是否滿足條件。

這是.NET 3中的新增功能。5並使用Func(TSource,bool)作爲參數,所以這是爲了與lambda表達式和LINQ一起使用。

在行爲上,它們是相同的。

+1

我後來做了[在另一個線程中的帖子](http:// stackoverflow。com/a/21436464/1336654)其中我列出了.NET 2`List <>`實例方法的所有Linq「等價物」。 – 2015-12-01 08:44:44

169

區別在於Any是System.Linq.Enumerable上定義的任何IEnumerable<T>的擴展方法。它可以用於任何IEnumerable<T>實例。

存在似乎不是擴展方法。我的猜測是coll是List<T>。如果是這樣的話Exists是一個與Any非常相似的實例方法。

總之,方法基本相同。一個比另一個更普遍。

  • 任何也有一個重載不帶參數,簡單地查找在枚舉的任何項目。
  • 存在沒有這樣的過載。
+10

恩把(+1)。列表。自2 .Net以來一直存在,但僅適用於通用列表。 IEnumerable 。任何被添加到.Net 3作爲擴展,適用於任何可枚舉集合。還有類似的成員,如列表.Count,這是一個屬性和IEnumerable .Count() - 一種方法。 – Keith 2009-05-18 19:53:01

4

此外,只有當值是bool類型時才能使用。通常這與謂詞一起使用。通常使用任何謂詞來查找是否存在滿足給定條件的元素。在這裏,你只是從你的元素我到一個布爾屬性做一個地圖。它將搜索Value屬性爲true的「i」。完成後,該方法將返回true。

38

TLDR;性能方面Any似乎要慢一些(如果我正確設置此同時評估值在幾乎同一時間)

 var list1 = Generate(1000000); 
     var forceListEval = list1.SingleOrDefault(o => o == ""); 
     if (forceListEval != "sdsdf") 
     { 
      var s = string.Empty; 
      var start2 = DateTime.Now; 
      if (!list1.Exists(o => o == "")) 
      { 
       var end2 = DateTime.Now; 
       s += " Exists: " + end2.Subtract(start2); 
      } 

      var start1 = DateTime.Now; 
      if (!list1.Any(o => o == "")) 
      { 
       var end1 = DateTime.Now; 
       s +=" Any: " +end1.Subtract(start1); 
      } 

      if (!s.Contains("sdfsd")) 
      { 

      } 

測試列表生成:

private List<string> Generate(int count) 
    { 
     var list = new List<string>(); 
     for (int i = 0; i < count; i++) 
     { 
      list.Add(new string(
      Enumerable.Repeat("ABCDEFGHIJKLMNOPQRSTUVWXYZ", 13) 
       .Select(s => 
       { 
        var cryptoResult = new byte[4]; 
        new RNGCryptoServiceProvider().GetBytes(cryptoResult); 
        return s[new Random(BitConverter.ToInt32(cryptoResult, 0)).Next(s.Length)]; 
       }) 
       .ToArray())); 
     } 

     return list; 
    } 

10M的記錄

「Any:00:00:00.3770377 Existing:00:00:00.2490249」

使用5M記錄

「任何:00:00:00.0940094存在:00:00:00.1420142」

用1M記錄

「任何00:00 :00.0180018 Exists:00:00:00.0090009「

隨着500k,(我也翻轉看到他們得到評估順序如果沒有與任何一個關聯的附加操作運行第一)

「存在:00:00:00.0050005任何:00:00:00.0100010」。

隨着100K記錄

「存在:00:00:00.0010001任何:00:00:00.0020002」

這似乎Any噸Ø由2

編輯的幅度較慢:對於5和10M記錄我改變了它產生的列表,並Exists突然變得慢Any這意味着有什麼東西錯在我測試的方式方法。

新的測試機制:

private static IEnumerable<string> Generate(int count) 
    { 
     var cripto = new RNGCryptoServiceProvider(); 
     Func<string> getString =() => new string(
      Enumerable.Repeat("ABCDEFGHIJKLMNOPQRSTUVWXYZ", 13) 
       .Select(s => 
       { 
        var cryptoResult = new byte[4]; 
        cripto.GetBytes(cryptoResult); 
        return s[new Random(BitConverter.ToInt32(cryptoResult, 0)).Next(s.Length)]; 
       }) 
       .ToArray()); 

     var list = new ConcurrentBag<string>(); 
     var x = Parallel.For(0, count, o => list.Add(getString())); 
     return list; 
    } 

    private static void Test() 
    { 
     var list = Generate(10000000); 
     var list1 = list.ToList(); 
     var forceListEval = list1.SingleOrDefault(o => o == ""); 
     if (forceListEval != "sdsdf") 
     { 
      var s = string.Empty; 

      var start1 = DateTime.Now; 
      if (!list1.Any(o => o == "")) 
      { 
       var end1 = DateTime.Now; 
       s += " Any: " + end1.Subtract(start1); 
      } 

      var start2 = DateTime.Now; 
      if (!list1.Exists(o => o == "")) 
      { 
       var end2 = DateTime.Now; 
       s += " Exists: " + end2.Subtract(start2); 
      } 

      if (!s.Contains("sdfsd")) 
      { 

      } 
     } 

EDIT2:確定,所以,以消除產生我寫的所有文件,現在進行閱讀測試數據有任何影響。

private static void Test() 
    { 
     var list1 = File.ReadAllLines("test.txt").Take(500000).ToList(); 
     var forceListEval = list1.SingleOrDefault(o => o == ""); 
     if (forceListEval != "sdsdf") 
     { 
      var s = string.Empty; 
      var start1 = DateTime.Now; 
      if (!list1.Any(o => o == "")) 
      { 
       var end1 = DateTime.Now; 
       s += " Any: " + end1.Subtract(start1); 
      } 

      var start2 = DateTime.Now; 
      if (!list1.Exists(o => o == "")) 
      { 
       var end2 = DateTime.Now; 
       s += " Exists: " + end2.Subtract(start2); 
      } 

      if (!s.Contains("sdfsd")) 
      { 
      } 
     } 
    } 

10M

「任何:00:00:00.1640164存在:00:00:00。0750075"

5M

「任何:00:00:00.0810081存在:00:00:00.0360036」

1M

「任何00:00 :00.0190019 Exists:00:00:00.0070007「

500K

「任何:00:00:00.0120012存在:00:00:00.0040004」

enter image description here

+1

不要辜負你,但我對這些基準感到懷疑。看數字:每個結果都有一個遞歸發生(3770377:2490249)。至少對我來說,這是一個肯定的跡象,有些事情是不正確的。我對這裏的數學不是百分之百肯定的,但我認爲每個價值在999^999(或999!也許?)中發生的重複模式的可能性是1。所以它發生** 8次**的機會是無限小的。我認爲這是因爲你使用[DateTime進行基準測試](http://stackoverflow.com/questions/28637/is-datetime-now-the-best-way-to-measure-a-functions-performance)。 – 2016-09-27 06:53:29

+0

@JerriKangasniemi獨立重複相同的操作應該總是花費相同的時間,同樣的重複多次。是什麼讓你說它是DateTime? – 2016-09-27 06:57:05

6

Matas' answer標杆上的延續。

TL/DR:Exists()和Any()同樣快。

首先:使用秒錶進行基準測試並不精確(see series0ne's answer on a different, but similiar, topic),但它比DateTime精確得多。

獲得真正精確讀數的方法是使用性能分析。但是,瞭解兩種方法的性能如何相互影響的一種方法是通過執行兩種方法,然後比較每個方法的最快執行時間。這樣一來,JITing和其他噪音給我們帶來不好的讀數並不重要(因爲它在確實是),因爲從某種意義上說,兩次執行都是「同樣誤導」。

static void Main(string[] args) 
    { 
     Console.WriteLine("Generating list..."); 
     List<string> list = GenerateTestList(1000000); 
     var s = string.Empty; 

     Stopwatch sw; 
     Stopwatch sw2; 
     List<long> existsTimes = new List<long>(); 
     List<long> anyTimes = new List<long>(); 

     Console.WriteLine("Executing..."); 
     for (int j = 0; j < 1000; j++) 
     { 
      sw = Stopwatch.StartNew(); 
      if (!list.Exists(o => o == "")) 
      { 
       sw.Stop(); 
       existsTimes.Add(sw.ElapsedTicks); 
      } 
     } 

     for (int j = 0; j < 1000; j++) 
     { 
      sw2 = Stopwatch.StartNew(); 
      if (!list.Exists(o => o == "")) 
      { 
       sw2.Stop(); 
       anyTimes.Add(sw2.ElapsedTicks); 
      } 
     } 

     long existsFastest = existsTimes.Min(); 
     long anyFastest = anyTimes.Min(); 

     Console.WriteLine(string.Format("Fastest Exists() execution: {0} ticks\nFastest Any() execution: {1} ticks", existsFastest.ToString(), anyFastest.ToString())); 
     Console.WriteLine("Benchmark finished. Press any key."); 
     Console.ReadKey(); 
    } 

    public static List<string> GenerateTestList(int count) 
    { 
     var list = new List<string>(); 
     for (int i = 0; i < count; i++) 
     { 
      Random r = new Random(); 
      int it = r.Next(0, 100); 
      list.Add(new string('s', it)); 
     } 
     return list; 
    } 

執行上面的代碼的4倍(而這又與1 000 000個元素的列表上做1 000 Exists()Any())後,不難看出,這些方法是幾乎一樣快。

Fastest Exists() execution: 57881 ticks 
Fastest Any() execution: 58272 ticks 

Fastest Exists() execution: 58133 ticks 
Fastest Any() execution: 58063 ticks 

Fastest Exists() execution: 58482 ticks 
Fastest Any() execution: 58982 ticks 

Fastest Exists() execution: 57121 ticks 
Fastest Any() execution: 57317 ticks 

略有區別,但它太小,不被背景噪音來解釋差異。我的猜測是,如果一個人會做10 000或100 000而不是Exists()Any(),那麼這個細微的差別會或多或少地消失。

5

當你糾正測量 - 上面提到的:任何與存在,並增加平均 - 我們會得到下面的輸出:

Executing search Exists() 1000 times ... 
Average Exists(): 35566,023 
Fastest Exists() execution: 32226 

Executing search Any() 1000 times ... 
Average Any(): 58852,435 
Fastest Any() execution: 52269 ticks 

Benchmark finished. Press any key.