I had a JSON string / object in my application.
{"list": [
{"name":"my Name","id":12,"type":"car owner"},
{"name":"my Name2","id":13,"type":"car owner2"},
{"name":"my Name4","id":14,"type":"car owner3"},
{"name":"my Name4","id":15,"type":"car owner5"}
]}
I had a filter box in my application, and when I type a name into that box, we have to filter the object and display the result.
For example, if the user types "name" and hits search, then we have to search full names in the JSON object and return the array, just like a MySQL search ...
My question is to filter the json object with string and return the array....
You could just loop through the array and find the matches:
var results = [];
var searchField = "name";
var searchVal = "my Name";
for (var i=0 ; i < obj.list.length ; i++)
{
if (obj.list[i][searchField] == searchVal) {
results.push(obj.list[i]);
}
}
If your question is, is there some built-in thing that will do the search for you, then no, there isn't. You basically loop through the array using either String#indexOf or a regular expression to test the strings.
For the loop, you have at least three choices:
A boring old for loop.
On ES5-enabled environments (or with a shim), Array#filter.
Because you're using jQuery, jQuery.map.
Boring old for loop example:
function search(source, name) {
var results = [];
var index;
var entry;
name = name.toUpperCase();
for (index = 0; index < source.length; ++index) {
entry = source[index];
if (entry && entry.name && entry.name.toUpperCase().indexOf(name) !== -1) {
results.push(entry);
}
}
return results;
}
Where you'd call that with obj.list as source and the desired name fragment as name.
Or if there's any chance there are blank entries or entries without names, change the if to:
if (entry && entry.name && entry.name.toUpperCase().indexOf(name) !== -1) {
Array#filter example:
function search(source, name) {
var results;
name = name.toUpperCase();
results = source.filter(function(entry) {
return entry.name.toUpperCase().indexOf(name) !== -1;
});
return results;
}
And again, if any chance that there are blank entries (e.g., undefined, as opposed to missing; filter will skip missing entries), change the inner return to:
return entry && entry.name && entry.name.toUpperCase().indexOf(name) !== -1;
jQuery.map example (here I'm assuming jQuery = $ as is usually the case; change $ to jQuery if you're using noConflict):
function search(source, name) {
var results;
name = name.toUpperCase();
results = $.map(source, function(entry) {
var match = entry.name.toUpperCase().indexOf(name) !== -1;
return match ? entry : null;
});
return results;
}
(And again, add entry && entry.name && in there if necessary.)
You can simply save your data in a variable and use find(to get single object of records) or filter(to get single array of records) method of JavaScript.
For example :-
let data = {
"list": [
{"name":"my Name","id":12,"type":"car owner"},
{"name":"my Name2","id":13,"type":"car owner2"},
{"name":"my Name4","id":14,"type":"car owner3"},
{"name":"my Name4","id":15,"type":"car owner5"}
]}
and now use below command onkeyup or enter
to get single object
data.list.find( record => record.name === "my Name")
to get single array object
data.list.filter( record => record.name === "my Name")
Use PaulGuo's jSQL, a SQL like database using javascript. For example:
var db = new jSQL();
db.create('dbname', testListData).use('dbname');
var data = db.select('*').where(function(o) {
return o.name == 'Jacking';
}).listAll();
I adapted regex to work with JSON.
First, stringify the JSON object. Then, you need to store the starts and lengths of the matched substrings. For example:
"matched".search("ch") // yields 3
For a JSON string, this works exactly the same (unless you are searching explicitly for commas and curly brackets in which case I'd recommend some prior transform of your JSON object before performing regex (i.e. think :, {, }).
Next, you need to reconstruct the JSON object. The algorithm I authored does this by detecting JSON syntax by recursively going backwards from the match index. For instance, the pseudo code might look as follows:
find the next key preceding the match index, call this theKey
then find the number of all occurrences of this key preceding theKey, call this theNumber
using the number of occurrences of all keys with same name as theKey up to position of theKey, traverse the object until keys named theKey has been discovered theNumber times
return this object called parentChain
With this information, it is possible to use regex to filter a JSON object to return the key, the value, and the parent object chain.
You can see the library and code I authored at http://json.spiritway.co/
If you are doing this in more than one place in your application it would make sense to use a client-side JSON database because creating custom search functions that get called by array.filter() is messy and less maintainable than the alternative.
Check out ForerunnerDB which provides you with a very powerful client-side JSON database system and includes a very simple query language to help you do exactly what you are looking for:
// Create a new instance of ForerunnerDB and then ask for a database
var fdb = new ForerunnerDB(),
db = fdb.db('myTestDatabase'),
coll;
// Create our new collection (like a MySQL table) and change the default
// primary key from "_id" to "id"
coll = db.collection('myCollection', {primaryKey: 'id'});
// Insert our records into the collection
coll.insert([
{"name":"my Name","id":12,"type":"car owner"},
{"name":"my Name2","id":13,"type":"car owner2"},
{"name":"my Name4","id":14,"type":"car owner3"},
{"name":"my Name4","id":15,"type":"car owner5"}
]);
// Search the collection for the string "my nam" as a case insensitive
// regular expression - this search will match all records because every
// name field has the text "my Nam" in it
var searchResultArray = coll.find({
name: /my nam/i
});
console.log(searchResultArray);
/* Outputs
[
{"name":"my Name","id":12,"type":"car owner"},
{"name":"my Name2","id":13,"type":"car owner2"},
{"name":"my Name4","id":14,"type":"car owner3"},
{"name":"my Name4","id":15,"type":"car owner5"}
]
*/
Disclaimer: I am the developer of ForerunnerDB.
Here is an iterative solution using object-scan. The advantage is that you can easily do other processing in the filter function and specify the paths in a more readable format. There is a trade-off in introducing a dependency though, so it really depends on your use case.
// const objectScan = require('object-scan');
const search = (haystack, k, v) => objectScan([`list[*].${k}`], {
rtn: 'parent',
filterFn: ({ value }) => value === v
})(haystack);
const obj = { list: [ { name: 'my Name', id: 12, type: 'car owner' }, { name: 'my Name2', id: 13, type: 'car owner2' }, { name: 'my Name4', id: 14, type: 'car owner3' }, { name: 'my Name4', id: 15, type: 'car owner5' } ] };
console.log(search(obj, 'name', 'my Name'));
// => [ { name: 'my Name', id: 12, type: 'car owner' } ]
.as-console-wrapper {max-height: 100% !important; top: 0}
<script src="https://bundle.run/object-scan#13.8.0"></script>
Disclaimer: I'm the author of object-scan
You can filter json object using any value from any property using this library
Js-Search
You can try this:
function search(data,search) {
var obj = [], index=0;
for(var i=0; i<data.length; i++) {
for(key in data[i]){
if(data[i][key].toString().toLowerCase().indexOf(search.toLowerCase())!=-1) {
obj[index] = data[i];
index++;
break;
}
}
return obj;
}
console.log(search(obj.list,'my Name'));
Related
Am facing an issue with while filtering array of object using JavaScript filter. Can any one help me to solve this issue.
Here is the code below.
var searchString = "item1";
var data = [
{
checkInfo: {
checkId: "item1"
}
},
{
checkInfo: {
checkId: "item2"
}
}
];
Am trying to filter above data using the below method.
const output = searchString ? data.filter(list => list.checkInfo.checkId === searchString)[0] : data[0];
I want to output if matched i want return matched object. If not matched always want to return first array of object from data array. It's working fine for match case. When searchString word not matching the ternary else condition not executing and it's returning undefined. Can any one look into my code and give your suggestion.
You are currently checking if searchString is defined and making the choice based on that. If you want to check if something matched with the filter you need to run the filter first and then check. Since it looks like you are only searching for the first match, you could just use find()
The following will check both:
var searchString = "item14";
var data = [{
checkInfo: {
checkId: "item1"
}
},
{
checkInfo: {
checkId: "item2"
}
}
];
let match = data.find(list => list.checkInfo.checkId === searchString)
const output = (searchString && match) || data[0];
console.log(output)
The filter functions returns an empty array if nothing is found, which is a truth-y value, so the ternary condition never triggers the false condition.
Thus, the first entry in an empty array is undefined.
Using the filter we can do this way
var searchString = "item3";
var data = [
{
checkInfo: {
checkId: "item1"
}
},
{
checkInfo: {
checkId: "item2"
}
}
];
var temp = data.filter(item => (item.checkInfo.checkId === searchString));
temp = temp.length > 0 ? temp : data[0];
console.log(temp);
When you call the .find(callback) method on an array, you will get back the first item that matches the condition that you specify. If no items are found, you will get back undefined.
I have an array like
vendors = [{
Name: 'Magenic',
ID: 'ABC'
},
{
Name: 'Microsoft',
ID: 'DEF'
} // and so on...
];
How do I check this array to see if "Magenic" exists? I don't want to loop, unless I have to. I'm working with potentially a couple thousand records.
No need to reinvent the wheel loop, at least not explicitly (using arrow functions, modern browsers only):
if (vendors.filter(e => e.Name === 'Magenic').length > 0) {
/* vendors contains the element we're looking for */
}
or, better yet, use some as it allows the browser to stop as soon as one element is found that matches, so it's going to be faster:
if (vendors.some(e => e.Name === 'Magenic')) {
/* vendors contains the element we're looking for */
}
or the equivalent (in this case) find:
if (vendors.find(e => e.Name === 'Magenic')) {
/* same result as above, but a different function return type */
}
And you can even get the position of that element by using findIndex:
const i = vendors.findIndex(e => e.Name === 'Magenic');
if (i > -1) {
/* vendors contains the element we're looking for, at index "i" */
}
And if you need compatibility with lousy browsers then your best bet is:
if (vendors.filter(function(e) { return e.Name === 'Magenic'; }).length > 0) {
/* vendors contains the element we're looking for */
}
2018 edit: This answer is from 2011, before browsers had widely supported array filtering methods and arrow functions. Have a look at CAFxX's answer.
There is no "magic" way to check for something in an array without a loop. Even if you use some function, the function itself will use a loop. What you can do is break out of the loop as soon as you find what you're looking for to minimize computational time.
var found = false;
for(var i = 0; i < vendors.length; i++) {
if (vendors[i].Name == 'Magenic') {
found = true;
break;
}
}
No loop necessary. Three methods that come to mind:
Array.prototype.some()
This is the most exact answer for your question, i.e. "check if something exists", implying a bool result. This will be true if there are any 'Magenic' objects, false otherwise:
let hasMagenicVendor = vendors.some( vendor => vendor['Name'] === 'Magenic' )
Array.prototype.filter()
This will return an array of all 'Magenic' objects, even if there is only one (will return a one-element array):
let magenicVendors = vendors.filter( vendor => vendor['Name'] === 'Magenic' )
If you try to coerce this to a boolean, it will not work, as an empty array (no 'Magenic' objects) is still truthy. So just use magenicVendors.length in your conditional.
Array.prototype.find()
This will return the first 'Magenic' object (or undefined if there aren't any):
let magenicVendor = vendors.find( vendor => vendor['Name'] === 'Magenic' );
This coerces to a boolean okay (any object is truthy, undefined is falsy).
Note: I'm using vendor["Name"] instead of vendor.Name because of the weird casing of the property names.
Note 2: No reason to use loose equality (==) instead of strict equality (===) when checking the name.
The accepted answer still works but now we have an ECMAScript 6 native methods [Array.find][1] and [Array.some][2] to achieve the same effect.
Array.some
Use some If you only want to determine if an element exists i.e. you need a true/false determination.
Quoting MDN:
The some() method tests whether at least one element in the array passes the test implemented by the provided function. It returns true if, in the array, it finds an element for which the provided function returns true; otherwise it returns false. It doesn't modify the array.
Array.find
Use find if you want to get the matched object from array else returns undefined.
Quoting MDN:
The find() method returns the value of the first element in the provided array that satisfies the provided testing function. If no values satisfy the testing function, undefined is returned.
var arr = [
{
id: 21,
label: 'Banana',
},
{
id: 22,
label: 'Apple',
}
]
/* 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
}
/* note : doesExist is a boolean thats true or false depending on of whether the data was found or not */
var doesExist = arr.some(function(ele) {
return ele.id === 21;
});
See my jsfiddle link There is a polyfill for IE provided by mozilla
Here's the way I'd do it
const found = vendors.some(item => item.Name === 'Magenic');
array.some() method checks if there is at least one value in an array that matches criteria and returns a boolean.
From here on you can go with:
if (found) {
// do something
} else {
// do something else
}
Unless you want to restructure it like this:
vendors = {
Magenic: {
Name: 'Magenic',
ID: 'ABC'
},
Microsoft: {
Name: 'Microsoft',
ID: 'DEF'
} and so on...
};
to which you can do if(vendors.Magnetic)
You will have to loop
May be too late, but javascript array has two methods some and every method that returns a boolean and can help you achieve this.
I think some would be most appropriate for what you intend to achieve.
vendors.some( vendor => vendor['Name'] !== 'Magenic' )
Some validates that any of the objects in the array satisfies the given condition.
vendors.every( vendor => vendor['Name'] !== 'Magenic' )
Every validates that all the objects in the array satisfies the given condition.
As per ECMAScript 6 specification, you can use findIndex.
const magenicIndex = vendors.findIndex(vendor => vendor.Name === 'Magenic');
magenicIndex will hold either 0 (which is the index in the array) or -1 if it wasn't found.
As the OP has asked the question if the key exists or not.
A more elegant solution that will return boolean using ES6 reduce function can be
const magenicVendorExists = vendors.reduce((accumulator, vendor) => (accumulator||vendor.Name === "Magenic"), false);
Note: The initial parameter of reduce is a false and if the array has the key it will return true.
Hope it helps for better and cleaner code implementation
You cannot without looking into the object really.
You probably should change your structure a little, like
vendors = {
Magenic: 'ABC',
Microsoft: 'DEF'
};
Then you can just use it like a lookup-hash.
vendors['Microsoft']; // 'DEF'
vendors['Apple']; // undefined
const check = vendors.find((item)=>item.Name==='Magenic')
console.log(check)
Try this code.
If the item or element is present then the output will show you that element. If it is not present then the output will be 'undefined'.
Testing for array elements:
JS Offers array functions which allow you to achieve this relatively easily. They are the following:
Array.prototype.filter: Takes a callback function which is a test, the array is then iterated over with is callback and filtered according to this callback. A new filtered array is returned.
Array.prototype.some: Takes a callback function which is a test, the array is then iterated over with is callback and if any element passes the test, the boolean true is returned. Otherwise false is returned
The specifics are best explained via an example:
Example:
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');
}
Browser support:
These 2 function are ES6 function, not all browsers might support them. To overcome this you can use a polyfill. Here is the polyfill for Array.prototype.some (from 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;
};
}
Simplest method so far:
if (vendors.findIndex(item => item.Name == "Magenic") == -1) {
//not found item
} else {
//found item
}
My approach to solving this problem is to use ES6 and creating a function that does the check for us. The benefit of this function is that it can be reusable through out your project to check any array of objects given the key and the value to check.
ENOUGH TALK, LET'S SEE THE CODE
Array
const ceos = [
{
name: "Jeff Bezos",
company: "Amazon"
},
{
name: "Mark Zuckerberg",
company: "Facebook"
},
{
name: "Tim Cook",
company: "Apple"
}
];
Function
const arrayIncludesInObj = (arr, key, valueToCheck) => {
return arr.some(value => value[key] === valueToCheck);
}
Call/Usage
const found = arrayIncludesInObj(ceos, "name", "Tim Cook"); // true
const found = arrayIncludesInObj(ceos, "name", "Tim Bezos"); // false
2021 Solution*
Lodash .some (docs) is a clean solution, if you use the _matchesProperty (docs) shorthand:
_.some(VENDORS, ['Name', 'Magenic'])
Explanation
This will iterate through the VENDORS Array looking for an element Object with the Name key having a value of the String 'Magenic'. Once it finds this element, it returns true and stops iterating. If it doesn't find the element after looking through the entire Array, it returns false.
Code snippet
const VENDORS = [{ Name: 'Magenic', ID: 'ABC' }, { Name: 'Microsoft', ID: 'DEF' }];
console.log(_.some(VENDORS, ['Name', 'Magenic'])); // true
<script src="https://cdn.jsdelivr.net/npm/lodash#4.17.20/lodash.min.js"></script>
* Note that this uses the popular lodash library to achieve the simplest/shortest possible solution. I'm offering this as an alternative to the existing vanilla JS solutions, for those who are interested.
You have to loop, there is no way around it.
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];
}
}
}
Of course you could use a library like linq.js to make this more pleasing:
Enumerable.From(vendors).Where("$.Name == 'Magenic'").First();
(see jsFiddle for a demo)
I doubt that linq.js will be faster than a straight-forward loop, but it certainly is more flexible when things get a little more complicated.
Correct me if i'm wrong..
i could have used forEach method like this,
var found=false;
vendors.forEach(function(item){
if(item.name === "name"){
found=true;
}
});
Nowadays i'm used to it ,because of it simplicity and self explanatory word.
Thank you.
Functions map, filter, find, and similar are slower than the simple loop.
For me they also less readable than the simple loop and harder to debug. Using them looks like a kind of irrational ritual.
Better have something like this:
arrayHelper = {
arrayContainsObject: function (array, object, key){
for (let i = 0; i < array.length; i++){
if (object[key] === array[i][key]){
return true;
}
}
return false;
}
};
And use it like this with given OP example:
vendors = [{
Name: 'Magenic',
ID: 'ABC'
},
{
Name: 'Microsoft',
ID: 'DEF'
}
];
let abcObject = {ID: 'ABC', Name: 'Magenic'};
let isContainObject = arrayHelper.arrayContainsObject(vendors, abcObject, 'ID');
if you're using jquery you can take advantage of grep to create array with all matching objects:
var results = $.grep(vendors, function (e) {
return e.Name == "Magenic";
});
and then use the results array:
for (var i=0, l=results.length; i<l; i++) {
console.log(results[i].ID);
}
You can use lodash. If lodash library is too heavy for your application consider chunking out unnecessary function not used.
let newArray = filter(_this.props.ArrayOne, function(item) {
return find(_this.props.ArrayTwo, {"speciesId": item.speciesId});
});
This is just one way to do this. Another one can be:
var newArray= [];
_.filter(ArrayOne, function(item) {
return AllSpecies.forEach(function(cItem){
if (cItem.speciesId == item.speciesId){
newArray.push(item);
}
})
});
console.log(arr);
The above example can also be rewritten without using any libraries like:
var newArray= [];
ArrayOne.filter(function(item) {
return ArrayTwo.forEach(function(cItem){
if (cItem.speciesId == item.speciesId){
newArray.push(item);
}
})
});
console.log(arr);
Hope my answer helps.
Many answers here are good and pretty easy. But if your array of object is having a fixed set of value then you can use below trick:
Map all the name in a object.
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.
}
Now this dirtyObj you can use again and again without any loop.
if(dirtyObj[vendor.Name]){
console.log("Hey! I am available.");
}
To compare one object to another, I combine a for in loop (used to loop through objects) and some().
You do not have to worry about an array going out of bounds etc, so that saves some code. Documentation on .some can be found here
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);
An alternative way I compare one object to another is to use a nested for loop with Object.keys().length to get the amount of objects in the array. Code below:
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);
To answer your exact question, if are just searching for a value in an object, you can use a single for in loop.
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');
}
}
Alternatively you can do:
const find = (key, needle) => return !!~vendors.findIndex(v => (v[key] === needle));
var without2 = (arr, args) => arr.filter(v => v.id !== args.id);
Example:
without2([{id:1},{id:1},{id:2}],{id:2})
Result:
without2([{id:1},{id:1},{id:2}],{id:2})
You can try this its work for me.
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 } ]
const a = [{one:2},{two:2},{two:4}]
const b = a.filter(val => "two" in val).length;
if (b) {
...
}
I would rather go with regex.
If your code is as follows,
vendors = [
{
Name: 'Magenic',
ID: 'ABC'
},
{
Name: 'Microsoft',
ID: 'DEF'
}
];
I would recommend
/"Name":"Magenic"/.test(JSON.stringify(vendors))
I have an array:
[
{
key: 'some key',
value: 'some value'
}, {
...
}, ...
]
Is there any simple way to get a certain element of this array without iterating through it and comparing each actual key with desired one?
I currently have a function
var select = function(what, from) {
for (var i in from) {
if (from[i].key == what) {
return from[i];
}
}
return null;
};
I believe there's a better way to handle it.
The short answer is no. There are lots of options to make your code cleaner - like all of the above - but you are still going to have to iterate through them one by one.
You can do 2 things to make it better:
Convert to Map
If you are going to do the search more than once or twice, then convert it to a map of the keys, so at least each subsequent lookup is O(1) instead of O(n). A number of answers suggested that - I use it a lot in my own code - but here is a basic version (there is a shorthand un underscore/lodash):
var i, hash = {};
for (i = 0; i < arr.length; i++) {
hash[arr[i].key] = arr[i].value;
}
Then for all future lookups it is a simple:
var value = hash[key];
Search Algorithms
If it needs to stay as an array for whatever reason, and you have some knowledge about what that array's values will be like, you can use all sorts of search algorithms. Cycling through them one by one is good for an even distribution, but will still be O(n), which will, on average require cycling through half the array (n/2) each time.
But search algorithms are beyond this post...
You were close. This would be the fastest form in this particular case:
var select = function(key, expected, from) {
var i;
for (i = 0; i < from.length; i += 1) {
if (from[i][key] === expected) {
return from[i];
}
}
return null;
};
select('thing', 'foo', [{thing: 'foo'}]);
// => {thing: 'foo'}
But do you require maximum speed? Or would a more elegant, general-purpose solution suit you? If so, use a predicate:
var find = function (array, predicate) {
var i;
for (i = 0; i < array.length; i += 1) {
if (predicate(array[i])) {
return array[i];
}
}
return null;
};
// Find, in an array, an item which passes the following truth test.
find([{thing: 'foo'}], function (item) {
return item.thing === 'foo';
});
// => {thing: 'foo'}
If you don't like writing boilerplate utility code like this, I recommend leveraging a library like lodash. It has a find method already and it's faster and more powerful than anything we could come up with.
Unfortunately not, however, if you alter your structure to use properties it will be much faster. Any other approach will require iteration over the array and will therefore always be less efficient than the below.
var keyValueObj = {
someKey: 'someValue',
nextKey: 'nextValue'
}
// represents 'someValue'
keyValueObj['someKey']
If you're using modern browsers, this should do the magic:
function include(arr,obj) {
return (arr.indexOf(obj) != -1);
}
or in jquery
$.inArray(value, array)
In response to your comment, check this link, this will also address your problem in the comment.
If your keys are strings use them as object properties instead of an array of objects
If your keys are objects use Map()
You can refactor your array into a map, which is, by design, good for quick and effective lookup:
{
'some key': {
value: 'some value'
},
'some other key': {
value: 'some other value'
},
}
Then your select function would be as short as
var select = function(what, from) {
return from[what];
};
If you expect return value of the select() to still have the .key property (which is redundant, as the caller already knows it as what), it is easy to achieve by either keeping the key property in map elements, or auto-adding in in select() before returning.
If you need to run this function very often, I would recommend creating an index:
var yourItemList = [{...}],
select = (function (items) {
var i = 0,
l = items.length,
preparedItems = {};
for (; i < l; ++i) {
preparedItems[items[i].key] = items[i].value;
}
return function (key) {
return preparedItems[key];
};
}(yourItemList));
This way you only iterate once on the item list. After that every select('theKeyYouNeed') just uses the mapped "index".
You can filter array. It is build in Array method so you don't need to declare other helper functions
var arr = [
{
key: 'some key',
value: 'some value'
}, {
key: 'some key1',
value: 'some value'
}
];
arr = arr.filter(function(item) {
return item.key === 'some key'
});
Now arr has only first object (because its key equal to 'some key'). Object that you find is arr[0].
You can use find() instead of filter() when you need just one object. Note, that find() is part of ES6 and has no support in all major browsers
if I have an array like this:
var msg = [ {name: ["a1", "a2"], value: "this is A"},
{name: ["b1", "b2"], value: "this is B"},
...
]
The array contains global errors messages for client-side form validations. I have managed to pass in faulty inputs (e.g. "a1") and now am wondering how to get the corresponding message out of my ill-constructed array.
Question
What would be the best way to loop through this array? for example, if I have "a1" as parameter passed into my function, how do I extract "this is A" as corresponding message?
inArray doesn't really help, because I need the corresponding message and not the position of a1. I'm also not sure if this is the best way to store my error messages... ideas welcome!
Thanks for help!
Re-arrange your data structure:
var my_param = 'b1';
// This is an object, so we can have key/value pairs
var error_codes =
{
'a1': 0,
'a2': 0,
'b1': 1,
'b2': 1
};
// This is an array because we only need values
var error_messages =
[
'This is A',
'This is b'
];
alert(error_messages[error_codes[my_param]]);
This makes it really easy to set up new error codes and messages, and is extremely easy to understand. The only gotcha is error_codes[my_param] - it's an object, but we can't do error_codes.my_param because it'll look for the element called 'my_param', so using array notation, we can look up the object key.
The only other potential trap is making sure you don't have any trailing commas:
var error_codes = { 'a1': 1, }; // NO!
Also knows as the trailing comma of death!
This would be how I'd do it
var myMsg = findMsg('a1')
function findMsg(msgType){
msg.forEach(function(obj){
if(inArray(msgType, obj.name) !== -1){
return obj.value
}
})
}
function inArray(key, obj){
return obj.join().indexOf(key)
}
$.each is the jQuery way for taking action on each element of an array or each enumerable property of an object.
var value;
$.each(msg, function (i, el) {
if (el.name.indexOf(name) >= 0) {
value = el.value;
return false; // Stops iteration.
}
});
If name is "a1" then after running the above, value === "this is A".
Nice and simple:
var getMessage = function (name)
{
var msg = [ ... ];
for(var i = 0; i < msg.length; ++ i)
if (msg [i].name.indexOf (name) != -1)
return msg [i].value;
}
Returns either the corresponding message or undefined if the name wasn't found.
You may need a shim for indexOf depending on which browsers you want to support:
https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/indexOf
I have an array like
vendors = [{
Name: 'Magenic',
ID: 'ABC'
},
{
Name: 'Microsoft',
ID: 'DEF'
} // and so on...
];
How do I check this array to see if "Magenic" exists? I don't want to loop, unless I have to. I'm working with potentially a couple thousand records.
No need to reinvent the wheel loop, at least not explicitly (using arrow functions, modern browsers only):
if (vendors.filter(e => e.Name === 'Magenic').length > 0) {
/* vendors contains the element we're looking for */
}
or, better yet, use some as it allows the browser to stop as soon as one element is found that matches, so it's going to be faster:
if (vendors.some(e => e.Name === 'Magenic')) {
/* vendors contains the element we're looking for */
}
or the equivalent (in this case) find:
if (vendors.find(e => e.Name === 'Magenic')) {
/* same result as above, but a different function return type */
}
And you can even get the position of that element by using findIndex:
const i = vendors.findIndex(e => e.Name === 'Magenic');
if (i > -1) {
/* vendors contains the element we're looking for, at index "i" */
}
And if you need compatibility with lousy browsers then your best bet is:
if (vendors.filter(function(e) { return e.Name === 'Magenic'; }).length > 0) {
/* vendors contains the element we're looking for */
}
2018 edit: This answer is from 2011, before browsers had widely supported array filtering methods and arrow functions. Have a look at CAFxX's answer.
There is no "magic" way to check for something in an array without a loop. Even if you use some function, the function itself will use a loop. What you can do is break out of the loop as soon as you find what you're looking for to minimize computational time.
var found = false;
for(var i = 0; i < vendors.length; i++) {
if (vendors[i].Name == 'Magenic') {
found = true;
break;
}
}
No loop necessary. Three methods that come to mind:
Array.prototype.some()
This is the most exact answer for your question, i.e. "check if something exists", implying a bool result. This will be true if there are any 'Magenic' objects, false otherwise:
let hasMagenicVendor = vendors.some( vendor => vendor['Name'] === 'Magenic' )
Array.prototype.filter()
This will return an array of all 'Magenic' objects, even if there is only one (will return a one-element array):
let magenicVendors = vendors.filter( vendor => vendor['Name'] === 'Magenic' )
If you try to coerce this to a boolean, it will not work, as an empty array (no 'Magenic' objects) is still truthy. So just use magenicVendors.length in your conditional.
Array.prototype.find()
This will return the first 'Magenic' object (or undefined if there aren't any):
let magenicVendor = vendors.find( vendor => vendor['Name'] === 'Magenic' );
This coerces to a boolean okay (any object is truthy, undefined is falsy).
Note: I'm using vendor["Name"] instead of vendor.Name because of the weird casing of the property names.
Note 2: No reason to use loose equality (==) instead of strict equality (===) when checking the name.
The accepted answer still works but now we have an ECMAScript 6 native methods [Array.find][1] and [Array.some][2] to achieve the same effect.
Array.some
Use some If you only want to determine if an element exists i.e. you need a true/false determination.
Quoting MDN:
The some() method tests whether at least one element in the array passes the test implemented by the provided function. It returns true if, in the array, it finds an element for which the provided function returns true; otherwise it returns false. It doesn't modify the array.
Array.find
Use find if you want to get the matched object from array else returns undefined.
Quoting MDN:
The find() method returns the value of the first element in the provided array that satisfies the provided testing function. If no values satisfy the testing function, undefined is returned.
var arr = [
{
id: 21,
label: 'Banana',
},
{
id: 22,
label: 'Apple',
}
]
/* 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
}
/* note : doesExist is a boolean thats true or false depending on of whether the data was found or not */
var doesExist = arr.some(function(ele) {
return ele.id === 21;
});
See my jsfiddle link There is a polyfill for IE provided by mozilla
Here's the way I'd do it
const found = vendors.some(item => item.Name === 'Magenic');
array.some() method checks if there is at least one value in an array that matches criteria and returns a boolean.
From here on you can go with:
if (found) {
// do something
} else {
// do something else
}
Unless you want to restructure it like this:
vendors = {
Magenic: {
Name: 'Magenic',
ID: 'ABC'
},
Microsoft: {
Name: 'Microsoft',
ID: 'DEF'
} and so on...
};
to which you can do if(vendors.Magnetic)
You will have to loop
May be too late, but javascript array has two methods some and every method that returns a boolean and can help you achieve this.
I think some would be most appropriate for what you intend to achieve.
vendors.some( vendor => vendor['Name'] !== 'Magenic' )
Some validates that any of the objects in the array satisfies the given condition.
vendors.every( vendor => vendor['Name'] !== 'Magenic' )
Every validates that all the objects in the array satisfies the given condition.
As per ECMAScript 6 specification, you can use findIndex.
const magenicIndex = vendors.findIndex(vendor => vendor.Name === 'Magenic');
magenicIndex will hold either 0 (which is the index in the array) or -1 if it wasn't found.
As the OP has asked the question if the key exists or not.
A more elegant solution that will return boolean using ES6 reduce function can be
const magenicVendorExists = vendors.reduce((accumulator, vendor) => (accumulator||vendor.Name === "Magenic"), false);
Note: The initial parameter of reduce is a false and if the array has the key it will return true.
Hope it helps for better and cleaner code implementation
You cannot without looking into the object really.
You probably should change your structure a little, like
vendors = {
Magenic: 'ABC',
Microsoft: 'DEF'
};
Then you can just use it like a lookup-hash.
vendors['Microsoft']; // 'DEF'
vendors['Apple']; // undefined
const check = vendors.find((item)=>item.Name==='Magenic')
console.log(check)
Try this code.
If the item or element is present then the output will show you that element. If it is not present then the output will be 'undefined'.
Testing for array elements:
JS Offers array functions which allow you to achieve this relatively easily. They are the following:
Array.prototype.filter: Takes a callback function which is a test, the array is then iterated over with is callback and filtered according to this callback. A new filtered array is returned.
Array.prototype.some: Takes a callback function which is a test, the array is then iterated over with is callback and if any element passes the test, the boolean true is returned. Otherwise false is returned
The specifics are best explained via an example:
Example:
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');
}
Browser support:
These 2 function are ES6 function, not all browsers might support them. To overcome this you can use a polyfill. Here is the polyfill for Array.prototype.some (from 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;
};
}
Simplest method so far:
if (vendors.findIndex(item => item.Name == "Magenic") == -1) {
//not found item
} else {
//found item
}
My approach to solving this problem is to use ES6 and creating a function that does the check for us. The benefit of this function is that it can be reusable through out your project to check any array of objects given the key and the value to check.
ENOUGH TALK, LET'S SEE THE CODE
Array
const ceos = [
{
name: "Jeff Bezos",
company: "Amazon"
},
{
name: "Mark Zuckerberg",
company: "Facebook"
},
{
name: "Tim Cook",
company: "Apple"
}
];
Function
const arrayIncludesInObj = (arr, key, valueToCheck) => {
return arr.some(value => value[key] === valueToCheck);
}
Call/Usage
const found = arrayIncludesInObj(ceos, "name", "Tim Cook"); // true
const found = arrayIncludesInObj(ceos, "name", "Tim Bezos"); // false
2021 Solution*
Lodash .some (docs) is a clean solution, if you use the _matchesProperty (docs) shorthand:
_.some(VENDORS, ['Name', 'Magenic'])
Explanation
This will iterate through the VENDORS Array looking for an element Object with the Name key having a value of the String 'Magenic'. Once it finds this element, it returns true and stops iterating. If it doesn't find the element after looking through the entire Array, it returns false.
Code snippet
const VENDORS = [{ Name: 'Magenic', ID: 'ABC' }, { Name: 'Microsoft', ID: 'DEF' }];
console.log(_.some(VENDORS, ['Name', 'Magenic'])); // true
<script src="https://cdn.jsdelivr.net/npm/lodash#4.17.20/lodash.min.js"></script>
* Note that this uses the popular lodash library to achieve the simplest/shortest possible solution. I'm offering this as an alternative to the existing vanilla JS solutions, for those who are interested.
You have to loop, there is no way around it.
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];
}
}
}
Of course you could use a library like linq.js to make this more pleasing:
Enumerable.From(vendors).Where("$.Name == 'Magenic'").First();
(see jsFiddle for a demo)
I doubt that linq.js will be faster than a straight-forward loop, but it certainly is more flexible when things get a little more complicated.
Correct me if i'm wrong..
i could have used forEach method like this,
var found=false;
vendors.forEach(function(item){
if(item.name === "name"){
found=true;
}
});
Nowadays i'm used to it ,because of it simplicity and self explanatory word.
Thank you.
Functions map, filter, find, and similar are slower than the simple loop.
For me they also less readable than the simple loop and harder to debug. Using them looks like a kind of irrational ritual.
Better have something like this:
arrayHelper = {
arrayContainsObject: function (array, object, key){
for (let i = 0; i < array.length; i++){
if (object[key] === array[i][key]){
return true;
}
}
return false;
}
};
And use it like this with given OP example:
vendors = [{
Name: 'Magenic',
ID: 'ABC'
},
{
Name: 'Microsoft',
ID: 'DEF'
}
];
let abcObject = {ID: 'ABC', Name: 'Magenic'};
let isContainObject = arrayHelper.arrayContainsObject(vendors, abcObject, 'ID');
if you're using jquery you can take advantage of grep to create array with all matching objects:
var results = $.grep(vendors, function (e) {
return e.Name == "Magenic";
});
and then use the results array:
for (var i=0, l=results.length; i<l; i++) {
console.log(results[i].ID);
}
You can use lodash. If lodash library is too heavy for your application consider chunking out unnecessary function not used.
let newArray = filter(_this.props.ArrayOne, function(item) {
return find(_this.props.ArrayTwo, {"speciesId": item.speciesId});
});
This is just one way to do this. Another one can be:
var newArray= [];
_.filter(ArrayOne, function(item) {
return AllSpecies.forEach(function(cItem){
if (cItem.speciesId == item.speciesId){
newArray.push(item);
}
})
});
console.log(arr);
The above example can also be rewritten without using any libraries like:
var newArray= [];
ArrayOne.filter(function(item) {
return ArrayTwo.forEach(function(cItem){
if (cItem.speciesId == item.speciesId){
newArray.push(item);
}
})
});
console.log(arr);
Hope my answer helps.
Many answers here are good and pretty easy. But if your array of object is having a fixed set of value then you can use below trick:
Map all the name in a object.
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.
}
Now this dirtyObj you can use again and again without any loop.
if(dirtyObj[vendor.Name]){
console.log("Hey! I am available.");
}
To compare one object to another, I combine a for in loop (used to loop through objects) and some().
You do not have to worry about an array going out of bounds etc, so that saves some code. Documentation on .some can be found here
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);
An alternative way I compare one object to another is to use a nested for loop with Object.keys().length to get the amount of objects in the array. Code below:
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);
To answer your exact question, if are just searching for a value in an object, you can use a single for in loop.
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');
}
}
Alternatively you can do:
const find = (key, needle) => return !!~vendors.findIndex(v => (v[key] === needle));
var without2 = (arr, args) => arr.filter(v => v.id !== args.id);
Example:
without2([{id:1},{id:1},{id:2}],{id:2})
Result:
without2([{id:1},{id:1},{id:2}],{id:2})
You can try this its work for me.
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 } ]
const a = [{one:2},{two:2},{two:4}]
const b = a.filter(val => "two" in val).length;
if (b) {
...
}
I would rather go with regex.
If your code is as follows,
vendors = [
{
Name: 'Magenic',
ID: 'ABC'
},
{
Name: 'Microsoft',
ID: 'DEF'
}
];
I would recommend
/"Name":"Magenic"/.test(JSON.stringify(vendors))