Câu hỏi Xác định xem một mảng có chứa một giá trị [trùng lặp] hay không


Câu hỏi này đã có câu trả lời ở đây:

Tôi cần phải xác định nếu một giá trị tồn tại trong một mảng.

Tôi đang sử dụng chức năng sau:

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

Hàm trên luôn trả về false.

Giá trị mảng và cuộc gọi hàm như sau:

arrValues = ["Sam","Great", "Sample", "High"]
alert(arrValues.contains("Sam"));

1152
2017-07-25 08:18


gốc


Mã hoạt động trong Safari 4.0.2. BTW: Tôi sẽ làm === so sánh thay vì chỉ ==. - Georg Schölly
"Hàm trên luôn trả về false." Không, hàm này không hoạt động như mong đợi - lỗi phải ở đâu đó khác. - Christoph
Xem thêm: stackoverflow.com/q/237104/1569 - Factor Mystic
Finally its worked. its due to improper trim of the comparing value. there was some space in the comparing value (Nhận xét từ người hỏi, đến câu trả lời được chấp nhận.) - ANeves
Nó hoạt động, bạn nên đã sử dụng === thay vì == - hellol11


Các câu trả lời:


var contains = function(needle) {
    // Per spec, the way to identify NaN is that it is not equal to itself
    var findNaN = needle !== needle;
    var indexOf;

    if(!findNaN && typeof Array.prototype.indexOf === 'function') {
        indexOf = Array.prototype.indexOf;
    } else {
        indexOf = function(needle) {
            var i = -1, index = -1;

            for(i = 0; i < this.length; i++) {
                var item = this[i];

                if((findNaN && item !== item) || item === needle) {
                    index = i;
                    break;
                }
            }

            return index;
        };
    }

    return indexOf.call(this, needle) > -1;
};

Bạn có thể sử dụng nó như thế này:

var myArray = [0,1,2],
    needle = 1,
    index = contains.call(myArray, needle); // true

Xác nhận / sử dụng CodePen


949
2017-07-25 08:22



Lưu ý rằng indexOf trên các mảng không được thực hiện trong IE, nhưng bạn có thể tự định nghĩa nó - RaYell
bạn nên sử dụng so sánh đã nhập với === tương thích với triển khai gốc - Christoph
cố định so sánh và thêm phần còn thiếu return -1; xin lưu ý rằng theo thông số ES5, phương pháp này sẽ hoạt động khác với phương pháp gốc trong trường hợp zeroes và NaN được thiết lập (xem 15.4.4.14 và 9.12 so với 11.9.6) - Christoph
Phiên bản nào của IE làm câu trả lời này đề cập đến? - Daniel Allen Langdon
@RiceFlourCookies, IE <9. - eyelidlessness


jQuery có một chức năng tiện ích cho việc này:

$.inArray(value, array)

Trả về chỉ mục của value trong array. Trả lại -1 nếu array không chứa value.

Xem thêm Làm thế nào để kiểm tra xem một mảng có chứa một đối tượng trong JavaScript không?


929
2017-09-24 19:34



Đừng để cái tên "inArray" đánh lừa bạn. Như đã đề cập ở trên (nhưng tất nhiên tôi đã không đọc đủ gần), trả về -1 (không sai) nếu phần tử không tồn tại. - Greg Bernhardt
Tôi không thể tin rằng họ đã đặt tên cho chức năng quá tệ. - Stephen Paul
@ Steve Paul những gì là sai với tên? nó làm những gì nó nói: -1 = nó KHÔNG có, bất cứ điều gì khác = nó có - Jeffz
'inArray' ngụ ý rằng một boolean sẽ được trả về cho biết liệu phần tử có thể được tìm thấy trong mảng hay không. Vì vậy, người dùng có thể cảm thấy bị cám dỗ khi sử dụng biểu thức: if ($ .inArray ('myval', myarray)) {...} Điều này sẽ được đánh giá là true nếu 'myval' KHÔNG trong myarray. Hơn nữa, nó sẽ đánh giá sai nếu chỉ số của myval là 0. - Stephen Paul
Sự phi booleanness của $.inArraySự trở lại chắc chắn cảm thấy giống như một sai lầm trên một phần của jQuery. Chắc chắn, nó phải được đổi tên thành $.indexOf, nếu đó là chức năng của nó là sự đổ đầy? - ChaseMoskal


Đây thường là phương thức indexOf (). Bạn sẽ nói:

return arrValues.indexOf('Sam') > -1

746
2017-07-25 08:25



indexOf không hoạt động trong <IE9. - Doug S
Không làm việc với NaN - Trevor
Tôi thích cách bình luận của Kenneth J có nhiều lợi thế hơn là câu trả lời. Nhưng tốt thứ - Tôi đã sử dụng indexOf () cho chuỗi, nhưng tôi không biết bạn có thể sử dụng nó cho mảng nói chung. - doubleDown
return ~arrValues.indexOf('Sam') sẽ trở lại false nếu phần tử không tồn tại trong mảng - Zychoo
@SebastianMach và nếu tất cả các nhà phát triển web chỉ cần đứng lên nói không ... người dùng sẽ bị buộc phải thay đổi. và giúp các công ty tiết kiệm tiền vì họ không phải thuê nhà phát triển IE - Sujay Phadke


Array.prototype.includes ()

Trong ES2016, có Array.prototype.includes().

Các includes() phương thức xác định xem một mảng có bao gồm một phần tử nào đó hay không, true hoặc là false khi thích hợp.

Thí dụ

["Sam", "Great", "Sample", "High"].includes("Sam"); // true

Ủng hộ

Theo kangax và MDN, các nền tảng sau được hỗ trợ:

  • Chrome 47
  • Cạnh 14
  • Firefox 43
  • Opera 34
  • Safari 9
  • Nút 6

Hỗ trợ có thể được mở rộng bằng cách sử dụng Babel (sử dụng babel-polyfill) hoặc là core-js. MDN cũng cung cấp polyfill:

if (![].includes) {
  Array.prototype.includes = function(searchElement /*, fromIndex*/ ) {
    'use strict';
    var O = Object(this);
    var len = parseInt(O.length) || 0;
    if (len === 0) {
      return false;
    }
    var n = parseInt(arguments[1]) || 0;
    var k;
    if (n >= 0) {
      k = n;
    } else {
      k = len + n;
      if (k < 0) {k = 0;}
    }
    var currentElement;
    while (k < len) {
      currentElement = O[k];
      if (searchElement === currentElement ||
         (searchElement !== searchElement && currentElement !== currentElement)) {
        return true;
      }
      k++;
    }
    return false;
  };
}

247
2018-06-09 06:45



Tôi bị cám dỗ để đăng câu trả lời này qua một số câu hỏi javascript liên quan đến nhiều giá trị biến hoặc mảng. Các polyfill từ MDN là tốt đẹp. - Nathan Goings
cám ơn vì cái này! Babel polyfils nó độc đáo :-) Tôi nhớ 2 năm trước jQuery đã ở trong bất kỳ dự án và ngày nay nó Babel :) chiến thắng lớn cho cộng đồng JavaScript! Có bảng những gì có sẵn của ES7 đã có trên nhiều nền tảng bao gồm cả pollyfils babel kangax.github.io/compat-table/es2016plus - Lukas
Nên là câu trả lời được chấp nhận - Antoine


Hầu như luôn an toàn hơn khi sử dụng thư viện như lodash đơn giản là vì tất cả các vấn đề với tính tương thích và hiệu quả của trình duyệt chéo.

Hiệu quả bởi vì bạn có thể được đảm bảo rằng tại bất kỳ thời điểm nào, một thư viện cực kỳ phổ biến như gạch dưới sẽ có phương pháp hiệu quả nhất để hoàn thành một chức năng tiện ích như thế này.

_.includes([1, 2, 3], 3); // returns true

Nếu bạn lo lắng về số lượng lớn đang được thêm vào ứng dụng của mình bằng cách bao gồm toàn bộ thư viện, hãy biết rằng bạn có thể bao gồm chức năng riêng:

var includes = require('lodash/collections/includes');

ĐỂ Ý: Với phiên bản cũ của lodash, đây là _.contains() thay vì _.includes().


116
2018-01-25 03:00



@threed, bạn không phải bao gồm toàn bộ thư viện. Một phần chức năng có thể được bao gồm với yêu cầu ('lodash / collections / contains'). - ncabral
FYI: Với lodash 4 bây giờ _.includes() thay vì _.contains(). - shadowhorst
Cảm ơn @shadowhorst. Tôi đã chỉnh sửa câu trả lời để phản ánh điều này. - ncabral
thư viện trợ giúp có thể có vẻ thuận tiện nhưng có xu hướng thay đổi (quá) thường xuyên, xem bình luận ở trên "lodash 4 '.contains () 'hiện là'.bao gồm()'" - anneb
@anneb có thể nói về bất kỳ thư viện nào. đó là lý do tại sao bạn có quản lý semver và dependency. - ncabral


tl; dr 

function includes(k) {
  for(var i=0; i < this.length; i++){
    if( this[i] === k || ( this[i] !== this[i] && k !== k ) ){
      return true;
    }
  }
  return false;
}

Thí dụ

function includes(k) {
  for(var i=0; i < this.length; i++){
    if( this[i] === k || ( this[i] !== this[i] && k !== k ) ){
      return true;
    }
  }
  return false;
}

function log(msg){
  $('#out').append('<div>' + msg + '</div>');  
}

var arr = [1, "2", NaN, true];
arr.includes = includes;

log('var arr = [1, "2", NaN, true];');
log('<br/>');
log('arr.includes(1): ' + arr.includes(1));
log('arr.includes(2): ' + arr.includes(2));
log('arr.includes("2"): ' + arr.includes("2"));
log('arr.includes(NaN): ' + arr.includes(NaN));
log('arr.includes(true): ' + arr.includes(true));
log('arr.includes(false): ' + arr.includes(false));
#out{
  font-family:monospace;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id=out></div>

Câu trả lời dài hơn

Tôi biết câu hỏi này không thực sự về việc có nên mở rộng các đối tượng dựng sẵn hay không, nhưng nỗ lực của OP và các nhận xét về câu trả lời này làm nổi bật cuộc tranh luận đó. Nhận xét của tôi từ ngày 12 tháng 2, '13 trích dẫn một bài viết phác thảo cuộc tranh luận này thực sự tốt, tuy nhiên liên kết đó đã bị phá vỡ và tôi không thể chỉnh sửa nhận xét ban đầu vì đã quá nhiều thời gian, vì vậy tôi đưa nó vào đây.

Nếu bạn đang tìm cách mở rộng tích hợp Array đối tượng với một contains phương pháp, có lẽ cách tốt nhất và có trách nhiệm nhất để làm điều này sẽ là sử dụng polyfill này từ MDN. (Xem thêm điều này của bài viết MDN về kế thừa nguyên mẫu, giải thích rằng "Lý do duy nhất để mở rộng nguyên mẫu được tích hợp sẵn là quay lại các tính năng của các công cụ JavaScript mới hơn, ví dụ như Array.forEach, v.v ...")

if (!Array.prototype.includes) {
  Array.prototype.includes = function(searchElement /*, fromIndex*/ ) {
    'use strict';
    var O = Object(this);
    var len = parseInt(O.length) || 0;
    if (len === 0) {
      return false;
    }
    var n = parseInt(arguments[1]) || 0;
    var k;
    if (n >= 0) {
      k = n;
    } else {
      k = len + n;
      if (k < 0) {k = 0;}
    }
    var currentElement;
    while (k < len) {
      currentElement = O[k];
      if (searchElement === currentElement ||
         (searchElement !== searchElement && currentElement !== currentElement)) {
        return true;
      }
      k++;
    }
    return false;
  };
}

Không muốn sự bình đẳng nghiêm ngặt, hoặc muốn chọn?

function includes(k, strict) {
  strict = strict !== false; // default is true
  // strict = !!strict; // default is false
  for(var i=0; i < this.length; i++){
    if( (this[i] === k && strict) || 
        (this[i] == k && !strict) ||
        (this[i] !== this[i] && k !== k)
    ) {
      return true;
    }
  }
  return false;
}

46
2017-09-15 20:03



Không phải kỹ thuật này làm tăng thêm các kiểu dựng sẵn cau mày sao? - Sahat Yalkabov
Lỗi: [1,2,4].contains([].contains) là đúng. Cũng không cần thiết chậm do lỗi tương tự. Tránh for..in qua mảng. - Eamon Nerbonne
@Eamon Nerbonne: Tôi chỉ dán mã đó vào jsfiddle.net và bị sai. Tôi có làm điều gì sai. Ngoài ra, bạn có thể giải thích về cách lỗi này làm chậm mã xuống không? Cuối cùng, tôi đã không nhận thức được rằng có một sự khác biệt hiệu suất cho "for..in" vòng. Bạn có thể giải thích hoặc hướng dẫn tôi tới một bài viết mà tôi có thể đọc thêm không? - Trevor
@threed hoàn toàn không đúng sự thật: "Đây là một thực tế rất phổ biến và được sử dụng rộng rãi bởi jQuery" - chúng tạo ra các nguyên mẫu mới cho một số đối tượng mà chúng sử dụng, nhưng KHÔNG sửa đổi các nguyên mẫu dựng sẵn - naugtur


Vì ECMAScript6, người ta có thể sử dụng Set:

var myArray = ['A', 'B', 'C'];
var mySet = new Set(myArray);
var hasB = mySet.has('B'); // true
var hasZ = mySet.has('Z'); // false

33
2018-01-07 13:05





Đóng góp nhỏ của tôi:

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

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

18
2017-09-13 17:29





Với việc thực hiện indexOf cho IE (như được mô tả bởi mí mắt):

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

17
2017-07-25 09:12



Đó là dư thừa. - eyelidlessness
Có thể, nhưng nó làm cho mã của bạn sạch hơn. nếu (myArray.contains (obj)) dễ đọc hơn và nêu rõ ý định tốt hơn nếu (myArray.indexOf (obj)> -1). Tôi dứt khoát sẽ thực hiện cả hai. - rlovtang
Điều này có hoạt động trên tất cả các trình duyệt không? Hoặc làm một số trình duyệt xem xét chỉ mục của "2" và 2 giống nhau không? - Trevor


Nếu bạn có quyền truy cập vào ECMA 5, bạn có thể sử dụng một số phương pháp.

MDN MỘT SỐ Liên kết phương pháp

arrValues = ["Sam","Great", "Sample", "High"];

function namePresent(name){
  return name === this.toString();
}
// Note:
// namePresent requires .toString() method to coerce primitive value
// i.e. String {0: "S", 1: "a", 2: "m", length: 3, [[PrimitiveValue]]: "Sam"}
// into
// "Sam"

arrValues.some(namePresent, 'Sam');
=> true;

Nếu bạn có quyền truy cập vào ECMA 6, bạn có thể sử dụng bao gồm phương pháp.

MDN BAO GỒM Liên kết phương pháp

arrValues = ["Sam","Great", "Sample", "High"];

arrValues.includes('Sam');
=> true;

15
2017-07-31 15:46