Làm cách nào để kiểm tra xem một mảng có bao gồm giá trị trong JavaScript không?


3996

Cách ngắn gọn và hiệu quả nhất để tìm hiểu xem một mảng JavaScript có chứa giá trị không là gì?

Đây là cách duy nhất tôi biết để làm điều đó:

function contains(a, obj) {
    for (var i = 0; i < a.length; i++) {
        if (a[i] === obj) {
            return true;
        }
    }
    return false;
}

Có cách nào tốt hơn và ngắn gọn hơn để thực hiện điều này?

Điều này liên quan rất chặt chẽ với câu hỏi Stack Overflow Cách tốt nhất để tìm một mục trong Mảng JavaScript? trong đó giải quyết việc tìm kiếm các đối tượng trong một mảng bằng cách sử dụng indexOf.


49
vừa được thử nghiệm: cách của bạn thực sự là nhanh nhất đối với các trình duyệt: jsperf.com/find-element-in-obj-vs-array/2 (ngoài việc lưu trước a.length trong một biến) trong khi sử dụng indexOf (như trong $ .inArray) chậm hơn nhiều
Jorn Berkefeld

17
nhiều người đã trả lời rằng Array # indexOf là lựa chọn tốt nhất của bạn ở đây. Nhưng nếu bạn muốn một cái gì đó có thể được đúc chính xác thành Boolean, hãy sử dụng cái này: ~[1,2,3].indexOf(4)sẽ trả về 0 sẽ đánh giá là sai, trong khi đó ~[1,2,3].indexOf(3)sẽ trả về -3 sẽ đánh giá là đúng.
chúa tể

8
~không phải là những gì bạn muốn sử dụng để chuyển đổi thành boolean, mà bạn cần !. Nhưng trong trường hợp này, bạn muốn kiểm tra đẳng thức với -1, vì vậy hàm có thể kết thúc return [1,2,3].indexOf(3) === -1; ~là nhị phân không, nó sẽ đảo ngược từng bit của giá trị riêng lẻ.
mcfedr

14
@Iordvlad [1,2,3].indexOf(4)sẽ thực sự trở lại -1 . Như @mcfedr đã chỉ ra, ~toán tử bitwise-NOT , xem ES5 11.4.8. Điều quan trọng là, vì biểu diễn nhị phân -1chỉ bao gồm 1, nên phần bổ sung của nó được 0đánh giá là sai. Phần bù của bất kỳ số nào khác sẽ khác không, do đó đúng. Vì vậy, ~hoạt động tốt và thường được sử dụng kết hợp với indexOf.
mknecht 14/03/2015

5
Tiêu đề là sai lệch. Đâu là [[1,2],[3,4]].includes([3,4])?
mplungjan

Câu trả lời:


4377

Các trình duyệt hiện đại Array#includes, thực hiện chính xác điều đó và được mọi người ủng hộ ngoại trừ IE:

console.log(['joe', 'jane', 'mary'].includes('jane')); //true

Bạn cũng có thể sử dụng Array#indexOf, ít trực tiếp hơn, nhưng không yêu cầu polyfill cho các trình duyệt lỗi thời.


Nhiều khung cũng cung cấp các phương thức tương tự:

Lưu ý rằng một số khung công tác thực hiện điều này như là một hàm, trong khi các khung khác thêm hàm vào nguyên mẫu mảng.


42
MooTools cũng có Array.contains trả về boolean, nghe giống như câu hỏi thực sự ở đây.
Ryan Florence

22
nguyên mẫu cũng có Array.includetrả về boolean
user102008

46
Nếu bạn đang sử dụng một trình duyệt tốt, bạn chỉ có thể sử dụngarray.indexOf(object) != -1
Sam Soffes

13
Ngoài ra, sử dụng dont indexOf một mình như một điều kiện, bởi vì phần tử đầu tiên sẽ trở về 0 và sẽ được đánh giá là falsy
plus-

241
inArraylà một tên khủng khiếp cho một hàm trả về chỉ mục của phần tử và -1nếu nó không tồn tại. Tôi sẽ mong đợi một boolean được trả lại.
Tim

434

Cập nhật từ năm 2019: Câu trả lời này là từ năm 2008 (11 tuổi!) Và không liên quan đến việc sử dụng JS hiện đại. Cải thiện hiệu suất được hứa hẹn dựa trên điểm chuẩn được thực hiện trong các trình duyệt thời đó. Nó có thể không liên quan đến bối cảnh thực thi JS hiện đại. Nếu bạn cần một giải pháp dễ dàng, hãy tìm câu trả lời khác. Nếu bạn cần hiệu suất tốt nhất, điểm chuẩn cho chính mình trong các môi trường thực thi có liên quan.

Như những người khác đã nói, việc lặp qua mảng có lẽ là cách tốt nhất, nhưng đã được chứng minh rằng một whilevòng lặp giảm là cách nhanh nhất để lặp lại trong JavaScript. Vì vậy, bạn có thể muốn viết lại mã của mình như sau:

function contains(a, obj) {
    var i = a.length;
    while (i--) {
       if (a[i] === obj) {
           return true;
       }
    }
    return false;
}

Tất nhiên, bạn cũng có thể mở rộng nguyên mẫu Array:

Array.prototype.contains = function(obj) {
    var i = this.length;
    while (i--) {
        if (this[i] === obj) {
            return true;
        }
    }
    return false;
}

Và bây giờ bạn có thể chỉ cần sử dụng như sau:

alert([1, 2, 3].contains(2)); // => true
alert([1, 2, 3].contains('2')); // => false


22
"Đã được chứng minh" là một từ mạnh mẽ. Các công cụ JS liên tục cải thiện và thời gian thực hiện được đo 3 năm trước đã lỗi thời khủng khiếp.
orip

2
@Damir - Tôi đồng ý. Có lẽ thay đổi mẫu để sử dụng indexOf nếu có, chỉ cần mọi người sao chép mã này một cách mù quáng sẽ có hiệu suất tốt nhất có thể.
orip

1
@cbmeek yeah, chăm sóc là chắc chắn cần thiết. Đây có lẽ là một trường hợp for (o in array)không nên làm khi lặp qua mảng nói chung ...
Damir Zekić

1
Cách tốt nhất để làm điều này là kiểm tra xem [1, 2, 3] .indexOf (1)> -1
Devin G Rhode

207

indexOf có thể, nhưng đó là "phần mở rộng JavaScript cho tiêu chuẩn ECMA-262; vì vậy nó có thể không có mặt trong các triển khai khác của tiêu chuẩn."

Thí dụ:

[1, 2, 3].indexOf(1) => 0
["foo", "bar", "baz"].indexOf("bar") => 1
[1, 2, 3].indexOf(4) => -1

AFAICS Microsoft không cung cấp một số loại thay thế cho điều này, nhưng bạn có thể thêm chức năng tương tự vào các mảng trong Internet Explorer (và các trình duyệt khác không hỗ trợ indexOf) nếu bạn muốn, như một tìm kiếm nhanh của Google tiết lộ (ví dụ: cái này ).


thực tế, có một ví dụ về việc triển khai tiện ích mở rộng indexOf cho các trình duyệt không hỗ trợ nó trên trang developer.mozilla.org mà bạn đã liên kết.
Lloyd Cotten

thực tế, nếu bạn thêm indexof vào nguyên mẫu của Array cho các trình duyệt không hỗ trợ nó (ví dụ IE7), họ cũng sẽ cố gắng lặp lại chức năng này khi lặp qua các mục trong mảng. bẩn thỉu.
CpILL


nó có thể áp dụng để kiểm tra đối tượng không? tôi không nghĩ nó hoạt động trong trường hợp của Object
Himesh Aadeshara

169

ECMAScript 7 giới thiệu Array.prototype.includes.

Nó có thể được sử dụng như thế này:

[1, 2, 3].includes(2); // true
[1, 2, 3].includes(4); // false

Nó cũng chấp nhận một đối số thứ hai tùy chọn fromIndex:

[1, 2, 3].includes(3, 3); // false
[1, 2, 3].includes(3, -1); // true

Không giống như indexOf, sử dụng So sánh bình đẳng nghiêm ngặt , includesso sánh bằng thuật toán đẳng thức SameValueZero . Điều đó có nghĩa là bạn có thể phát hiện nếu một mảng bao gồm NaN:

[1, 2, NaN].includes(NaN); // true

Cũng không giống như indexOf, includeskhông bỏ qua các chỉ số bị thiếu:

new Array(5).includes(undefined); // true

Hiện tại nó vẫn chỉ là một bản nháp nhưng có thể được hoàn thiện để làm cho nó hoạt động trên tất cả các trình duyệt.


3
Không được hỗ trợ cho IE và microsfot Edge (2015) ( developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/ trộm )
Adriano Resende

1
Cũng có liên quan, bảng tương thích ES7 (có vẻ như chrome hỗ trợ ngay bây giờ)
styfle 11/03/2016

nó có thể áp dụng để kiểm tra đối tượng không? tôi không nghĩ nó hoạt động trong trường hợp của Object
Himesh Aadeshara

128

Các câu trả lời hàng đầu giả định các kiểu nguyên thủy nhưng nếu bạn muốn tìm hiểu xem một mảng có chứa một đối tượng có một số đặc điểm hay không, Array.prototype.some () là một giải pháp rất thanh lịch:

const items = [ {a: '1'}, {a: '2'}, {a: '3'} ]

items.some(item => item.a === '3')  // returns true
items.some(item => item.a === '4')  // returns false

Điều thú vị ở đây là phép lặp bị hủy bỏ một khi phần tử được tìm thấy để các chu kỳ lặp không cần thiết được bỏ qua.

Ngoài ra, nó phù hợp độc đáo trong một iftuyên bố vì nó trả về một boolean:

if (items.some(item => item.a === '3')) {
  // do something
}

* Như Jamess đã chỉ ra trong bình luận, tại thời điểm trả lời này, tháng 9 năm 2018, Array.prototype.some()được hỗ trợ đầy đủ: bảng hỗ trợ caniuse.com


1
Kể từ hôm nay, tháng 9 năm 2018, Array.prototype.some () được hỗ trợ đầy đủ: bảng hỗ trợ caniuse.com
gây nhiễu

1
Làm việc trong Node> = 8.10 cho AWS Node.js Lambda, vì vậy điều này thật tuyệt. Giải pháp rất sạch sẽ và đơn giản! 👍🏻
Jordan

1
@jamess Nó có thể được hỗ trợ tốt, nhưng hãy nhớ rằng Arrow functionstrong ví dụ này không được hỗ trợ tốt như vậy. Để biết thêm chi tiết, xem tại đây: developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/
Kẻ

Có một số ngắn mạch? Hoặc nó lặp lại toàn bộ mảng ngay cả khi nó tìm thấy một giá trị?
Douglas Gaskell

@DoumundGaskell nó hủy bỏ việc lặp lại một lần được tìm thấy (được đề cập trong câu trả lời)
Michael

112

Giả sử bạn đã xác định một mảng như vậy:

const array = [1, 2, 3, 4]

Dưới đây là ba cách để kiểm tra xem có một 3trong đó. Tất cả đều trở về truehoặc false.

Phương thức Mảng bản địa (kể từ ES2016) ( bảng tương thích )

array.includes(3) // true

Là phương thức Mảng tùy chỉnh (trước ES2016)

// Prefixing the method with '_' to avoid name clashes
Object.defineProperty(Array.prototype, '_includes', { value: function (v) { return this.indexOf(v) !== -1 }})
array._includes(3) // true

Chức năng đơn giản

const includes = (a, v) => a.indexOf(v) !== -1
includes(array, 3) // true

Nó trả về đúng nếu "b" nằm trong mảng "a" ... Tôi không biết làm thế nào khác để giải thích nó ...
william malo

4
Phần này tôi không hiểu "!! ~". Và tôi nghĩ rằng điều này sẽ không hoạt động trong IE8 vì IE8 không hỗ trợ indexOf () trên đối tượng Array.
Svlada

62
"~" là toán tử phân tầng, đảo ngược và trừ 1 từ một số. indexOf trả về -1 nếu thất bại, vì vậy "~" biến -1 thành "0". sử dụng "!!" biến số thành boleans (!! 0 === sai)
william malo

1
Thật tuyệt, nhưng nghiêm túc vì sự đơn giản y không chỉ a.indexOf (b)> - 1, kể từ "> -1" .length === "!! ~" .length
super

2
Tôi gọi là thiếu kiến ​​thức về ảnh hưởng của các nhà khai thác boolean là không chuyên nghiệp. Nhưng tôi đồng ý về giá trị của mã có thể đọc được, tôi chắc chắn sẽ bọc nó trong một chức năng được dán nhãn rõ ràng. Và đó chính xác là những gì hầu hết các khung công tác JS chính làm.
okdewit

79

Đây là một triển khai tương thích JavaScript 1.6 của Array.indexOf:

if (!Array.indexOf) {
    Array.indexOf = [].indexOf ?
        function(arr, obj, from) {
            return arr.indexOf(obj, from);
        } :
        function(arr, obj, from) { // (for IE6)
            var l = arr.length,
                i = from ? parseInt((1 * from) + (from < 0 ? l : 0), 10) : 0;
            i = i < 0 ? 0 : i;
            for (; i < l; i++) {
                if (i in arr && arr[i] === obj) {
                    return i;
                }
            }
            return -1;
        };
}

Điều này có vẻ tuyệt vời, nhưng có một chút nhầm lẫn: * Không phải các bài kiểm tra trên dòng 1 và 3 tương đương? * Sẽ tốt hơn nếu kiểm tra nguyên mẫu và thêm chức năng vào Array.prototype nếu cần thiết?
Avi Flax

10
Họ không bình đẳng. [].indexOflà một tốc ký cho Array.prototype.indexOf. Chúng tôi lập trình viên Javascript phòng thủ hoang tưởng tránh mở rộng các nguyên mẫu bản địa bằng mọi giá.
Már rlygsson

1
Không [].indexOftạo một mảng mới và sau đó truy cập indexOf, trong khi Array.prototype.indexOfchỉ truy cập trực tiếp vào nguyên mẫu?
alex

3
@alex có [].indexOf === Array.prototype.indexOf(dùng thử trong FireBug), nhưng ngược lại [].indexOf !== Array.indexOf.
Már rlygsson

57

Sử dụng:

function isInArray(array, search)
{
    return array.indexOf(search) >= 0;
}

// Usage
if(isInArray(my_array, "my_value"))
{
    //...
}

25
x ? true : falsethường là dư thừa. Nó ở đây.
Ry-

@minitech Tại sao bạn nói nó là dư thừa?
Matías Cánepa

8
array.indexOf(search) >= 0đã là một boolean. Chỉ cần return array.indexOf(search) >= 0.
Ry-

@minitech cũng cảm ơn! Thật ra tôi không biết rằng một công trình như vậy có thể được trả lại. TIL một cái gì đó mới.
Matías Cánepa

Nghĩa đen là bất kỳ cấu trúc nào trong javascript đều có thể được trả về
BT

49

Mở rộng Arrayđối tượng JavaScript là một ý tưởng thực sự tồi tệ vì bạn giới thiệu các thuộc tính mới (phương thức tùy chỉnh của bạn) vào for-incác vòng lặp có thể phá vỡ các tập lệnh hiện có. Một vài năm trước, các tác giả của thư viện Prototype đã phải thiết kế lại việc triển khai thư viện của họ để loại bỏ loại điều này.

Nếu bạn không cần lo lắng về khả năng tương thích với các JavaScript khác đang chạy trên trang của mình, hãy sử dụng nó, nếu không, tôi khuyên bạn nên sử dụng giải pháp chức năng tự do khó xử lý hơn nhưng an toàn hơn.


22
Tôi không đồng ý. Các vòng lặp không nên được sử dụng cho các mảng vì lý do này chính xác. Việc sử dụng các vòng lặp for-in sẽ bị hỏng khi sử dụng một trong các thư viện js phổ biến
Tomas

Điều này sẽ được coi là vá khỉ? lol Một số người thích điều đó.
cbmeek

33

Lót:

function contains(arr, x) {
    return arr.filter(function(elem) { return elem == x }).length > 0;
}

8
array.filter(e=>e==x).length > 0tương đương array.some(e=>e==x)nhưng somehiệu quả hơn
Apolo

32

Suy nghĩ ra khỏi hộp trong một giây, nếu bạn thực hiện cuộc gọi này nhiều lần, sẽ hiệu quả hơn rất nhiều khi sử dụng một mảng kết hợp Bản đồ để thực hiện tra cứu bằng hàm băm.

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map


Mặc dù điều này rõ ràng hữu ích với nhiều người, nhưng sẽ tốt hơn nếu một đoạn mã được thêm vào.
Pie 'Oh' Pah

28

Tôi sử dụng như sau:

Array.prototype.contains = function (v) {
    return this.indexOf(v) > -1;
}

var a = [ 'foo', 'bar' ];

a.contains('foo'); // true
a.contains('fox'); // false

24
function contains(a, obj) {
    return a.some(function(element){return element == obj;})
}

Array.prototype.some () đã được thêm vào tiêu chuẩn ECMA-262 trong phiên bản thứ 5


nếu sử dụng es6 thì nó sẽ được rút ngắn làcontains = (a, obj) => a.some((element) => element === obj))
diEcho

Ngay cả IE9 cũng hỗ trợ Array.prototype.some () kể từ ECMAScript 5 .
Suncat2000

19

Hy vọng hai chiều indexOf/ lastIndexOfthay thế nhanh hơn

2015

Mặc dù phương thức mới bao gồm rất hay, nhưng về cơ bản thì sự hỗ trợ là bằng không.

Lâu lắm rồi tôi mới nghĩ ra cách thay thế các hàm indexOf / lastIndexOf chậm.

Một cách biểu diễn đã được tìm thấy, nhìn vào các câu trả lời hàng đầu. Từ những người tôi đã chọn containschức năng được đăng bởi @Damir Zekic, đây là chức năng nhanh nhất. Nhưng nó cũng nói rằng các điểm chuẩn là từ năm 2008 và do đó đã lỗi thời.

Tôi cũng thích whilehơn for, nhưng không phải là một lý do cụ thể, tôi đã kết thúc việc viết hàm với một vòng lặp for. Nó cũng có thể được thực hiện với mộtwhile -- .

Tôi đã tò mò nếu việc lặp lại chậm hơn nhiều nếu tôi kiểm tra cả hai mặt của mảng trong khi thực hiện nó. Rõ ràng là không, và do đó, chức năng này nhanh hơn khoảng hai lần so với các chức năng được bình chọn hàng đầu. Rõ ràng nó cũng nhanh hơn bản địa. Điều này trong một môi trường thế giới thực, nơi bạn không bao giờ biết liệu giá trị bạn đang tìm kiếm là ở đầu hay cuối mảng.

Khi bạn biết rằng bạn vừa đẩy một mảng có giá trị, sử dụng lastIndexOf có thể vẫn là giải pháp tốt nhất, nhưng nếu bạn phải đi qua các mảng lớn và kết quả có thể ở khắp mọi nơi, đây có thể là một giải pháp vững chắc để làm mọi thứ nhanh hơn.

Chỉ mục hai chiềuOf / last IndexOf

function bidirectionalIndexOf(a, b, c, d, e){
  for(c=a.length,d=c*1; c--; ){
    if(a[c]==b) return c; //or this[c]===b
    if(a[e=d-1-c]==b) return e; //or a[e=d-1-c]===b
  }
  return -1
}

//Usage
bidirectionalIndexOf(array,'value');

Kiểm tra hiệu suất

http://jsperf.com/bidirectionalindexof

Khi kiểm tra tôi đã tạo ra một mảng với 100k mục.

Ba truy vấn: ở đầu, ở giữa & ở cuối mảng.

Tôi hy vọng bạn cũng tìm thấy điều này thú vị và kiểm tra hiệu suất.

Lưu ý: Như bạn có thể thấy tôi đã sửa đổi một chút containschức năng để phản ánh đầu ra indexOf & lastIndexOf (về cơ bản là truevới indexfalsevới -1). Điều đó không nên làm hại nó.

Các biến thể nguyên mẫu mảng

Object.defineProperty(Array.prototype,'bidirectionalIndexOf',{value:function(b,c,d,e){
  for(c=this.length,d=c*1; c--; ){
    if(this[c]==b) return c; //or this[c]===b
    if(this[e=d-1-c] == b) return e; //or this[e=d-1-c]===b
  }
  return -1
},writable:false, enumerable:false});

// Usage
array.bidirectionalIndexOf('value');

Hàm này cũng có thể dễ dàng được sửa đổi để trả về true hoặc false hoặc thậm chí là đối tượng, chuỗi hoặc bất cứ thứ gì.

Và đây là whilebiến thể:

function bidirectionalIndexOf(a, b, c, d){
  c=a.length; d=c-1;
  while(c--){
    if(b===a[c]) return c;
    if(b===a[d-c]) return d-c;
  }
  return c
}

// Usage
bidirectionalIndexOf(array,'value');

Sao có thể như thế được?

Tôi nghĩ rằng phép tính đơn giản để lấy chỉ số phản ánh trong một mảng đơn giản đến mức nhanh hơn hai lần so với thực hiện một vòng lặp thực tế.

Dưới đây là một ví dụ phức tạp khi thực hiện ba kiểm tra mỗi lần lặp, nhưng điều này chỉ có thể với một phép tính dài hơn gây ra sự chậm lại của mã.

http://jsperf.com/bidirectionalindexof/2


18

Hiệu suất

Hôm nay 2020.01.07 Tôi thực hiện các thử nghiệm trên MacOs HighSierra 10.13.6 trên Chrome v78.0.0, Safari v13.0.4 và Firefox v71.0.0 cho 15 giải pháp được chọn. Kết luận

  • giải pháp dựa trên JSON, Setvà đáng ngạc nhiên find(K, N, O) là chậm nhất trên tất cả các trình duyệt
  • es6 includes(F) chỉ nhanh trên chrome
  • các giải pháp dựa trên for(C, D) và indexOf(G, H) khá nhanh trên tất cả các trình duyệt trên các mảng nhỏ và lớn, vì vậy có lẽ chúng là lựa chọn tốt nhất cho giải pháp hiệu quả
  • các giải pháp trong đó chỉ số giảm trong vòng lặp, (B) có thể chậm hơn vì cách bộ đệm CPU hoạt động .
  • Tôi cũng chạy thử nghiệm cho mảng lớn khi phần tử được tìm kiếm ở vị trí 66% chiều dài mảng và các giải pháp dựa trên for(C, D, E) cho kết quả tương tự (~ 630 ops / giây - nhưng E trên safari và firefox là 10- Chậm hơn 20% so với C và D)

Các kết quả

nhập mô tả hình ảnh ở đây

Chi tiết

Tôi thực hiện 2 trường hợp kiểm tra: cho mảng có 10 phần tử và mảng có 1 phần tử. Trong cả hai trường hợp, chúng tôi đặt phần tử tìm kiếm ở giữa mảng.

Mảng nhỏ - 10 phần tử

Bạn có thể thực hiện các bài kiểm tra trong máy của mình TẠI ĐÂY

nhập mô tả hình ảnh ở đây

Mảng lớn - 1.000.000 phần tử

Bạn có thể thực hiện các bài kiểm tra trong máy của mình TẠI ĐÂY

nhập mô tả hình ảnh ở đây


16

Nếu bạn đang sử dụng JavaScript 1.6 trở lên (Firefox 1.5 trở lên), bạn có thể sử dụng Array.indexOf . Mặt khác, tôi nghĩ rằng bạn sẽ kết thúc với một cái gì đó tương tự như mã ban đầu của bạn.


16
function inArray(elem,array)
{
    var len = array.length;
    for(var i = 0 ; i < len;i++)
    {
        if(array[i] == elem){return i;}
    }
    return -1;
} 

Trả về chỉ mục mảng nếu tìm thấy hoặc -1 nếu không tìm thấy


16

Chúng tôi sử dụng đoạn mã này (hoạt động với các đối tượng, mảng, chuỗi):

/*
 * @function
 * @name Object.prototype.inArray
 * @description Extend Object prototype within inArray function
 *
 * @param {mix}    needle       - Search-able needle
 * @param {bool}   searchInKey  - Search needle in keys?
 *
 */
Object.defineProperty(Object.prototype, 'inArray',{
    value: function(needle, searchInKey){

        var object = this;

        if( Object.prototype.toString.call(needle) === '[object Object]' || 
            Object.prototype.toString.call(needle) === '[object Array]'){
            needle = JSON.stringify(needle);
        }

        return Object.keys(object).some(function(key){

            var value = object[key];

            if( Object.prototype.toString.call(value) === '[object Object]' || 
                Object.prototype.toString.call(value) === '[object Array]'){
                value = JSON.stringify(value);
            }

            if(searchInKey){
                if(value === needle || key === needle){
                return true;
                }
            }else{
                if(value === needle){
                    return true;
                }
            }
        });
    },
    writable: true,
    configurable: true,
    enumerable: false
});

Sử dụng:

var a = {one: "first", two: "second", foo: {three: "third"}};
a.inArray("first");          //true
a.inArray("foo");            //false
a.inArray("foo", true);      //true - search by keys
a.inArray({three: "third"}); //true

var b = ["one", "two", "three", "four", {foo: 'val'}];
b.inArray("one");         //true
b.inArray('foo');         //false
b.inArray({foo: 'val'})   //true
b.inArray("{foo: 'val'}") //false

var c = "String";
c.inArray("S");        //true
c.inArray("s");        //false
c.inArray("2", true);  //true
c.inArray("20", true); //false

15

Nếu bạn đang kiểm tra nhiều lần sự tồn tại của một đối tượng trong một mảng, bạn có thể nên xem xét

  1. Giữ mảng được sắp xếp mọi lúc bằng cách thực hiện sắp xếp chèn trong mảng của bạn (đặt các đối tượng mới vào đúng vị trí)
  2. Thực hiện cập nhật các đối tượng như loại bỏ + thao tác chèn được sắp xếp và
  3. Sử dụng một tra cứu tìm kiếm nhị phân trong của bạn contains(a, obj).

2
Hoặc nếu có thể, hãy ngừng sử dụng hoàn toàn Mảng và thay vào đó hãy sử dụng Đối tượng làm từ điển, như MattMcKnight và ninjagecko đã đề xuất.
joeytwiddle

13

Giải pháp hoạt động trong tất cả các trình duyệt hiện đại:

function contains(arr, obj) {
  const stringifiedObj = JSON.stringify(obj); // Cache our object to not call `JSON.stringify` on every iteration
  return arr.some(item => JSON.stringify(item) === stringifiedObj);
}

Sử dụng:

contains([{a: 1}, {a: 2}], {a: 1}); // true

Giải pháp IE6 +:

function contains(arr, obj) {
  var stringifiedObj = JSON.stringify(obj)
  return arr.some(function (item) {
    return JSON.stringify(item) === stringifiedObj;
  });
}

// .some polyfill, not needed for IE9+
if (!('some' in Array.prototype)) {
  Array.prototype.some = function (tester, that /*opt*/) {
    for (var i = 0, n = this.length; i < n; i++) {
      if (i in this && tester.call(that, this[i], i, this)) return true;
    } return false;
  };
}

Sử dụng:

contains([{a: 1}, {a: 2}], {a: 1}); // true

Tại sao phải sử dụng JSON.stringify?

Array.indexOfArray.includes(cũng như hầu hết các câu trả lời ở đây) chỉ so sánh theo tham chiếu chứ không phải theo giá trị.

[{a: 1}, {a: 2}].includes({a: 1});
// false, because {a: 1} is a new object

Tặng kem

ES6 một lớp không được tối ưu hóa:

[{a: 1}, {a: 2}].some(item => JSON.stringify(item) === JSON.stringify({a: 1));
// true

Lưu ý: So sánh các đối tượng theo giá trị sẽ hoạt động tốt hơn nếu các khóa theo cùng một thứ tự, vì vậy để an toàn, bạn có thể sắp xếp các khóa trước với gói như thế này: https://www.npmjs.com/package/sort-keys


Cập nhật containschức năng với một tối ưu hóa hoàn hảo. Cảm ơn itinance đã chỉ ra nó.


Đoạn mã đặc biệt này có thể hoạt động trong IE6 (chưa được thử nghiệm), nhưng IE không hỗ trợ ES5 cho đến IE9.
Mark Reed

Vì lý do hiệu suất, bạn nên tránh xâu chuỗi. Ít nhất bạn nên tránh để JSON. Stringify "obj" trên mỗi vòng lặp vì nó đắt tiền và sẽ làm chậm ứng dụng của bạn. Do bạn nên nắm bắt nó trước khi cho vòng lặp trong một biến temp
itinance

1
@itinance điểm tốt. Cập nhật includeschức năng với đề nghị của bạn. Tôi đã chạy jsperf với chức năng của mình. Nó chậm hơn khoảng 5 lần so với lodash. Mặc dù lodash không so sánh theo giá trị và không thể tìm thấy {a: 1}trong [{a: 1}]. Tôi không biết có thư viện nào làm việc đó không. Nhưng tôi tò mò liệu có cách nào hiệu quả hơn và cách làm cực kỳ phức tạp không.
Igor Barbashin

Lưu ý muộn: điều này không hoạt động với, contains([{ a: 1, b: 2 }], { b: 2, a: 1 })vì các đối tượng được xâu chuỗi duy trì thứ tự của các thuộc tính.
Khỉ Heretic

1
@HereticMonkey, đúng. Đó là lý do tại sao tôi đã thêm sort-keysghi chú ở phía dưới
Igor Barbashin

12

Sử dụng lodash là một số chức năng.

Nó ngắn gọn, chính xác và có hỗ trợ đa nền tảng tuyệt vời.

Câu trả lời được chấp nhận thậm chí không đáp ứng yêu cầu.

Yêu cầu: Đề xuất cách ngắn gọn và hiệu quả nhất để tìm hiểu xem mảng JavaScript có chứa đối tượng không.

Trả lời được chấp nhận:

$.inArray({'b': 2}, [{'a': 1}, {'b': 2}])
> -1

Đề nghị của tôi:

_.some([{'a': 1}, {'b': 2}], {'b': 2})
> true

Ghi chú:

$ .inArray hoạt động tốt để xác định xem giá trị vô hướng có tồn tại trong một mảng vô hướng không ...

$.inArray(2, [1,2])
> 1

... nhưng câu hỏi rõ ràng yêu cầu một cách hiệu quả để xác định xem một đối tượng có được chứa trong một mảng hay không.

Để xử lý cả vô hướng và đối tượng, bạn có thể làm điều này:

(_.isObject(item)) ? _.some(ary, item) : (_.indexOf(ary, item) > -1)

10

ECMAScript 6 có một đề xuất thanh lịch về tìm kiếm.

Phương thức find thực hiện chức năng gọi lại một lần cho mỗi phần tử có trong mảng cho đến khi nó tìm thấy một trong đó gọi lại trả về một giá trị thực. Nếu một phần tử như vậy được tìm thấy, tìm ngay lập tức trả về giá trị của phần tử đó. Nếu không, tìm trả về không xác định. gọi lại chỉ được gọi cho các chỉ mục của mảng đã gán giá trị; nó không được gọi cho các chỉ mục đã bị xóa hoặc chưa bao giờ được gán giá trị.

Đây là tài liệu MDN về điều đó.

Các chức năng tìm thấy hoạt động như thế này.

function isPrime(element, index, array) {
    var start = 2;
    while (start <= Math.sqrt(element)) {
        if (element % start++ < 1) return false;
    }
    return (element > 1);
}

console.log( [4, 6, 8, 12].find(isPrime) ); // Undefined, not found
console.log( [4, 5, 8, 12].find(isPrime) ); // 5

Bạn có thể sử dụng điều này trong ECMAScript 5 trở xuống bằng cách xác định hàm .

if (!Array.prototype.find) {
  Object.defineProperty(Array.prototype, 'find', {
    enumerable: false,
    configurable: true,
    writable: true,
    value: function(predicate) {
      if (this == null) {
        throw new TypeError('Array.prototype.find called on null or undefined');
      }
      if (typeof predicate !== 'function') {
        throw new TypeError('predicate must be a function');
      }
      var list = Object(this);
      var length = list.length >>> 0;
      var thisArg = arguments[1];
      var value;

      for (var i = 0; i < length; i++) {
        if (i in list) {
          value = list[i];
          if (predicate.call(thisArg, value, i, list)) {
            return value;
          }
        }
      }
      return undefined;
    }
  });
}

Bây giờ đây là một tiêu chuẩn: ecma
i Intl.org/ecma-262/6.0/#sec-array.prototype.find

9

Mặc dù array.indexOf(x)!=-1là cách ngắn gọn nhất để làm điều này (và đã được hỗ trợ bởi các trình duyệt không phải Internet Explorer trong hơn thập kỷ ...), nhưng đó không phải là O (1), mà là O (N), rất tệ. Nếu mảng của bạn sẽ không thay đổi, bạn có thể chuyển đổi mảng của mình thành hashtable, sau đó thực hiện table[x]!==undefinedhoặc ===undefined:

Array.prototype.toTable = function() {
    var t = {};
    this.forEach(function(x){t[x]=true});
    return t;
}

Bản giới thiệu:

var toRemove = [2,4].toTable();
[1,2,3,4,5].filter(function(x){return toRemove[x]===undefined})

(Thật không may, trong khi bạn có thể tạo Array.prototype.contains để "đóng băng" một mảng và lưu trữ hashtable trong this._cache trong hai dòng, điều này sẽ cho kết quả sai nếu bạn chọn chỉnh sửa mảng của mình sau. JavaScript không đủ móc vào cho phép bạn giữ trạng thái này, không giống như Python chẳng hạn.)


9

Người ta có thể sử dụng Set có phương thức "has ()":

function contains(arr, obj) {
      var proxy = new Set(arr);
      if (proxy.has(obj))
        return true;
      else
        return false;
    }

    var arr = ['Happy', 'New', 'Year'];
    console.log(contains(arr, 'Happy'));


5
Tôi nghĩ return proxy.has(obj)là sạch sẽ hơn nhiều so với hai dòng với tuyên bố if-other ở đây
Maciej Bukowski

function contains(arr, obj) { return new Set(arr).has(obj); }
Gordon Bean

8

Sử dụng:

var myArray = ['yellow', 'orange', 'red'] ;

alert(!!~myArray.indexOf('red')); //true

Bản giới thiệu

Để biết chính xác những gì tilde ~làm tại thời điểm này, hãy tham khảo câu hỏi này Dấu ngã làm gì khi nó đứng trước một biểu thức? .


5
Điều này đã được đăng một năm rưỡi trước không cần phải lặp lại.
Shadow Wizard là tai cho bạn

3
Trên thực tế, nó đã không được đăng. Không phải là một câu trả lời, mà là một nhận xét cho một câu trả lời, và thậm chí sau đó nó không rõ ràng và súc tích. Cảm ơn bạn đã đăng nó, Mina Gabriel.
T.CK

6

OK, bạn chỉ có thể tối ưu hóacủa mình để có kết quả!

Có nhiều cách để làm điều này sạch hơn và tốt hơn, nhưng tôi chỉ muốn lấy mẫu của bạn và áp dụng cho việc sử dụng đó JSON.stringify, chỉ đơn giản là làm một cái gì đó như thế này trong trường hợp của bạn:

function contains(a, obj) {
    for (var i = 0; i < a.length; i++) {
        if (JSON.stringify(a[i]) === JSON.stringify(obj)) {
            return true;
        }
    }
    return false;
}

Lưu ý muộn: điều này không hoạt động với, contains([{ a: 1, b: 2 }], { b: 2, a: 1 })vì các đối tượng được xâu chuỗi duy trì thứ tự của các thuộc tính.
Khỉ Heretic

5

Không có nghĩa là tốt nhất, nhưng tôi chỉ sáng tạo và thêm vào tiết mục.

Không dùng cái này

Object.defineProperty(Array.prototype, 'exists', {
  value: function(element, index) {

    var index = index || 0

    return index === this.length ? -1 : this[index] === element ? index : this.exists(element, ++index)
  }
})


// Outputs 1
console.log(['one', 'two'].exists('two'));

// Outputs -1
console.log(['one', 'two'].exists('three'));

console.log(['one', 'two', 'three', 'four'].exists('four'));


Bạn nên sử dụng cái gì nếu không phải cái này?
bryc

@bryc có thể là giải pháp được chấp nhận, hoặc giải pháp khác từ đây. Nếu bạn không quan tâm nhiều đến hiệu suất, thì bạn có thể sử dụng cái này
sqram

5

Ngạc nhiên vì câu hỏi này vẫn chưa có cú pháp mới nhất được thêm vào, thêm 2 xu của tôi.

Giả sử chúng ta có mảng đối tượng ArrayObj và chúng ta muốn tìm kiếm obj trong đó.

Array.prototype. indexOf -> (trả về chỉ mục hoặc -1 ) thường được sử dụng để tìm chỉ mục của phần tử trong mảng. Điều này cũng có thể được sử dụng để tìm kiếm đối tượng nhưng chỉ hoạt động nếu bạn chuyển tham chiếu đến cùng một đối tượng.

let obj = { name: 'Sumer', age: 36 };
let arrObj = [obj, { name: 'Kishor', age: 46 }, { name: 'Rupen', age: 26 }];


console.log(arrObj.indexOf(obj));// 0
console.log(arrObj.indexOf({ name: 'Sumer', age: 36 })); //-1

console.log([1, 3, 5, 2].indexOf(2)); //3

Array.prototype. bao gồm -> (trả về đúng hay sai )

console.log(arrObj.includes(obj));  //true
console.log(arrObj.includes({ name: 'Sumer', age: 36 })); //false

console.log([1, 3, 5, 2].includes(2)); //true

Array.prototype. find -> (nhận cuộc gọi lại, trả về giá trị / đối tượng đầu tiên trả về true trong CB).

console.log(arrObj.find(e => e.age > 40));  //{ name: 'Kishor', age: 46 }
console.log(arrObj.find(e => e.age > 40)); //{ name: 'Kishor', age: 46 }

console.log([1, 3, 5, 2].find(e => e > 2)); //3

Array.prototype. find Index -> (nhận cuộc gọi lại, trả về chỉ mục của giá trị / đối tượng đầu tiên trả về true trong CB).

console.log(arrObj.findIndex(e => e.age > 40));  //1
console.log(arrObj.findIndex(e => e.age > 40)); //1

console.log([1, 3, 5, 2].findIndex(e => e > 2)); //1

Vì find và find Index có một cuộc gọi lại, chúng tôi có thể tìm nạp bất kỳ đối tượng nào (ngay cả khi chúng tôi không có tham chiếu) từ mảng bằng cách đặt sáng tạo điều kiện thực.


5

Giải pháp đơn giản cho yêu cầu này là sử dụng find()

Nếu bạn đang có một loạt các đối tượng như dưới đây,

var users = [{id: "101", name: "Choose one..."},
{id: "102", name: "shilpa"},
{id: "103", name: "anita"},
{id: "104", name: "admin"},
{id: "105", name: "user"}];

Sau đó, bạn có thể kiểm tra xem đối tượng có giá trị của bạn đã có hay chưa

let data = users.find(object => object['id'] === '104');

nếu dữ liệu là null thì không có admin, nếu không nó sẽ trả về đối tượng hiện có như bên dưới.

{id: "104", name: "admin"}

Sau đó, bạn có thể tìm chỉ mục của đối tượng đó trong mảng và thay thế đối tượng bằng mã bên dưới.

let indexToUpdate = users.indexOf(data);
let newObject = {id: "104", name: "customer"};
users[indexToUpdate] = newObject;//your new object
console.log(users);

bạn sẽ nhận được giá trị như dưới đây

[{id: "101", name: "Choose one..."},
{id: "102", name: "shilpa"},
{id: "103", name: "anita"},
{id: "104", name: "customer"},
{id: "105", name: "user"}];

hy vọng điều này sẽ giúp bất cứ ai.


5

    function countArray(originalArray) {
     
    	var compressed = [];
    	// make a copy of the input array
    	var copyArray = originalArray.slice(0);
     
    	// first loop goes over every element
    	for (var i = 0; i < originalArray.length; i++) {
     
    		var count = 0;	
    		// loop over every element in the copy and see if it's the same
    		for (var w = 0; w < copyArray.length; w++) {
    			if (originalArray[i] == copyArray[w]) {
    				// increase amount of times duplicate is found
    				count++;
    				// sets item to undefined
    				delete copyArray[w];
    			}
    		}
     
    		if (count > 0) {
    			var a = new Object();
    			a.value = originalArray[i];
    			a.count = count;
    			compressed.push(a);
    		}
    	}
     
    	return compressed;
    };
    
    // It should go something like this:
    
    var testArray = new Array("dog", "dog", "cat", "buffalo", "wolf", "cat", "tiger", "cat");
    var newArray = countArray(testArray);
    console.log(newArray);

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.