2009-09-04 19 views
26

Last()'u gerçekten çok seviyorum ve List<T> s için her zaman kullanıyorum. Ancak, IEnumerable<T> için tanımlanmış gibi göründüğü için, önce numaralandırmayı numaralandırır - bu, 0 (0) List<T>'un son öğesinin doğrudan indekslenmesi için O (1) 'in yerine O (n) olmalıdır.List <T> için Last() uzantı yönteminin performansı nedir?

Standart (Linq) uzantı yöntemleri bunun farkında mı?

C++ 'da STL, yineleyiciler ve niçin tüm bir "kalıtım ağacı" nedeniyle bunun farkındadır.

+0

Yineleyiciler için kalıtım ağacı nedir? C++ ilk etapta uzatma metotlarına sahip değildir, bu yüzden '' 'vektöründe '' ('' '' '' '' '' '' '' '' '' '' '' '' '' den farklı bir şekilde uygulanır ve her ikisi için iteratörlerle çalışmak isteyen her şey bir' şablon 'olmalıdır. 'yineleyici 'türü parametresi. –

cevap

30

Sadece son koduna bakmak için reflektörü kullanılmış ve bunun bir IList<T> ilk olup olmadığını görmek için kontrol eder ve (1) çağrısı uygun O gerçekleştirir:


DÜZENLEME:

Avukatımın tavsiyesi üzerine kod pasajını reflektörden çıkardım. Kendiniz için kod görmek istiyorsanız ya Reflektör almak ve kendiniz yapın (herkesin sahip olması gereken) ya da daha basitçe bu yazının düzeltme geçmişine bakın (bu konuda yapabileceğim hiçbir şey olmadığından)

(Ya aslında açıkça onu koruyan aynı çatlak yasal ekibi yok kim Mark'ın cevap bakmak)


Yani hafif bir döküm yükü değil, numaralandırılırken büyük havai var.

+0

'un düzeltildiğini belirttiği bir konu (ve şimdi de beni çirkin bir aptal gibi göstererek silinen bir konu), Mono gibi bir çerçevenin uygulanmasında çalışan herhangi birinin herhangi bir kod görmemiş olması. Microsoft bunu en azından yazdı, bunu açıkça yayınlamak kaba. Aslında aslında * yasadışı * olduğunu görmek için arama yapmakta çok şansım yok ve bunun bir alıntı olduğunu görmek isterim. Buradaki kurallara bakın http://www.mono-project.com/Contributing –

+8

Belki de birileri beni davet ettiğinden sandalyemin tekerleklerinin bir resmini yayınlamak da yasadışı. Bazen insanların telif hakkı sorunları hakkında çıldırdığını düşünüyorum. –

+0

Burada meta ile ilgili bir soru yayınladım (http://meta.stackexchange.com/questions/20153/posting-code-from-reflector) bana * * * * 'nin yasa dışı olduğuna ikna oldu. Daha önce de belirttiğim gibi, sadece sildiğim bazı yorumlar (ki şimdi de silinmişti). Reflektörden daha önce kod yazdım ve eminim yine yapacağım. Microsoft telif hakkı SWAT ekibi için omzuma bakmıyorum çünkü .NET'in anlayışını ve güvenini geliştirmek için herhangi bir şeyin Microsoft'a faydası olduğunu iddia ediyorum. –

7

IList<T>'u uygulayan her şey için bir optimizasyon içerir, bu durumda yalnızca öğeyi -1 uzunluğuna bakar.

tüm kod bakamıyor olanlar için IList<T>

uygulamak ... sen gönderecek şeyler büyük çoğunluğu böyle devam IList<T>

List<int> 
int[] 

ve uygulayacak unutmayın

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using System.Diagnostics; 

namespace ConsoleApplication4 { 
    class Program { 

     static void Profile(string description, int iterations, Action func) { 

      // clean up 
      GC.Collect(); 
      GC.WaitForPendingFinalizers(); 
      GC.Collect(); 

      // warm up 
      func(); 

      var watch = Stopwatch.StartNew(); 
      for (int i = 0; i < iterations; i++) { 
       func(); 
      } 
      watch.Stop(); 
      Console.Write(description); 
      Console.WriteLine(" Time Elapsed {0} ms", watch.ElapsedMilliseconds); 
     } 

     static void Main(string[] args) { 
      int[] nums = Enumerable.Range(1, 1000000).ToArray(); 

      int a; 

      Profile("Raw performance", 100000,() => { a = nums[nums.Length - 1]; }); 
      Profile("With Last", 100000,() => { a = nums.Last(); }); 

      Console.ReadKey(); 
     } 


    } 
} 

Çıktı:

onaylamak, sen gözlem ile onaylayabilirsiniz
 
Raw performance Time Elapsed 1 ms 
With Last Time Elapsed 31 ms 

Bu yüzden sadece 30 kat daha yavaştır ve sahip olduğunuz uzunluk listesine sahip performans profilini korur, bu da büyük bir şemada hiçbir şey değildir.

+0

Sadece küçük bir nitpick: 'HashSet ', IList 'uygulamıyor. – LukeH

+0

@Luke, –

2

List<T> için O (1) 'dir, ancak diğer numaralar için O (N) olabilir.

21

sadece :)

Enumerable.Last IList<T> için IEnumerable<T> örneğini downcast çalışır endişelenmeden List<T> ile son kullanabilirsiniz. Bu mümkün ise, indeksleyici ve Count özelliğini kullanır.Reflector gördüğü gibi

İşte uygulamanın bir parçasıdır:

IList<TSource> list = source as IList<TSource>; 
if (list != null) 
{ 
    int count = list.Count; 
    if (count > 0) 
    { 
     return list[count - 1]; 
    } 
} 
0

Kısa cevap:

O (1).

Açıklama:

O Son() için ListeCount() uzatma yöntemi kullandığı ortada. Sunulursa,

Sayısı() çekler yürütmesinde koleksiyon türü ve Kont özellik kullanır. liste

Sayısı özelliği O (1) karmaşıklığı çok Son() uzatma yöntemi vardır.

+0

'Last' * * Count' uzantı yöntemini kullanmaz * fakat her iki yöntemin belirli durumlarda O (1) olabileceği konusunda haklısınız:“ Last ”, koleksiyonun IList ' u içerip içermediğini kontrol eder ve eğer öyleyse son öğeyi numaralandırma yerine dizinle alır; "Count" yöntemi, koleksiyonun "ICollection " u uygulayıp uygulamadığını kontrol eder ve eğer öyleyse numaralandırma yerine "Count" özelliğini alır. – LukeH

+0

Teşekkürler Luke,% 100 doğru değildim. Son, IList için mülkiyet Sayısını kullanır ve O (1) karmaşıklığına sahiptir. Sadece Son (bu koleksiyon, yüklem) ve O (N) kodlarını kontrol ettim. Bu tembel. –

+0

@Konstantin: Eğer bir yüklemi "Last" yöntemine iletirseniz, o zaman, o eşleme ile eşleşen öğelerin hangileri olduğunu belirlemek için koleksiyonun bir O (n) sayımını yapmak zorundadır. – LukeH

İlgili konular