Làm cách nào để xác định xem mảng Javascript có chứa một đối tượng có thuộc tính bằng với một giá trị đã cho không?


655

Tôi có một mảng như

vendors = [
    {
      Name: 'Magenic',
      ID: 'ABC'
     },
    {
      Name: 'Microsoft',
      ID: 'DEF'
    } //and so on goes array... 
];

Làm cách nào để kiểm tra mảng này để xem Magenic có tồn tại không? Tôi không muốn lặp, trừ khi tôi phải làm thế. Tôi đang làm việc với một vài nghìn hồ sơ.


CẬP NHẬT

Vì đây là một bài viết phổ biến, tôi nghĩ rằng tôi muốn chia sẻ một cái gì đó mới mà tôi tìm thấy. Và nó xuất hiện @CAFxX đã chia sẻ điều này! Tôi nên đọc những điều này thường xuyên hơn. Tôi đã xem qua https://benfrain.com/under Hiểu-native-javascript-marray-method / .

vendors.filter(function(vendor){ return vendor.Name === "Magenic" })

Và với ECMAScript 2015, nó thậm chí còn đơn giản hơn khi sử dụng các hàm mũi tên mới:

vendors.filter(vendor => vendor.Name === "Magenic")

Xin vui lòng bỏ qua nhận xét có vẻ ngẫu nhiên, nhưng câu hỏi của bạn có liên quan đến JSON hay chỉ là mảng JavaScript không?
Alex Turpin

4
Giải pháp @CAFxX tốt hơn, sẽ rất tuyệt nếu bạn cập nhật giải pháp đã chọn.
eMarine

1
Đồng ý, không thấy điều đó sớm hơn!
David Lozzi

Bạn có thể đơn giản hóa điều này ngay cả nhiều hơn bằng cách sử dụng các hàm mũi tên. Tất cả các trình duyệt hiện đại đều hỗ trợ điều này và trông đẹp hơn.
Piotr Kula

bạn có thể sử dụng chức năng bản đồ, rất hữu ích
Monir alhussini

Câu trả lời:


264

Chỉnh sửa năm 2018 : Câu trả lời này là từ năm 2011, trước khi các trình duyệt đã hỗ trợ rộng rãi các phương thức lọc mảng và các hàm mũi tên. Hãy xem câu trả lời của CAFxX .

Không có cách "ma thuật" nào để kiểm tra thứ gì đó trong một mảng mà không có vòng lặp. Ngay cả khi bạn sử dụng một số chức năng, chính chức năng đó sẽ sử dụng một vòng lặp. Những gì bạn có thể làm là thoát ra khỏi vòng lặp ngay khi bạn tìm thấy những gì bạn đang tìm kiếm để giảm thiểu thời gian tính toán.

var found = false;
for(var i = 0; i < vendors.length; i++) {
    if (vendors[i].Name == 'Magenic') {
        found = true;
        break;
    }
}

4
Không vấn đề gì. Hãy nhớ rằng giải pháp của Keith cũng rất khả thi và giúp bạn tránh khỏi vòng lặp.
Alex Turpin

2
Bạn không cần một cờ nếu tất cả những gì bạn cần biết là có "cái gì đó" hay không, bạn chỉ cần kiểm tra giá trị của chỉ mục quét với kích thước của mảng. Để làm việc này, chỉ số var cần được khai báo trước câu lệnh for.
Alex

5
Các tùy chọn này dường như hoạt động ngay bây giờ: nhà cung cấp.forEach, nhà cung cấp.filter, nhà cung cấp.reduce
David Lozzi

1
Còn về JSON.opesify (nhà cung cấp) .indexOf ('Magenic')! == -1
Hơi thở cuối cùng

1
@LastBreath có thể dẫn đến kết quả dương tính giả khá dễ dàng nếu 'Magenic'ở một nơi khác trong đối tượng
Alex Turpin

945

Không cần phải phát minh lại bánh xevòng lặp, ít nhất là không rõ ràng (chỉ sử dụng các chức năng mũi tên , chỉ các trình duyệt hiện đại ):

if (vendors.filter(e => e.Name === 'Magenic').length > 0) {
  /* vendors contains the element we're looking for */
}

hoặc, tốt hơn nữa :

if (vendors.some(e => e.Name === 'Magenic')) {
  /* vendors contains the element we're looking for */
}

EDIT: Nếu bạn cần khả năng tương thích với các trình duyệt tệ hại thì cách tốt nhất của bạn là:

if (vendors.filter(function(e) { return e.Name === 'Magenic'; }).length > 0) {
  /* vendors contains the element we're looking for */
}

4
@Rocket tại sao bạn chỉnh sửa câu trả lời của tôi? Cú pháp không có dấu ngoặc nhọn là javascript hoàn toàn hợp lệ .
CAFxX

4
Cú pháp "lambda" vẫn không hoạt động trong Chrome 16 (không phải là trình duyệt tệ hại).
Rocket Hazmat

27
Nó phụ thuộc vào định nghĩa của bạn về tệ hại, tôi đoán. Cú pháp đó là một phần của javascript 1.8.
CAFxX

7
Các biểu thức đóng mà bạn đang sử dụng ở đây trong các ví dụ thứ nhất và thứ hai có Không chuẩn, không sử dụng! cảnh báo từ Mozilla (xem liên kết đó). Họ chỉ từng làm việc trong Firefox và hiện không được chấp nhận và sẽ bị xóa theo các chức năng mũi tên .
doppelgreener

2
@ 7 Cấm vì somecó thể đoản mạch một khi name === "Magenic"tìm thấy vật. Với filter, nó sẽ kiểm tra từng mục cho đến hết mảng và tạo một mục mảng mới phù hợp với điều kiện, sau đó kiểm tralength
adiga

92

Không có vòng lặp cần thiết. Ba phương pháp mà tôi nghĩ đến:

Array.prototype.some ()

Đây là câu trả lời chính xác nhất cho câu hỏi của bạn, tức là "kiểm tra xem có gì tồn tại không", ngụ ý kết quả bool. Điều này sẽ đúng nếu có bất kỳ đối tượng 'Magenic' nào, sai khác:

let hasMagenicVendor = vendors.some( vendor => vendor['Name'] === 'Magenic' )

Array.prototype.filter ()

Điều này sẽ trả về một mảng của tất cả các đối tượng 'Magenic', ngay cả khi chỉ có một (sẽ trả về một mảng một phần tử):

let magenicVendors = vendors.filter( vendor => vendor['Name'] === 'Magenic' )

Nếu bạn cố gắng ép buộc điều này thành boolean, nó sẽ không hoạt động, vì một mảng trống (không có đối tượng 'Magenic') vẫn còn đúng. Vì vậy, chỉ cần sử dụng magenicVendors.lengthtrong điều kiện của bạn.

Array.prototype.find ()

Điều này sẽ trả về đối tượng 'Magenic' đầu tiên (hoặc undefinednếu không có):

let magenicVendor = vendors.find( vendor => vendor['Name'] === 'Magenic' );

Điều này ép buộc một boolean ổn (bất kỳ đối tượng là sự thật, undefinedlà giả mạo ).


Lưu ý: Tôi đang sử dụng nhà cung cấp ["Tên"] thay vì nhà cung cấp. Tên vì vỏ bọc kỳ lạ của tên tài sản.

Lưu ý 2: Không có lý do để sử dụng đẳng thức lỏng lẻo (==) thay vì bình đẳng nghiêm ngặt (===) khi kiểm tra tên.


5
Thật hữu ích khi chỉ ra rằng dưới mui xe, tất cả đều là vòng lặp. Đây cũng là tất cả các tính toán chậm hơn chỉ đơn giản là để lặp và thực hiện các hoạt động.
ThePartyTurtle

Cũng có thể chia sẻ tình yêu đó tại đây: stackoverflow.com/questions/21748670/ Vì vậy, nhiều người như tôi không điều hướng đến trang cũ đó và đưa ra các giả định.
ThePartyTurtle

43

Câu trả lời được chấp nhận vẫn hoạt động nhưng bây giờ chúng ta có một phương thức riêng ECMAScript 6 [Array.find][1]để đạt được hiệu quả tương tự.

Trích dẫn MDN:

Phương thức find () trả về giá trị của phần tử đầu tiên trong mảng thỏa mãn hàm kiểm tra được cung cấp. Nếu không, không xác định được trả lại.

var arr = []; 
var item = {
  id: '21',
  step: 'step2',
  label: 'Banana',
  price: '19$'
};

arr.push(item);
/* note : data is the actual object that matched search criteria 
  or undefined if nothing matched */
var data = arr.find( function( ele ) { 
    return ele.id === '21';
} );

if( data ) {
 console.log( 'found' );
 console.log(data); // This is entire object i.e. `item` not boolean
}

Xem liên kết jsfiddle của tôi Có một polyfill cho IE được cung cấp bởi mozilla


2
Có thể ngắn hơn nếu bạn chỉ cần làm return ele.id == '2', nhưng +1 cho một giải pháp ES6 tốt.
Lye Fish


Tôi nghĩ điều quan trọng là chỉ ra rằng giá trị trả về của 'dữ liệu' (khi ele.id khớp với một id, chẳng hạn như '21') sẽ là chính mục mảng (trong trường hợp này là toàn bộ đối tượng mục). Nếu kỳ vọng là kết quả biến dữ liệu sẽ là 'đúng' hoặc 'sai' thay vì giá trị giả, bạn sẽ thất vọng vô cùng.
adamgede

Cám ơn! Nhiệm vụ của tôi là một chút khác nhau. Lấy chỉ mục của Object trong Mảng => push if <0 || splice(index, 1)đây là mã được cập nhật một chút của tôi:const index = this.selected.indexOf(this.selected.find(s => s.id == passedObj.id))
Leonid Zadorozhnykh

29

Đây là cách tôi làm

const found = vendors.some(item => item.Name === 'Magenic');

array.some()phương thức kiểm tra nếu có ít nhất một giá trị trong một mảng phù hợp với tiêu chí và trả về giá trị boolean. Từ đây bạn có thể đi với:

if (found) {
// do something
} else {
// do something else
}

22

Trừ khi bạn muốn cơ cấu lại nó như thế này:

vendors = {
    Magenic: {
      Name: 'Magenic',
      ID: 'ABC'
     },
    Microsoft: {
      Name: 'Microsoft',
      ID: 'DEF'
    } and so on... 
};

mà bạn có thể làm if(vendors.Magnetic)

Bạn sẽ phải lặp


2
Trong trường hợp anh ta vẫn muốn duy trì cấu trúc đối tượng để sử dụng nó ở nơi khác
Keith.Abramo

21

Theo thông số kỹ thuật ECMAScript 6, bạn có thể sử dụng findIndex.

const magenicIndex = vendors.findIndex(vendor => vendor.Name === 'Magenic');

magenicIndexsẽ giữ một trong hai 0(đó là chỉ mục trong mảng) hoặc -1nếu nó không được tìm thấy.


Chỉ cần làm cho mọi người biết rằng 0 vẫn sẽ khớp với kết quả sai nếu điều đó được sử dụng làm điều kiện. Vì lý do này, tôi nghĩ find () tốt hơn khi bạn có được một đánh giá trung thực logic hơn .
dhj

15

Như OP đã đặt câu hỏi liệu khóa có tồn tại hay không .

Một giải pháp thanh lịch hơn sẽ trả về boolean bằng hàm giảm ES6 có thể là

const magenicVendorExists =  vendors.reduce((accumulator, vendor) => (accumulator||vendor.Name === "Magenic"), false);

Lưu ý: Tham số ban đầu của giảm là a falsevà nếu mảng có khóa, nó sẽ trả về true.

Hy vọng nó sẽ giúp thực thi mã tốt hơn và sạch hơn


1
Từ khi nào !! [] bằng với sai?
Serge

1
Bắt đẹp. Cập nhật câu trả lời bằng cách sử dụng giảm :)
Jay Chakra

1
Cái này sai. Tham số đầu tiên reducelà bộ tích lũy chứ không phải vendorđối tượng. Điều này kiểm tra false.Name === "Magenic"trong mỗi vòng lặp và nó trả về sai
adiga

@adiga: Đã sửa.
Jay Chakra

1
Vui lòng kiểm tra giải pháp của Mirza Leka. Một giải pháp thanh lịch hơn nhiều.
Jay Chakra

13

Bạn không thể không nhìn vào đối tượng thực sự.

Bạn có lẽ nên thay đổi cấu trúc của bạn một chút, như

vendors = {
    Magenic:   'ABC',
    Microsoft: 'DEF'
};

Sau đó, bạn có thể chỉ cần sử dụng nó như một băm tra cứu.

vendors['Microsoft']; // 'DEF'
vendors['Apple']; // undefined

5

Bạn phải lặp đi lặp lại, không có cách nào xung quanh nó.

function seekVendor(vendors, name) {
  for (var i=0, l=vendors.length; i<l; i++) {
    if (typeof vendors[i] == "object" && vendors[i].Name === name) {
      return vendors[i];
    }
  }
}

Tất nhiên, bạn có thể sử dụng một thư viện như linq.js để làm cho điều này trở nên dễ chịu hơn:

Enumerable.From(vendors).Where("$.Name == 'Magenic'").First();

(xem jsFiddle để xem bản demo)

Tôi nghi ngờ rằng linq.js sẽ nhanh hơn vòng lặp thẳng, nhưng chắc chắn nó linh hoạt hơn khi mọi thứ trở nên phức tạp hơn một chút.


5

Kiểm tra các phần tử mảng:

JS Cung cấp các hàm mảng cho phép bạn đạt được điều này tương đối dễ dàng. Họ là như sau:

  1. Array.prototype.filter: Thực hiện một hàm gọi lại là một bài kiểm tra, mảng sau đó được lặp lại với là gọi lại và được lọc theo hàm gọi lại này. Một mảng được lọc mới được trả về.
  2. Array.prototype.some: Thực hiện một hàm gọi lại là một bài kiểm tra, mảng sau đó được lặp lại với là gọi lại và nếu bất kỳ phần tử nào vượt qua kiểm tra, thì boolean true được trả về. Nếu không sai được trả lại

Các chi tiết cụ thể được giải thích tốt nhất thông qua một ví dụ:

Thí dụ:

vendors = [
    {
      Name: 'Magenic',
      ID: 'ABC'
     },
    {
      Name: 'Microsoft',
      ID: 'DEF'
    } //and so on goes array... 
];

// filter returns a new array, we instantly check if the length 
// is longer than zero of this newly created array
if (vendors.filter(company => company.Name === 'Magenic').length ) {
  console.log('I contain Magenic');
}

// some would be a better option then filter since it directly returns a boolean
if (vendors.some(company => company.Name === 'Magenic')) {
  console.log('I also contain Magenic');
}

Hỗ trợ trình duyệt:

Hai chức năng này là ES6chức năng, không phải tất cả các trình duyệt có thể hỗ trợ chúng. Để khắc phục điều này, bạn có thể sử dụng một polyfill. Đây là polyfill cho Array.prototype.some(từ MDN):

if (!Array.prototype.some) {
  Array.prototype.some = function(fun, thisArg) {
    'use strict';

    if (this == null) {
      throw new TypeError('Array.prototype.some called on null or undefined');
    }

    if (typeof fun !== 'function') {
      throw new TypeError();
    }

    var t = Object(this);
    var len = t.length >>> 0;

    for (var i = 0; i < len; i++) {
      if (i in t && fun.call(thisArg, t[i], i, t)) {
        return true;
      }
    }

    return false;
  };
}


5

Có thể là quá muộn, nhưng mảng javascript có hai phương thức someeveryphương thức trả về boolean và có thể giúp bạn đạt được điều này.

Tôi nghĩ rằng somesẽ thích hợp nhất cho những gì bạn dự định đạt được.

vendors.some( vendor => vendor['Name'] !== 'Magenic' )

Một số xác nhận rằng bất kỳ đối tượng nào trong mảng thỏa mãn điều kiện đã cho.

vendors.every( vendor => vendor['Name'] !== 'Magenic' )

Mỗi xác nhận rằng tất cả các đối tượng trong mảng thỏa mãn điều kiện đã cho.


Nó không hoạt động, const array1 = [{name:'Mike'},{name:'Alice'}]; console.log(array1.every(item => item.name !== 'Mike'));nó sẽ trở lại đúng
Thanwa Ch.

Xin lỗi, ý tôi là some, sẽ cập nhật câu trả lời của tôi.
Akinjiola Toni

4

nếu bạn đang sử dụng jquery, bạn có thể tận dụng grep để tạo mảng với tất cả các đối tượng phù hợp:

var results = $.grep(vendors, function (e) {
    return e.Name == "Magenic";
});

và sau đó sử dụng mảng kết quả:

for (var i=0, l=results.length; i<l; i++) {
    console.log(results[i].ID);
}

3

Sửa lỗi cho tôi nếu tôi sai .. tôi có thể đã sử dụng forEachphương pháp như thế này,

var found=false;
vendors.forEach(function(item){
   if(item.name === "name"){
       found=true;

   }
});

Ngày nay tôi đã quen với nó, bởi vì nó đơn giản và từ tự giải thích. Cảm ơn bạn.


1
Lưu ý: không sử dụng trả lại tại đây
Edison

2

Bạn có thể thử nó làm việc cho tôi.

const _ = require('lodash');

var arr = [
  {
    name: 'Jack',
    id: 1
  },
  {
    name: 'Gabriel',
    id: 2
  },
  {
    name: 'John',
    id: 3
  }
]

function findValue(arr,value) {
  return _.filter(arr, function (object) {
    return object['name'].toLowerCase().indexOf(value.toLowerCase()) >= 0;
  });
}

console.log(findValue(arr,'jack'))
//[ { name: 'Jack', id: 1 } ]

Vâng, đây là một câu hỏi thực sự cũ và tôi nghĩ rằng bản cập nhật của nó đã có giải pháp tốt nhất hiện nay.
Federico Galfione

1

Bạn có thể sử dụng lodash . Nếu thư viện lodash quá nặng cho ứng dụng của bạn, hãy cân nhắc việc sử dụng chức năng không cần thiết không được sử dụng.

let newArray = filter(_this.props.ArrayOne, function(item) {
                    return find(_this.props.ArrayTwo, {"speciesId": item.speciesId});
                });

Đây chỉ là một cách để làm điều này. Một số khác có thể là:

var newArray=  [];
     _.filter(ArrayOne, function(item) {
                        return AllSpecies.forEach(function(cItem){
                            if (cItem.speciesId == item.speciesId){
                            newArray.push(item);
                          }
                        }) 
                    });

console.log(arr);

Ví dụ trên cũng có thể được viết lại mà không cần sử dụng bất kỳ thư viện nào như:

var newArray=  [];
ArrayOne.filter(function(item) {
                return ArrayTwo.forEach(function(cItem){
                    if (cItem.speciesId == item.speciesId){
                    newArray.push(item);
                  }
                }) 
            });
console.log(arr);

Hy vọng câu trả lời của tôi sẽ giúp.


1

Nhiều câu trả lời ở đây là tốt và khá dễ dàng. Nhưng nếu mảng đối tượng của bạn có một bộ giá trị cố định thì bạn có thể sử dụng mẹo dưới đây:

Ánh xạ tất cả các tên trong một đối tượng.

vendors = [
    {
      Name: 'Magenic',
      ID: 'ABC'
     },
    {
      Name: 'Microsoft',
      ID: 'DEF'
    }
];

var dirtyObj = {}
for(var count=0;count<vendors.length;count++){
   dirtyObj[vendors[count].Name] = true //or assign which gives you true.
}

Bây giờ bẩn này bạn có thể sử dụng nhiều lần mà không cần bất kỳ vòng lặp.

if(dirtyObj[vendor.Name]){
  console.log("Hey! I am available.");
}

1

Để so sánh một đối tượng với đối tượng khác, tôi kết hợp một vòng lặp for (được sử dụng để lặp qua các đối tượng) và một số (). Bạn không phải lo lắng về việc một mảng vượt ra ngoài giới hạn, vì vậy sẽ tiết kiệm được một số mã. Tài liệu về .some có thể được tìm thấy ở đây

var productList = [{id: 'text3'}, {id: 'text2'}, {id: 'text4', product: 'Shampoo'}]; // Example of selected products
var theDatabaseList = [{id: 'text1'}, {id: 'text2'},{id: 'text3'},{id:'text4', product: 'shampoo'}];    
var  objectsFound = [];

for(let objectNumber in productList){
    var currentId = productList[objectNumber].id;   
    if (theDatabaseList.some(obj => obj.id === currentId)) {
        // Do what you need to do with the matching value here
        objectsFound.push(currentId);
    }
}
console.log(objectsFound);

Một cách khác tôi so sánh một đối tượng này với một đối tượng khác là sử dụng vòng lặp lồng nhau với chiều dài Object.keys (). Để lấy số lượng đối tượng trong mảng. Mã dưới đây:

var productList = [{id: 'text3'}, {id: 'text2'}, {id: 'text4', product: 'Shampoo'}]; // Example of selected products
var theDatabaseList = [{id: 'text1'}, {id: 'text2'},{id: 'text3'},{id:'text4', product: 'shampoo'}];    
var objectsFound = [];

for(var i = 0; i < Object.keys(productList).length; i++){
        for(var j = 0; j < Object.keys(theDatabaseList).length; j++){
        if(productList[i].id === theDatabaseList[j].id){
            objectsFound.push(productList[i].id);
        }       
    }
}
console.log(objectsFound);

Để trả lời chính xác câu hỏi của bạn, nếu chỉ tìm kiếm một giá trị trong một đối tượng, bạn có thể sử dụng một vòng lặp for.

var vendors = [
    {
      Name: 'Magenic',
      ID: 'ABC'
     },
    {
      Name: 'Microsoft',
      ID: 'DEF'
    } 
];

for(var ojectNumbers in vendors){
    if(vendors[ojectNumbers].Name === 'Magenic'){
        console.log('object contains Magenic');
    }
}

0

Ngoài ra, bạn có thể làm:

const find = (key, needle) => return !!~vendors.findIndex(v => (v[key] === needle));

1
bạn nên nói lý do tại sao anh ta có thể làm điều đó
Azzabi Haythem

0

var without2 = (arr, args) => arr.filter(v => v.id !== args.id); Thí dụ:

without2([{id:1},{id:1},{id:2}],{id:2})

Kết quả: without2 ([{id: 1}, {id: 1}, {id: 2}], {id: 2})


Tôi nghĩ bạn muốn nói Kết quả: [{id: 1}, {id: 1}]
Isaac Pak

0
const a = [{one:2},{two:2},{two:4}]
const b = a.filter(val => "two" in val).length;
if (b) {
   ...
}

3
Vui lòng và một số mô tả và đảm bảo ví dụ bạn cung cấp hoạt động .. (bộ lọc sẽ không thay đổi mảng ban đầu mà sao chép nó).
Moshe Simantov

-1

Cách tiếp cận của tôi để giải quyết vấn đề này là sử dụng ES6 và tạo một chức năng kiểm tra cho chúng tôi. Lợi ích của chức năng này là nó có thể được sử dụng lại thông qua dự án của bạn để kiểm tra bất kỳ mảng đối tượng nào được cung cấp keyvalueđể kiểm tra.

HÃY NÓI CHUYỆN, HÃY XEM MÃ

Mảng

const ceos = [
  {
    name: "Jeff Bezos",
    company: "Amazon"
  }, 
  {
    name: "Mark Zuckerberg",
    company: "Facebook"
  }, 
  {
    name: "Tim Cook",
    company: "Apple"
  }
];

Chức năng

const arrayIncludesInObj = (arr, key, valueToCheck) => {
  let found = false;

  arr.some(value => {
    if (value[key] === valueToCheck) {
      found = true;
      return true; // this will break the loop once found
    }
  });

  return found;
}

Gọi / Sử dụng

const found = arrayIncludesInObj(ceos, "name", "Tim Cook"); // true

const found = arrayIncludesInObj(ceos, "name", "Tim Bezos"); // false

-4

Tôi thà đi với regex.

Nếu mã của bạn như sau,

vendors = [
    {
      Name: 'Magenic',
      ID: 'ABC'
     },
    {
      Name: 'Microsoft',
      ID: 'DEF'
    }
];

Tôi muốn giới thiệu

/"Name":"Magenic"/.test(JSON.stringify(vendors))

23
Một số người, khi đối mặt với một vấn đề, nghĩ rằng "Tôi biết, tôi sẽ sử dụng các biểu thức thông thường." Bây giờ họ có hai vấn đề.
Craicerjack

Nộp cái này bên dưới, chỉ vì bạn có thể làm gì đó, không có nghĩa là bạn nên làm.
Liam
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.