array indexOf with objects? - javascript

I know we can match array values with indexOf in JavaScript. If it matches it wont return -1.
var test = [
1, 2, 3
]
// Returns 2
test.indexOf(3);
Is there a way to match objects? For example?
var test = [
{
name: 'Josh'
}
]
// Would ideally return 0, but of course it's -1.
test.indexOf({ name: 'Josh' });

Since the two objects are distinct (though perhaps equivalent), you can't use indexOf.
You can use findIndex with a callback, and handle the matching based on the properties you want. For instance, to match on all enumerable props:
var target = {name: 'Josh'};
var targetKeys = Object.keys(target);
var index = test.findIndex(function(entry) {
var keys = Object.keys(entry);
return keys.length == targetKeys.length && keys.every(function(key) {
return target.hasOwnProperty(key) && entry[key] === target[key];
});
});
Example:
var test = [
{
name: 'Josh'
}
];
var target = {name: 'Josh'};
var targetKeys = Object.keys(target);
var index = test.findIndex(function(entry) {
var keys = Object.keys(entry);
return keys.length == targetKeys.length && keys.every(function(key) {
return target.hasOwnProperty(key) && entry[key] === target[key];
});
});
console.log(index);
Note that findIndex was added in ES2015, but is fully polyfillable.

Nope, you can't and the explanation is simple. Despite you use the same object literal, two different objects are created. So test would have another reference for the mentioned object if you compare it with the reference you are looking for in indexOf.

This is kind of custom indexOf function. The code just iterates through the items in the object's array and finds the name property of each and then tests for the name you're looking for. Testing for 'Josh' returns 0 and testing for 'Kate' returns 1. Testing for 'Jim' returns -1.
var test = [
{
name: 'Josh'
},
{
name: 'Kate'
}
]
myIndexOf('Kate')
function myIndexOf(name) {
testName = name;
for (var i = 0; i < test.length; i++) {
if(test[i].hasOwnProperty('name')) {
if(test[i].name === testName) {
console.log('name: ' + test[i].name + ' index: ' + i);
return i;
}
}
}
return -1;
}

You can loop on array and then look for what you want
var test = [{ name: 'Josh' }]
const Myname = test.map((item) => { return item.name; }).indexOf("Josh")

Related

looping inside an array of object?

my problem is to update an array , containing objects , and each object contains array , i want to update the global array , with values refering to array inside objects , this logic !
generalArray = [{name:String, features:String[]}]
// Try edit message
let array1 = [{ name: "num", features: ['id'] },
{ name: "cat", features: ['gender'] }];
ob = {name:'num2', features:['id']};
function updateArr(arr,ob){
const index = arr.findIndex(x =>
ob.features.toString() === x.features.toString()
);
if (index === -1) {
arr.push(ob);
} else {
arr[index] = ob;
}
}
console.log(array1);
updateArr(array1,ob);
console.log(array1);
this is working perfectly when features array of any object contains one string , but if it contains more than one string , exm features=['id','gender' ] it can't do anything ! help please and thanks
Here I made a solution to your problem
var array1 = [{ name: "num", features: ['id', 'gender']},
{ name: "cat", features: ['gender']}];
ob = {name:'num2', features:['id']};
function updateArr(arr, ob){
for(var i = 0;i < arr.length; i++) {
if(ob.features.join("") === arr[i].features.join("")) {
arr[i] = ob;
return;
}
}
arr.push(ob);
}
updateArr(array1, ob);
console.log(array1);
Option 1: When order of the elements in the features array does not matter.
You can simply change the compare operator in your below line of code
ob.features.toString() === x.features.toString()
to
JSON.stringify(ob.features.sort()) === JSON.stringify(x.features.sort())
Option 2: If the order of the elements in the features array matter. Then you can simply remove .sort().
Note: If you do not want to use stringify, then you can use the array compare function as mentioned in answer here - https://stackoverflow.com/a/16436975/989139.
let array1 = [{ name: "num", features: ['id'] },
{ name: "cat", features: ['gender'] }];
ob = {name:'num2', features:['id']};
function updateArr(arr,ob){
const index = arr.findIndex(x =>
ob.features.includes(x.features)
// ob.features.toString() === x.features.toString()
);
debugger
if (index === -1) {
arr.push(ob);
} else {
arr[index] = ob;
}
}
console.log(array1);
updateArr(array1,ob);
console.log(array1);

how to make array of object using an array?

I have one array
var ar=['aa','cc','po']
I want to push objects in new array after checking the value of given array .In other words
I have these given conditions
var ar=['aa','cc','po']
var arr =[{name:"po"},{name:'aa'},{name:'cc'}];
Expected Output in new Array
[{name:'aa'},{name:'cc'},{name:"po"}]
As "aa" in in 0 index then I added object whose name property aa.
I try like this .but I used two for look .is there any simple way to do this
FIDDLE
var newArr=[];
for(var i=0;i<ar.length ;i++){
var text =ar[i];
for(var j=0;j<arr.length ;j++){
var obj =arr[j];
console.log(obj.name);
/*if(obj.name===text){
newArr.push(obj);
}*/
}
}
console.log(newArr);
This is a proposal in two part, first build an object with the reference to the items of arr and the create a new array with the given items of ar.
var ar = ['aa', 'cc', 'po'],
arr = [{ name: "po" }, { name: 'aa' }, { name: 'cc' }],
object = Object.create(null),
result = [];
arr.forEach(function (a) {
object[a.name] = a;
});
ar.forEach(function (a) {
object[a] && result.push(object[a]);
});
document.write('<pre>' + JSON.stringify(result, 0, 4) + '</pre>');
Using forEach iterator and generate object reference based on name and then generate result array using map()
var ar = ['aa', 'cc', 'po']
var arr = [{
name: "po"
}, {
name: 'aa'
}, {
name: 'cc'
}];
var ref = {};
// generating object reference with name property
arr.forEach(function(v) {
ref[v.name] = v;
});
// generating result array
// or you can use forEach as #NinaScholz answer
var res = ar.map(function(v) {
return ref[v];
}).filter(function(v) { // use filter to avoid null values , in case of missing elements
return v != null;
});
document.write('<pre>' + JSON.stringify(res, null, 3) + '</pre>');
Try this:
function convert(source) {
var
obj = [],
i;
for (i = 0; i < source.length; ++i) {
obj.push({name: source[i]});
}
return obj;
}
convert(['aa', 'bb', 'cc']); // [{name:'aa'},{name:'bb'},{name:'cc'}]
This would work if you want to assign values from array in sequence:
var ar=['aa','cc','po']
var arr =[{name:"po"},{name:'aa'},{name:'cc'}];
arr.map(function(obj,key){
obj.name = ar[key];
});
console.log(arr);
Do like this
var ar = ['aa', 'cc', 'po']
var arr = [{ name: "po"}, { name: 'aa'}, { name: 'cc'}];
$.each(ar, function(i, v) {
arr[i].name = v;
});
console.log(arr)
Fiddle
var array=['a','b','c'];
var arrayObj=[];
for(var i=0;i<array.length;i++){
var obj={};
obj.name=array[i];
arrayObj.push(obj);
}
console.log(JSON.stringify(arrayObj));
Output:
[{"name":"a"},{"name":"b"},{"name":"c"}]
I guess this is one very functional way of doing this job with no more than an assignment line. However Anoop Joshi's answer is more elegant provided that the ar array is shorter than equal to in length to the arr array.
var arr = ['aa','cc','po'],
ar = [{name:"po"},{name:'aa'},{name:'cc'}],
res = arr.map(e => ar[ar.findIndex(f => f.name == e)]);
document.write("<pre>" + JSON.stringify(res) + "</pre>");

indexOf() when array-elements are objects (javascript)

For instance, a variable named arrayElements of type array contains:
[{id:1, value:5},{id:2, value:6},{id:3, value:7},{id:4, value:8}].
How do I get the position of the array element with id === 3(3rd element) in the arrayElements variable besides using loop?
thanks.
You have to loop at one point. But you can abstract it to look like you're not looping
function indexOfCallback(arr, callback, startIndex) {
if (typeof startIndex == 'undefined') {
startIndex = 0;
}
for(var i=startIndex; i < arr.length; i ++) {
if (callback(arr[i])) {
return i;
}
}
return -1;
}
var array = [{id:1, value:5},{id:2, value:6},{id:3, value:7},{id:4, value:8}];
// Search on id === 3
console.log(indexOfCallback(array, function(obj){
return obj.id === 3;
}));
// Search on value === 6
console.log(indexOfCallback(array, function(obj){
return obj.value === 6;
}));
As mentioned by Anthony, this is proposed for ECMAScript 6. Here's the more complete polyfill https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/findIndex
if (!Array.prototype.findIndex) {
Array.prototype.findIndex = 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++) {
value = list[i];
if (predicate.call(thisArg, value, i, list)) {
return i;
}
}
return -1;
};
}
console.log(array.findIndex(function(obj){
return obj.id === 3;
}));
arrayElements.map(o => o.id).indexOf(3);
Notes:
Possibly slower than a loop because transforms whole array prior to
search. But with high-level languages like Javascript, you never
know.
Infinitely more readable than a loop.
IE compatible (unlike findIndex as of 2017).
In an array like this, you cant access elements by id. So using a loop is the best solution you have. However, depending on your use case you could also consider using an object instead of an array for direct access.
var container = { 1: {id:1, value:5}, 2: {id:2, value:6}, 3: {id:3, value:7} }
const arrayElements = [
{ id: 1, value: 5 },
{ id: 2, value: 6 },
{ id: 3, value: 7 },
{ id: 4, value: 8 }
]
console.log(arrayElements.findIndex((item) => item.id === 3))
You can use an array filter but I think that you will get a better solution using a loop.
var array = [{id:1, value:5},{id:2, value:6},{id:3, value:7},{id:4, value:8}];
var result = array.filter(condition);
function condition(value, index){
if (value.id === 3) return index;
}
console.log(result);
I wrote a function for you that you can use get the job done, but it uses a loop:
var yourObjArray = [{id:1, value:5},{id:2, value:6},{id:3, value:7},{id:4, value:8}];
function objArrayIndex(objArray){
for(var i = 0; i < objArray.length; i++){
if(objArray[i]['id'] == 3){
return i;
}
}
return -1;
}
console.log(objArrayIndex(yourObjArray));

Check if an object with index is in array

$.each(constructions, function(i,v) {
if ($.inArray(v.name, map[ii].buildings) == -1) {//stuff}
};
Where constructions is an array of objects, each with a unique name. map[ii].buildings is an array containing some of these objects. I want to iterate each object in constructions, checking if its name parameter appears in the objects of map[ii].buildings.
The above code works if the each element in the map[ii].buildings array is just the text string of the object name, but not if the element is the entire object.. close, but no dice >.<
Try using $.grep() instead of $.inArray(); you can specify a function to do the filtering for you.
Instead of checking for -1, you check whether the array that $.grep() returns has length == 0
Simple example: (would be easier if you posted the code / example of what "constructions" objects look like)
var constructions = [{
Name: "Mess hall",
SqFt: 5000
}, {
Name: "Infirmary",
SqFt: 2000
}, {
Name: "Bungalow",
SqFt: 2000
}, {
Name: "HQ",
SqFt: 2000
}];
var buildings = [{
Name: "Infirmary",
SqFt: 2000
}, {
Name: "HQ",
SqFt: 2000
}];
// found buildings will be list of items in "constructions" that is not in "buildings"
var foundBuildings = $.grep(constructions, function (constructionsItem) {
return $.grep(buildings, function (buildingsItem) {
return buildingsItem.Name === constructionsItem.Name
}).length == 0; // == 0 means "not in", and > 0 means "in"
});
// this just renders the results all pretty for ya
$.each(foundBuildings, function (idx, item) {
$("#output").append("<div>" + item.Name + "</div>");
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id='output'></div>
Example jsFiddle: http://jsfiddle.net/eLeuy9eg/3/
The non-jQuery way of doing this would be to use filter. Something like this:
// pass in an array and the key for which you want values
// it returns an array of those values
function getValues(arr, key) {
return arr.map(function (el) { return el[key]; });
}
function notFoundIn(arr, arr2) {
// grab the names of the buildings
var buildings = getValues(arr2, 'name');
// grab the names from the construction objects and filter
// those that are not in the building array
return getValues(arr, 'name').filter(function (el) {
return buildings.indexOf(el) === -1;
});
}
notFoundIn(constructions, buildings); // eg [ "one", "three" ]
DEMO
You could even add a new method to the array prototype. With this one you can use either simple arrays, or arrays of objects if you pass in a key. Note in this example I've replaced map and filter with loops that perform the same functions, but faster (see comments):
function getValues(arr, key) {
var out = [];
for (var i = 0, l = arr.length; i < l; i++) {
out.push(arr[i][key]);
}
return out;
}
if (!Array.prototype.notFoundIn) {
Array.prototype.notFoundIn = function (inThisArray, key) {
var thisArr = key ? getValues(this, key) : this;
var arrIn = key ? getValues(inThisArray, key) : inThisArray;
var out = [];
for (var i = 0, l = thisArr.length; i < l; i++) {
if (arrIn.indexOf(thisArr[i]) === -1) {
out.push(thisArr[i]);
}
}
return out;
}
}
constructions.notFoundIn(buildings, 'name');
[1, 2, 3].notFoundIn([2]); // [1, 3]
DEMO

How can I get the index of an object by its property in JavaScript?

For example, I have:
var Data = [
{ id_list: 1, name: 'Nick', token: '312312' },
{ id_list: 2, name: 'John', token: '123123' },
]
Then, I want to sort/reverse this object by name, for example. And then I want to get something like this:
var Data = [
{ id_list: 2, name: 'John', token: '123123' },
{ id_list: 1, name: 'Nick', token: '312312' },
]
And now I want to know the index of the object with property name='John' to get the value of the property token.
How do I solve the problem?
Since the sort part is already answered. I'm just going to propose another elegant way to get the indexOf of a property in your array
Your example is:
var Data = [
{id_list:1, name:'Nick', token:'312312'},
{id_list:2, name:'John', token:'123123'}
]
You can do:
var index = Data.map(function(e) { return e.name; }).indexOf('Nick');
var Data = [{
id_list: 1,
name: 'Nick',
token: '312312'
},
{
id_list: 2,
name: 'John',
token: '123123'
}
]
var index = Data.map(function(e) {
return e.name;
}).indexOf('Nick');
console.log(index)
Array.prototype.map is not available on Internet Explorer 7 or Internet Explorer 8. ES5 Compatibility
And here it is with ES6 and arrow syntax, which is even simpler:
const index = Data.map(e => e.name).indexOf('Nick');
If you're fine with using ES6, arrays now have the findIndex function. Which means you can do something like this:
const index = Data.findIndex(item => item.name === 'John');
As the other answers suggest, looping through the array is probably the best way. But I would put it in its own function, and make it a little more abstract:
function findWithAttr(array, attr, value) {
for(var i = 0; i < array.length; i += 1) {
if(array[i][attr] === value) {
return i;
}
}
return -1;
}
var Data = [
{id_list: 2, name: 'John', token: '123123'},
{id_list: 1, name: 'Nick', token: '312312'}
];
With this, not only can you find which one contains 'John', but you can find which contains the token '312312':
findWithAttr(Data, 'name', 'John'); // returns 0
findWithAttr(Data, 'token', '312312'); // returns 1
findWithAttr(Data, 'id_list', '10'); // returns -1
The function returns -1 when not found, so it follows the same construct as Array.prototype.indexOf().
If you're having issues with Internet Explorer, you could use the map() function which is supported from 9.0 onward:
var index = Data.map(item => item.name).indexOf("Nick");
var index = Data.findIndex(item => item.name == "John")
Which is a simplified version of:
var index = Data.findIndex(function(item){ return item.name == "John"})
From mozilla.org:
The findIndex() method returns the index of the first element in the array that satisfies the provided testing function. Otherwise -1 is returned.
Only way known to me is to loop through all array:
var index = -1;
for(var i=0; i<Data.length; i++)
if(Data[i].name === "John") {
index = i;
break;
}
Or case insensitive:
var index = -1;
for(var i=0; i<Data.length; i++)
if(Data[i].name.toLowerCase() === "john") {
index = i;
break;
}
On result variable index contain index of object or -1 if not found.
A prototypical way
(function(){
if (!Array.prototype.indexOfPropertyValue){
Array.prototype.indexOfPropertyValue = function(prop, value){
for (var index = 0; index < this.length; index++){
if (this[index][prop]){
if (this[index][prop] == value){
return index;
}
}
}
return -1;
}
}
})();
// Usage:
var Data = [
{id_list:1, name:'Nick', token:'312312'}, {id_list:2, name:'John', token:'123123'}];
Data.indexOfPropertyValue('name', 'John'); // Returns 1 (index of array);
Data.indexOfPropertyValue('name', 'Invalid name') // Returns -1 (no result);
var indexOfArray = Data.indexOfPropertyValue('name', 'John');
Data[indexOfArray] // Returns the desired object.
you can use filter method
const filteredData = data.filter(e => e.name !== 'john');
Just go through your array and find the position:
var i = 0;
for(var item in Data) {
if(Data[item].name == 'John')
break;
i++;
}
alert(i);
let indexOf = -1;
let theProperty = "value"
let searchFor = "something";
theArray.every(function (element, index) {
if (element[theProperty] === searchFor) {
indexOf = index;
return false;
}
return true;
});
collection.findIndex(item => item.value === 'smth') !== -1
You can use Array.sort using a custom function as a parameter to define your sorting mechanism.
In your example, it would give:
var Data = [
{id_list:1, name:'Nick',token:'312312'},{id_list:2,name:'John',token:'123123'}
]
Data.sort(function(a, b){
return a.name < b.name ? -1 : a.name > b.name ? 1 : 0;
});
alert("First name is : " + Data[0].name); // alerts 'John'
alert("Second name is : " + Data[1].name); // alerts 'Nick'
The sort function must return either -1 if a should come before b, 1 if a should come after b and 0 if both are equal. It's up to you to define the right logic in your sorting function to sort the array.
Missed the last part of your question where you want to know the index. You would have to loop through the array to find that as others have said.
This might be useful:
function showProps(obj, objName) {
var result = "";
for (var i in obj)
result += objName + "." + i + " = " + obj[i] + "\n";
return result;
}
I copied this from Working with objects.
Use a small workaround:
Create a new array with names as indexes. After that all searches will use indexes. So, only one loop. After that you don't need to loop through all elements!
var Data = [
{id_list:1, name:'Nick',token:'312312'},{id_list:2,name:'John',token:'123123'}
]
var searchArr = []
Data.forEach(function(one){
searchArr[one.name]=one;
})
console.log(searchArr['Nick'])
http://jsbin.com/xibala/1/edit
Live example.
I extended Chris Pickett's answer, because in my case I needed to search deeper than one attribute level:
function findWithAttr(array, attr, value) {
if (attr.indexOf('.') >= 0) {
var split = attr.split('.');
var attr1 = split[0];
var attr2 = split[1];
for(var i = 0; i < array.length; i += 1) {
if(array[i][attr1][attr2] === value) {
return i;
}
}
} else {
for(var i = 0; i < array.length; i += 1) {
if(array[i][attr] === value) {
return i;
}
}
};
};
You can pass 'attr1.attr2' into the function.
Use this:
Data.indexOf(_.find(Data, function(element) {
return element.name === 'John';
}));
It is assuming you are using Lodash or Underscore.js.
var fields = {
teste:
{
Acess:
{
Edit: true,
View: false
}
},
teste1:
{
Acess:
{
Edit: false,
View: false
}
}
};
console.log(find(fields,'teste'));
function find(fields,field) {
for(key in fields) {
if(key == field) {
return true;
}
}
return false;
}
If you have one Object with multiple objects inside, if you want know if some object are include on Master object, just use find(MasterObject, 'Object to Search'). This function will return the response if it exists or not (TRUE or FALSE). I hope to help with this - can see the example on JSFiddle.
If you want to get the value of the property token then you can also try this:
let data=[
{ id_list: 1, name: 'Nick', token: '312312' },
{ id_list: 2, name: 'John', token: '123123' },
]
let resultingToken = data[_.findKey(data,['name','John'])].token
where _.findKey is a Lodash function.
You can use findIndex in Lodash library.
Example:
var users = [
{ 'user': 'barney', 'active': false },
{ 'user': 'fred', 'active': false },
{ 'user': 'pebbles', 'active': true }
];
_.findIndex(users, function(o) { return o.user == 'barney'; });
// => 0
// The `_.matches` iteratee shorthand.
_.findIndex(users, { 'user': 'fred', 'active': false });
// => 1
// The `_.matchesProperty` iteratee shorthand.
_.findIndex(users, ['active', false]);
// => 0
// The `_.property` iteratee shorthand.
_.findIndex(users, 'active');
// => 2
Alternatively to German Attanasio Ruiz's answer, you can eliminate the second loop by using Array.reduce() instead of Array.map();
var Data = [
{ name: 'hypno7oad' }
]
var indexOfTarget = Data.reduce(function (indexOfTarget, element, currentIndex) {
return (element.name === 'hypno7oad') ? currentIndex : indexOfTarget;
}, -1);
Maybe the Object.keys, Object.entries, and Object.values methods might help.
Using Underscore.js:
var index = _.indexOf(_.pluck(item , 'name'), 'Nick');

Categories