String.Contains () có nhanh hơn String.IndexOf () không?


111

Tôi có bộ đệm chuỗi khoảng 2000 ký tự và cần kiểm tra bộ đệm xem nó có chứa một chuỗi cụ thể hay không.
Sẽ thực hiện kiểm tra trong ứng dụng web ASP.NET 2.0 cho mọi yêu cầu web.

Có ai biết nếu phương thức String.Contains hoạt động tốt hơn phương thức String.IndexOf không?

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

Sự thật thú vị


14
Nếu bạn cần làm điều này hàng tỷ lần cho mỗi yêu cầu web, tôi sẽ bắt đầu xem xét những thứ như thế này. Trong bất kỳ trường hợp nào khác, tôi sẽ không bận tâm, vì thời gian dành cho cả hai phương pháp rất có thể sẽ không đáng kể so với việc nhận yêu cầu HTTP ngay từ đầu.
mookid8000,

2
Một trong những chìa khóa để tối ưu hóa là kiểm tra thay vì giả định, vì nó có thể phụ thuộc vào rất nhiều yếu tố như phiên bản .NET, hệ điều hành, phần cứng, sự thay đổi trong đầu vào, v.v. Trong nhiều trường hợp, kết quả kiểm tra do người khác thực hiện có thể rất khác trên hệ thống của bạn.
Slai

Câu trả lời:


174

Containscuộc gọi IndexOf:

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

Cuộc gọi nào CompareInfo.IndexOf, cuối cùng sử dụng triển khai CLR.

Nếu bạn muốn xem các chuỗi được so sánh như thế nào trong CLR, điều này sẽ hiển thị cho bạn (tìm CaseInsensitiveCompHelper ).

IndexOf(string)không có tùy chọn và Contains()sử dụng so sánh Ordinal (so sánh từng byte thay vì cố gắng thực hiện so sánh thông minh, ví dụ: e với é).

Vì vậy, IndexOfsẽ nhanh hơn một chút (trên lý thuyết) khi IndexOfđi thẳng vào tìm kiếm chuỗi sử dụng FindNLSString từ kernel32.dll (sức mạnh của phản xạ!).

Đã cập nhật cho .NET 4.0 - IndexOf không còn sử dụng so sánh thông thường và do đó Contains có thể nhanh hơn. Xem bình luận bên dưới.


3
Câu trả lời này không có nơi nào gần đúng, chỉ cần xem ở đây stackoverflow.com/posts/498880/revisions để biết lời giải thích
pzaj 12/11/15

55
Câu trả lời của tôi là 7 tuổi và dựa trên .NET 2 framework. Phiên bản 4 IndexOf()thực sự sử dụng StringComparison.CurrentCultureContains()sử dụng StringComparison.Ordinalsẽ nhanh hơn. Nhưng thực sự sự khác biệt về tốc độ mà chúng ta đang nói đến chỉ là phút - điểm này gọi cái kia, và Contains dễ đọc hơn nếu bạn không cần chỉ mục. Nói cách khác, đừng lo lắng về điều đó.
Chris S

21

Có lẽ, nó sẽ không có vấn đề gì cả. Đọc bài đăng này trên Coding Horror;): http://www.codinghorror.com/blog/archives/001218.html


4
Bú với ông chủ là chúng ta ...? : D Mặc dù vậy, bạn nói đúng, so với thời gian thực hiện để cung cấp một yêu cầu http, việc tìm kiếm qua một chuỗi ngắn, một lần, không đáng kể.
Fowl

Một bài đọc rất thú vị, nhưng nó làm tôi khó chịu khi phàn nàn ban đầu của anh ấy với việc nối là sử dụng bộ nhớ, sau đó anh ấy chỉ kiểm tra thời gian dành cho các cách kết hợp chuỗi khác nhau.
sab669

11

Contains (s2) nhanh hơn IndexOf (s2) nhiều lần (trong máy tính của tôi 10 lần) vì Contains sử dụng StringComparison. Cuối cùng là nhanh hơn tìm kiếm nhạy cảm với văn hóa mà IndexOf thực hiện theo mặc định (nhưng điều đó có thể thay đổi trong .net 4.0 http: //davesbox.com/archive/2008/11/12/break-changes-to-the-string-class.aspx ).

Contains có cùng hiệu suất như IndexOf (s2, StringComparison.Ordinal)> = 0 trong các thử nghiệm của tôi nhưng nó ngắn hơn và làm rõ ý định của bạn.


2
Những thay đổi trong .NET 4.0 dường như đã được hoàn nguyên trước khi nó đi RTM vì vậy tôi sẽ không dựa vào bài viết mà quá nhiều blogs.msdn.com/bclteam/archive/2008/11/04/...
Stephen Kennedy

7

Tôi đang chạy một trường hợp thực (ngược lại với một điểm chuẩn tổng hợp)

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

đấu với

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

Nó là một phần quan trọng trong hệ thống của tôi và nó được thực thi 131,953 lần (cảm ơn DotTrace).

Tuy nhiên , bất ngờ gây sốc , kết quả lại ngược lại với mong đợi

  • IndexOf 533ms.
  • Chứa 266ms.

: - /

net framework 4.0 (được cập nhật cho ngày 13-02-2012)


1
bởi vì INTlớn hơn nhiều BOOLIndexOf>=0gây ra thêm một bước
Eric Yin

3
Bạn quên sử dụng ´StringComparison.Ordinal´
Davi Fiamenghi

6

Bằng cách sử dụng Reflector, bạn có thể thấy rằng Contains được triển khai bằng IndexOf. Đây là cách thực hiện.

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

Vì vậy, Contains có thể chậm hơn một chút so với việc gọi IndexOf trực tiếp, nhưng tôi nghi ngờ rằng nó sẽ có bất kỳ ý nghĩa nào đối với hiệu suất thực tế.


1
Có, nhưng để sử dụng indexof làm bool, anh ta sẽ phải thực hiện phép so sánh bên ngoài hàm. Điều đó rất có thể sẽ cho kết quả tương tự như Contains, phải không?
Gonzalo Quero,

1
Có thể, nhưng bạn lưu một cuộc gọi phương thức (trừ khi nó có thể được nội dòng). Như tôi đã nói, nó có thể sẽ không bao giờ đáng kể.
Brian Rasmussen

6

Nếu bạn thực sự muốn tối ưu hóa vi mô thì cách tốt nhất của bạn luôn là đo điểm chuẩn.

Khung .net có triển khai đồng hồ bấm giờ tuyệt vời - System.Diagnostics.Stopwatch


Đó là cách tốt nhất nhưng nếu bạn muốn tiếp cận nhanh chóng, chỉ cần nhấn nút tạm dừng trong phiên gỡ lỗi. Quá trình kiểm soát mã có khả năng tạm dừng ở phần chậm nhất, khoảng 50% thời gian .
Jeremy Thompson

4

Từ một bài đọc nhỏ, có vẻ như bên dưới phương thức String.Contains chỉ đơn giản gọi String.IndexOf. Sự khác biệt là String.Contains trả về một boolean trong khi String.IndexOf trả về một số nguyên với (-1) biểu thị rằng không tìm thấy chuỗi con.

Tôi khuyên bạn nên viết một bài kiểm tra nhỏ với 100.000 lần lặp hoặc lâu hơn và tự mình xem. Nếu tôi đoán, tôi muốn nói rằng IndexOf có thể nhanh hơn một chút nhưng giống như tôi đã nói đó chỉ là phỏng đoán.

Jeff Atwood có một bài viết hay về chuỗi tại blog của mình . Nó thiên về nối nhưng có thể hữu ích.


3

Cũng giống như bản cập nhật cho điều này, tôi đã thực hiện một số thử nghiệm và cung cấp chuỗi đầu vào của bạn khá lớn thì Regex song song là phương pháp C # nhanh nhất mà tôi đã tìm thấy (miễn là bạn có nhiều lõi mà tôi tưởng tượng)

Lấy tổng số trận đấu chẳng hạn -

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

Hi vọng điêu nay co ich!


1
Xin chào phild trên một chủ đề riêng đã cập nhật điều này với một phiên bản từ tomasp.net/articles/ahocorasick.aspx , việc cung cấp các từ khóa (kim) của bạn không thay đổi sẽ nhanh hơn rất nhiều.
gary

2

Sử dụng thư viện điểm chuẩn, như bước đột phá gần đây của Jon Skeet để đo lường nó.

Emptor caveat

Như tất cả các câu hỏi về hiệu suất (vi mô), điều này phụ thuộc vào phiên bản phần mềm bạn đang sử dụng, chi tiết của dữ liệu được kiểm tra và mã xung quanh cuộc gọi.

Như tất cả các câu hỏi về hiệu suất (vi mô), bước đầu tiên phải là có được một phiên bản đang chạy có thể dễ dàng bảo trì. Sau đó, đo điểm chuẩn, lập hồ sơ và điều chỉnh có thể được áp dụng cho các điểm nghẽn đã đo được thay vì phỏng đoán.


Mặc dù liên kết này có thể trả lời câu hỏi, nhưng tốt hơn hết bạn nên đưa các phần thiết yếu của câu trả lời vào đây và cung cấp liên kết để tham khảo. Các câu trả lời chỉ có liên kết có thể trở nên không hợp lệ nếu trang được liên kết thay đổi.
Mike Stockdale

thư viện được liên kết chỉ là một trong nhiều thư viện và không phải là lực đẩy chính của câu trả lời. Tôi không nghĩ rằng đăng nguồn thư viện hoặc mô tả sẽ cải thiện câu trả lời, trang web này hoặc thế giới.
David Schmitt

3
-1; câu hỏi là "Có ai biết nếu phương thức String.Contains hoạt động tốt hơn phương thức String.IndexOf không?" - câu trả lời của bạn là "sử dụng thư viện điểm chuẩn", về cơ bản có nghĩa là "tôi không biết, tự làm", "điều này tùy thuộc", có nghĩa là "tôi không biết" và "tải phiên bản và hồ sơ đang chạy" , cũng có nghĩa là "Tôi không biết, hãy tự làm". Đây không phải là 'Jeopardy' - vui lòng cung cấp câu trả lời cho câu hỏi được hỏi , không phải ý tưởng về cách thực hiện - vị trí của họ là trong nhận xét .

-7

Đối với bất kỳ ai vẫn đang đọc phần này, indexOf () có thể sẽ hoạt động tốt hơn trên hầu hết các hệ thống doanh nghiệp, vì hàm chứa () không tương thích với IE!


12
ném OutOfScopeException mới ();
Raphaël
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.