Apakah String.Contains () lebih cepat dari String.IndexOf ()?

111

Saya memiliki buffer string sekitar 2000 karakter dan perlu memeriksa buffer jika berisi string tertentu.
Akan melakukan pemeriksaan di aplikasi web ASP.NET 2.0 untuk setiap permintaan web.

Apakah ada yang tahu jika metode String.Contains berkinerja lebih baik daripada metode String.IndexOf ?

    // 2000 characters in s1, search token in s2
    string s1 = "Many characters. The quick brown fox jumps over the lazy dog"; 
    string s2 = "fox";
    bool b;
    b = s1.Contains(s2);
    int i;
    i = s1.IndexOf(s2);

Fakta menyenangkan

Kb.
sumber
14
Jika Anda perlu melakukan ini satu miliar kali per permintaan web, saya akan mulai melihat hal-hal seperti ini. Dalam kasus lain, saya tidak akan repot-repot, karena waktu yang dihabiskan dengan metode mana pun kemungkinan besar akan sangat tidak signifikan dibandingkan dengan menerima permintaan HTTP di tempat pertama.
mookid8000
2
Salah satu kunci untuk pengoptimalan adalah menguji alih-alih mengasumsikan, karena dapat bergantung pada banyak faktor seperti versi .NET, sistem operasi, perangkat keras, variasi input, dll. Dalam banyak kasus, hasil pengujian dilakukan oleh orang lain bisa sangat berbeda di sistem Anda.
Slai

Jawaban:

174

Containspanggilan IndexOf:

public bool Contains(string value)
{
    return (this.IndexOf(value, StringComparison.Ordinal) >= 0);
}

Panggilan CompareInfo.IndexOfmana, yang pada akhirnya menggunakan implementasi CLR.

Jika Anda ingin melihat bagaimana string dibandingkan di CLR, ini akan menunjukkan kepada Anda (cari CaseInsensitiveCompHelper ).

IndexOf(string)tidak memiliki opsi dan Contains()menggunakan perbandingan Ordinal (perbandingan byte-by-byte daripada mencoba melakukan perbandingan cerdas, misalnya, e dengan é).

Jadi IndexOfakan sedikit lebih cepat (dalam teori) karena IndexOflangsung ke pencarian string menggunakan FindNLSString dari kernel32.dll (kekuatan reflektor!).

Diperbarui untuk .NET 4.0 - IndexOf tidak lagi menggunakan Perbandingan Ordinal sehingga Mengandung bisa lebih cepat. Lihat komentar di bawah.

Chris S
sumber
3
Jawaban ini sama sekali tidak benar, lihat saja di sini stackoverflow.com/posts/498880/revised untuk penjelasannya
pzaj
55
Jawaban saya adalah 7 tahun dan berdasarkan framework .NET 2. Versi 4 IndexOf()memang menggunakan StringComparison.CurrentCulturedan Contains()menggunakan StringComparison.Ordinalyang akan lebih cepat. Tetapi sebenarnya perbedaan kecepatan yang kita bicarakan adalah menit - intinya adalah satu memanggil yang lain, dan Berisi lebih mudah dibaca jika Anda tidak memerlukan indeks. Dengan kata lain jangan khawatir tentang itu.
Chris S
21

Mungkin, itu tidak masalah sama sekali. Baca posting ini di Coding Horror;): http://www.codinghorror.com/blog/archives/001218.html

Gonzalo Quero
sumber
4
Mengisap bos apakah kita ...? : D Anda benar, dibandingkan dengan waktu yang dibutuhkan untuk melayani permintaan http, mencari melalui string pendek, sekali, tidaklah signifikan.
Unggas
Bacaan yang sangat menghibur, tetapi mengganggu saya. Keluhan awalnya dengan penggabungan adalah penggunaan memori, lalu dia hanya menguji waktu yang dihabiskan dengan berbagai cara untuk menggabungkan string.
sab669
11

Berisi (s2) berkali-kali (di komputer saya 10 kali) lebih cepat daripada IndexOf (s2) karena Berisi menggunakan StringComparison.Ordinal yang lebih cepat daripada pencarian sensitif budaya yang dilakukan IndexOf secara default (tetapi itu dapat berubah di .net 4.0 http: //davesbox.com/archive/2008/11/12/breaking-changes-to-the-string-class.aspx ).

Berisi memiliki kinerja yang persis sama dengan IndexOf (s2, StringComparison.Ordinal)> = 0 dalam pengujian saya tetapi lebih pendek dan membuat niat Anda jelas.

ggf31416
sumber
2
Perubahan pada .NET 4.0 tampaknya dikembalikan sebelum menjadi RTM jadi saya tidak akan terlalu mengandalkan artikel itu blogs.msdn.com/bclteam/archive/2008/11/04/…
Stephen Kennedy
7

Saya menjalankan kasus nyata (berlawanan dengan tolok ukur sintetis)

 if("=,<=,=>,<>,<,>,!=,==,".IndexOf(tmps)>=0) {

melawan

 if("=,<=,=>,<>,<,>,!=,==,".Contains(tmps)) {

Ini adalah bagian penting dari sistem saya dan dijalankan 131.953 kali (terima kasih DotTrace).

Betapapun mengejutkannya , hasilnya berlawanan dengan yang diharapkan

  • Indeks Dari 533ms.
  • Berisi 266ms.

: - /

kerangka kerja bersih 4.0 (diperbarui untuk 13-02-2012)

magallanes
sumber
1
karena INTjauh lebih besar dari BOOL, dan IndexOf>=0menyebabkan satu langkah lagi
Eric Yin
3
Anda lupa menggunakan ´StringComparison.Ordinal´
Davi Fiamenghi
6

Dengan menggunakan Reflector, Anda dapat melihat, bahwa Contains diimplementasikan menggunakan IndexOf. Berikut implementasinya.

public bool Contains(string value)
{
   return (this.IndexOf(value, StringComparison.Ordinal) >= 0);
}

Jadi Contains sepertinya sedikit lebih lambat daripada memanggil IndexOf secara langsung, tapi saya ragu itu akan memiliki signifikansi untuk kinerja sebenarnya.

Brian Rasmussen
sumber
1
Ya, tetapi untuk menggunakan indexof sebagai bool, dia harus melakukan perbandingan di luar fungsi. Itu kemungkinan besar akan memberikan hasil yang sama dengan Contains, bukan?
Gonzalo Quero
1
Mungkin, tetapi Anda menyimpan satu panggilan metode (kecuali jika dapat disisipkan). Seperti yang saya katakan, itu mungkin tidak akan pernah signifikan.
Brian Rasmussen
6

Jika Anda benar-benar ingin mengoptimalkan mikro kode Anda, pendekatan terbaik Anda selalu benchmarking.

Kerangka .net memiliki implementasi stopwatch yang sangat baik - System.Diagnostics.Stopwatch

Andrew Harry
sumber
Itu yang terbaik tetapi jika Anda ingin pendekatan cepat cukup tekan tombol jeda dalam sesi debug. Kontrol kode kemungkinan akan berhenti di bagian paling lambat kira-kira 50% dari waktu .
Jeremy Thompson
4

Dari sedikit pembacaan, tampak bahwa di bawah tenda metode String.Contains hanya memanggil String.IndexOf. Perbedaannya adalah String.Contains mengembalikan boolean sementara String.IndexOf mengembalikan integer dengan (-1) yang menyatakan bahwa substring tidak ditemukan.

Saya akan menyarankan menulis tes kecil dengan 100.000 atau lebih iterasi dan lihat sendiri. Jika saya harus menebak, saya akan mengatakan bahwa IndexOf mungkin sedikit lebih cepat tetapi seperti yang saya katakan itu hanya tebakan.

Jeff Atwood memiliki artikel bagus tentang string di blognya . Ini lebih tentang penggabungan tetapi mungkin tetap membantu.

Mike Roosa
sumber
3

Sama seperti pembaruan untuk ini, saya telah melakukan beberapa pengujian dan memberikan string input Anda cukup besar maka Regex paralel adalah metode C # tercepat yang saya temukan (asalkan Anda memiliki lebih dari satu inti yang saya bayangkan)

Mendapatkan jumlah total pertandingan misalnya -

needles.AsParallel ( ).Sum ( l => Regex.IsMatch ( haystack , Regex.Escape ( l ) ) ? 1 : 0 );

Semoga ini membantu!

gary
sumber
1
Hi phild di utas terpisah memperbarui ini dengan versi dari tomasp.net/articles/ahocorasick.aspx yang, memberikan kata kunci Anda (jarum) tidak berubah jauh lebih cepat.
gary
2

Gunakan pustaka patokan, seperti upaya terbaru dari Jon Skeet untuk mengukurnya.

Caveat Emptor

Seperti semua pertanyaan kinerja (mikro), ini tergantung pada versi perangkat lunak yang Anda gunakan, detail data yang diinspeksi, dan kode seputar panggilan.

Seperti semua pertanyaan kinerja (mikro), langkah pertama yang harus dilakukan adalah mendapatkan versi berjalan yang mudah dipelihara. Kemudian benchmarking, profiling, dan tuning dapat diterapkan ke bottleneck yang diukur, bukan menebak-nebak.

David Schmitt
sumber
Meskipun tautan ini mungkin menjawab pertanyaan, lebih baik menyertakan bagian penting dari jawaban di sini dan menyediakan tautan untuk referensi. Jawaban link saja bisa menjadi tidak valid jika halaman tertaut berubah.
Mike Stockdale
perpustakaan terkait hanyalah satu dari sekian banyak, dan bukan pendorong utama jawabannya. Saya tidak berpikir bahwa memposting sumber atau deskripsi perpustakaan akan meningkatkan jawaban, situs ini atau dunia.
David Schmitt
3
-1; pertanyaannya adalah "Apakah ada yang tahu jika metode String.Contains berkinerja lebih baik daripada metode String.IndexOf?" - jawaban Anda adalah "gunakan pustaka patokan", yang pada dasarnya berarti "Saya tidak tahu, lakukan sendiri", "ini tergantung", yang berarti "Saya tidak tahu", dan "dapatkan versi dan profil yang berjalan" , yang juga berarti "Saya tidak tahu, lakukan sendiri". Ini bukan 'Jeopardy' - harap berikan jawaban untuk pertanyaan yang diajukan , bukan ide cara melakukannya - tempatnya ada di komentar .
-7

Bagi siapa pun yang masih membaca ini, indexOf () mungkin akan bekerja lebih baik di sebagian besar sistem perusahaan, karena berisi () tidak kompatibel dengan IE!

Zargontapel
sumber
12
membuang OutOfScopeException () baru;
Raphaël