indexOf method for array of objects in Javascript - javascript

I have array of objets like:
var MyArray = [] ,
Person = {},
[
{
name: 'John',
surname: 'Smith',
age: '22'
},
{
name: 'Jesica',
surname: 'Garou',
age: '31'
},
{
name: 'Max',
surname: 'Jolie',
age: '50'
}
]
I want to check , if my data has name 'John' that don't add new person , if not , then add new person with name 'John' and etc.
Thanks in advance .

You could deal with it using Array#find. I assume that you want to mutate your original array.
let arr = [{
name: 'Jesica',
surname: 'Garou',
age: '31'
},
{
name: 'Max',
surname: 'Jolie',
age: '50'
}
];
const obj = {
name: 'John',
surname: 'Smith',
age: '22'
};
const ensure = ({ name, ...z }) => {
if (!arr.find(v => v.name === name)) {
arr.push({ name, ...z });
}
}
ensure(obj);
console.log(arr);

You can use map but you have to know that map iterates through all elements in the array, whereas findIndex returns the first element index that equals the condition and stops the loop.
var MyArray = [
{
name: 'John',
surname: 'Smith',
age: '22'
},
{
name: 'Jesica',
surname: 'Garou',
age: '31'
},
{
name: 'Max',
surname: 'Jolie',
age: '50'
}
];
if(MyArray.findIndex(index => index.name === "John") > -1)
console.log("Found!");
else
console.log("Not found!");

To check if a name already exists in an array, you can make use of array.some function. It will check if name provided already exits or not.
If not then you can write the code to push the object in the array.
I have used the sample names John and Anne. For John, the function isAlreadyPresent returns true. For Anne, it returns false.
let arr = [
{
name: 'John',
surname: 'Smith',
age: '22'
},
{
name: 'Jesica',
surname: 'Garou',
age: '31'
},
{
name: 'Max',
surname: 'Jolie',
age: '50'
}
];
function isAlreadyPresent(name) {
return arr.some(a => a.name === name );
}
console.log('John already exists?',isAlreadyPresent('John'));
console.log('Anne already exists?',isAlreadyPresent('Anne'));

Maybe a name Map could be useful:
var byNam e =new Map(myArray.map(el=>[el.name,el]));
So you can easily do:
if (byName.has("John")){
alert("already exists");
} else {
var obj = { name: "John" };
Map.set(obj.name,obj);
myArray.push(obj);
}
The upper can be achieved with a Set also, but you may also want to do this:
byName.get("John").age=15;

You'll need to loop through all of the objects and check each of their name values. At worst runs in O(n) time.
For example, to check if "John" is a name in the array:
var inArray = false; // Have we found the name in the array yet?
for (var i = 0; i < MyArray.length; i++) { // Loop through the array of objects
if (MyArray[i].name=="John") { // If the name field is equal to "John"
inArray = true; // Name is in the array
break; // Exit the loop
}
}

var searchTerm = "John",
index = -1;
for(var i = 0, len = MyArray.length; i < len; i++) {
if (MyArray[i].name === searchTerm) {
alert("matched string");
index = i;
break;
}
}

You can make a search function like this that:
const index = (array, name) => {
// Search for the string "name" in your array
for (let i in array){
// Look at every element in the array, if an element has the
// corresponding name, return its index
if (array[i].name === name) return i;
}
return -1;
// If you found nothing, return -1
}
let position = index(myArray, "John");

Traditionally we use a constructor to build many similar objects. However, how that is OOP and is out of the scope of what you are asking.
Here we can use a for... in loop to iterate though MyArray, and check that each object does not include the name John.
function addJohn () {
for (let iterator in MyArray) { // You can also use for... of, but it will break in Node.
if (MyArray[iterator].name == "John") {return}; //You can also replace the string with a variable name to check that all objects do not have the variable in them.
else continue;
}
// you can now put in your new object here.
}

Related

Can't access object's properties by argument of a function

Why array[i].key (where key === "surname") within the function doesn't work,
meanwhile array[i].surname works perfectly?
let objects = [
{ name: 'Jack', surname: 'Jackson' },
{ name: 'Ivar', surname: 'Bjornsson' },
{ name: 'John', surname: 'Mickelson' }
];
function sort (array, key) {
for (let i = 0; i < array.length; i++) {
console.log(array[i].key)// Somehow the "key", which is equal to "surname" doesn't work;
// here will be undefined;
console.log(array[i].surname)//But here writing 'surname' directly works fine;
// the correct answer will be there;
console.log(key)// However, key === surname
}
}
sort(objects, 'surname');
You have to access the property with square brackets:
let objects = [
{ name: 'Jack', surname: 'Jackson' },
{ name: 'Ivar', surname: 'Bjornsson' },
{ name: 'John', surname: 'Mickelson' }
];
function sort (array, key) {
for (let i = 0; i < array.length; i++) {
console.log(array[i][key])// Somehow the "key", which is equal to "surname" doesn't work;
// here will be undefined;
console.log(array[i].surname)//But here writing 'surname' directly works fine;
// the correct answer will be there;
console.log(key)// However, key === surname
}
}
sort(objects, 'surname');
This
array[i].key
is equivalent to
array[i]['key']

Having trouble finding value with for-in loop

I am attempting to loop through this array's objects elements and return 'gotcha, bill' when the 'for in' loop finds the value 'bill'. However, it only seems to return 'not him' four times. I've skimmed over it several times and I'm not sure what I am missing. This is my first time using a for in loop, so I could be misunderstanding how it works.
Any help would be appreciated!
var names = [{name: 'steven', age: 22}, {name: 'bill', age: 13}];
function findBill(array) {
for(let i = 0; i < array.length; i++) {
for(let key in array[i]) {
if(key === 'bill') {
return console.log('gotcha, bill');
} else {
console.log('not him');
}
}
}
}
findBill(names)
for..in iterates over an object's keys. Since bill is a value, not a key, the (key === 'bill') test will never evaluate to true.
If you wanted to iterate over the object's values instead, use Object.values, and since it sounds like you want to find the bill object, you can use .find:
var names = [{name: 'steven', age: 22}, {name: 'bill', age: 13}];
function findBill(array) {
return array.find((obj) => (
Object.values(obj).includes('bill')
))
};
console.log(findBill(names))
If you know in advance that the value will be in the name property, then just test that property, rather than using Object.values:
var names = [{name: 'steven', age: 22}, {name: 'bill', age: 13}];
function findBill(array) {
return array.find((obj) => (
obj.name === 'bill'
))
};
console.log(findBill(names))
Here. I changed your for loop to forEach but that is not the main thing that solves your problem. It is how you access the object's property. I use forEach because it will be easier (for me) to get the desired data from the object.
var names = [{name: 'steven', age: 22}, {name: 'bill', age: 13}];
function findBill(array) {
array.forEach(function(person){
if(person.name === 'bill') {
return console.log('gotcha, bill');
} else {
console.log('not him');
}
});
}
findBill(names)
And this is how it should be if you insist on using for loop.
var names = [{name: 'steven', age: 22}, {name: 'bill', age: 13}];
function findBill(array) {
for(let i = 0; i < array.length; i++) {
if(array[i].name === 'bill') {
return console.log('gotcha, bill');
} else {
console.log('not him');
}
}
}
findBill(names)
key is exactly that--the keys of each object, namely, name or age. You need to actually index into the array at the correct index, then access the value for the key you're inspecting in the loop with if (array[i][key] === 'bill').
Here's a working example:
var names = [{name: 'steven', age: 22}, {name: 'bill', age: 13}];
function findBill(array) {
for(let i = 0; i < array.length; i++) {
for(let key in array[i]) {
if(array[i][key] === 'bill') {
return console.log('gotcha, bill');
} else {
console.log('not him');
}
}
}
}
findBill(names);
However, the extra loop isn't necessary and causes logic errors because you might have some other key, say, buffalo that happens to have the value "bill" and you'll wind up with a false positive. You know the key, so you can simply search the array for any object with the matching value for that key:
var names = [{name: 'steven', age: 22}, {name: 'bill', age: 13}];
console.log(names.find(e => e.name === "bill"));
Lastly, I recommend avoiding console.log in functions, which is a side effect that limits reusability. console.log returns undefined after printing, so it's misleading to return this, even in simple or contrived examples.
You don't need two loops for this. In fact you can use the Array.find() method to find the object you need and do with it what you need:
const people = [{name: 'steven', age: 22}, {name: 'bill', age: 13}];
const findByName = (data, name) => data.find(cur => cur.name === name);
const Bill = findByName(people, 'bill');
if (Bill === null) { console.log(`could not find bill`); }
else { console.log(`bill is ${Bill.age} years old`); }

How can I return an object out of an array? [duplicate]

This question already has answers here:
Get JavaScript object from array of objects by value of property [duplicate]
(17 answers)
Closed 6 years ago.
I have an array of objects and I wanted to search through each object and check if the data matches a given value and I want to return the object out of the array and if it is not found then I have to return undefined.
This is what I have so far:
var data = [{
id: 1,
firstName: 'John',
lastName: 'Smith'
}, {
id: 2,
firstName: 'Jane',
lastName: 'Smith'
}, {
id: 3,
firstName: 'John',
lastName: 'Doe'
}];
var asf[] = data[0];
return asf;
I'm trying to return the object if the condition in if else statement matches but it gives me error in returning array object.
I am also trying to use _.findwhere(data, pid) which is method in module of underscore can I use it to return the object out of array?
You can use Array.prototype.find(), like this:
var data = [{
id: 1,
firstName: 'John',
lastName: 'Smith'
}, {
id: 2,
firstName: 'Jane',
lastName: 'Smith'
}, {
id: 3,
firstName: 'John',
lastName: 'Doe'
}];
data.find(x => {x.id === 1});
If you like to know more about arrays vist this link.
http://exploringjs.com/es6/ch_arrays.html
I'm not sure if you want to return the object or remove the object so I'll show you how to do both as both are very simple to do.
This is a tidied version of your data:
// this is your data
var data = [{
id: 1,
firstName: 'John',
lastName: 'Smith'
}, {
id: 2,
firstName: 'Jane',
lastName: 'Smith'
}, {
id: 3,
firstName: 'John',
lastName: 'Doe'
}];
This the loop you'll use to return the target object from the array:
// loop through the data array
for(var i = 0; i < data.length; i++) {
// check if the current item is "John Smith"
if(data[i].firstName == "John" && data[i].lastName == "Smith") {
return data[i];
}
// continue with the loop if the current item is not "John Smith"
continue;
}
This snippet does the exact same thing but without the continue:
// loop through the data array
for(var i = 0; i < data.length; i++) {
// check if the current item is "John Smith"
if(data[i].firstName == "John" && data[i].lastName == "Smith") {
return data[i];
}
}
This the loop you'll use to remove the target object from the array:
// loop through the data array
for(var i = 0; i < data.length; i++) {
// check if the current item is "John Smith"
if(data[i].firstName == "John" && data[i].lastName == "Smith") {
delete data[i];
// you can also use Array.prototype.splice() to remove an item from an array:
// data.splice(i, 1);
}
// continue with the loop if the current item is not "John Smith"
continue;
}
This snippet does the exact same thing but without the continue:
// loop through the data array
for(var i = 0; i < data.length; i++) {
// check if the current item is "John Smith"
if(data[i].firstName == "John" && data[i].lastName == "Smith") {
delete data[i];
// you can also use Array.prototype.splice() to remove an item from an array:
// data.splice(i, 1);
}
}
Use this snippet if you are using jQuery, instead of returning or deleting anything you can handle the object however you please inside the jQuery callback function.
In this case, I'll be using console.log(); as an example:
$.each(data, function(i, object) {
if(object.firstName == "John" && object.lastName == "Smith") {
console.log(object);
}
});
Good luck and all the best.
Vanilla JS:
var findWhere = function(key,val,array) {
var o;
array.some(function(object) { return object[key] == val && (o = object); });
return o;
};
var data = []; //your array
findWhere('id',1,data); //get the first object in the array where id = 1
EDIT
Here's a better one that actually takes a callback and can return just one element, or all matching elements:
var find = function(arr,cb,all) {
var o;
if(all) {
return arr.filter(cb);
}
arr.some(function(object) { return cb(object) && (o = object); });
return o;
};
var findAll = function(arr,cb) { return find(arr,cb,true); };
//return the first object in the data array where the id = 1
find(data,function(object) { return object.id == 1 });
//return all objects in the data array where name = 'John'
findAll(data,function(object) { return object.firstName = 'John'; });

How to find duplicate values in a JavaScript array of objects, and output only unique values?

I'm learning JS. Supposing I have the below array of objects:
var family = [
{
name: "Mike",
age: 10
},
{
name: "Matt"
age: 13
},
{
name: "Nancy",
age: 15
},
{
name: "Adam",
age: 22
},
{
name: "Jenny",
age: 85
},
{
name: "Nancy",
age: 2
},
{
name: "Carl",
age: 40
}
];
Notice that Nancy is showing up twice (changing only the age). Supposing I want to output only unique names. How do I output the above array of objects, without duplicates? ES6 answers more than welcome.
Related (couldn't find a good way for usage on objects):
Remove Duplicates from JavaScript Array
Easiest way to find duplicate values in a JavaScript array
EDIT Here's what I tried. It works well with strings but I can't figure how to make it work with objects:
family.reduce((a, b) => {
if (a.indexOf(b) < 0 ) {
a.push(b);
}
return a;
},[]);
You could use a Set in combination with Array#map and a spread operator ... in a single line.
Map returns an array with all names, which are going into the set initializer and then all values of the set are returned in an array.
var family = [{ name: "Mike", age: 10 }, { name: "Matt", age: 13 }, { name: "Nancy", age: 15 }, { name: "Adam", age: 22 }, { name: "Jenny", age: 85 }, { name: "Nancy", age: 2 }, { name: "Carl", age: 40 }],
unique = [...new Set(family.map(a => a.name))];
console.log(unique);
For filtering and return only unique names, you can use Array#filter with Set.
var family = [{ name: "Mike", age: 10 }, { name: "Matt", age: 13 }, { name: "Nancy", age: 15 }, { name: "Adam", age: 22 }, { name: "Jenny", age: 85 }, { name: "Nancy", age: 2 }, { name: "Carl", age: 40 }],
unique = family.filter((set => f => !set.has(f.name) && set.add(f.name))(new Set));
console.log(unique);
The Solution
Store occurrences of name external to the loop in an object, and filter if there's been a previous occurrence.
https://jsfiddle.net/nputptbb/2/
var occurrences = {}
var filteredFamily = family.filter(function(x) {
if (occurrences[x.name]) {
return false;
}
occurrences[x.name] = true;
return true;
})
you can also generalize this solution to a function
function filterByProperty(array, propertyName) {
var occurrences = {}
return array.filter(function(x) {
var property = x[propertyName]
if (occurrences[property]) {
return false;
}
occurrences[property]] = true;
return true;
})
}
and use it like
var filteredFamily = filterByProperty(family, 'name')
Explanation
Don't compare objects using indexOf, which only uses the === operator between objects. The reason why your current answer doesn't work is because === in JS does not compare the objects deeply, but instead compares the references. What I mean by that you can see in the following code:
var a = { x: 1 }
var b = { x: 1 }
console.log(a === b) // false
console.log(a === a) // true
Equality will tell you if you found the same exact object, but not if you found an object with the same contents.
In this case, you can compare your object on name since it should be a unique key. So obj.name === obj.name instead of obj === obj. Moreover another problem with your code that affects its runtime and not its function is that you use an indexOf inside of your reduce. indexOf is O(n), which makes the complexity of your algorithm O(n^2). Thus, it's better to use an object, which has O(1) lookup.
This will work fine.
const result = [1, 2, 2, 3, 3, 3, 3].reduce((x, y) => x.includes(y) ? x : [...x, y], []);
console.log(result);
With the code you mentioned, you can try:
family.filter((item, index, array) => {
return array.map((mapItem) => mapItem['name']).indexOf(item['name']) === index
})
Or you can have a generic function to make it work for other array of objects as well:
function printUniqueResults (arrayOfObj, key) {
return arrayOfObj.filter((item, index, array) => {
return array.map((mapItem) => mapItem[key]).indexOf(item[key]) === index
})
}
and then just use printUniqueResults(family, 'name')
(FIDDLE)
I just thought of 2 simple ways for Lodash users
Given this array:
let family = [
{
name: "Mike",
age: 10
},
{
name: "Matt",
age: 13
},
{
name: "Nancy",
age: 15
},
{
name: "Adam",
age: 22
},
{
name: "Jenny",
age: 85
},
{
name: "Nancy",
age: 2
},
{
name: "Carl",
age: 40
}
]
1. Find duplicates:
let duplicatesArr = _.difference(family, _.uniqBy(family, 'name'), 'name')
// duplicatesArr:
// [{
// name: "Nancy",
// age: 2
// }]
2 Find if there are duplicates, for validation purpose:
let uniqArr = _.uniqBy(family, 'name')
if (uniqArr.length === family.length) {
// No duplicates
}
if (uniqArr.length !== family.length) {
// Has duplicates
}
Since most of the answers won't have a good performance, i thought i share my take on this:
const arrayWithDuplicateData = [{ id: 5, name: 'Facebook'}, { id: 3, name: 'Twitter' }, { id: 5, name: 'Facebook' }];
const uniqueObj = {};
arrayWithDuplicateData.forEach(i => {
uniqueObj[i.id] = i;
});
const arrayWithoutDuplicates = Object.values(uniqueObj);
We're leveraging the fact that keys are unique within objects. That means the last duplication item inside the first array, will win over its predecessors. If we'd want to change that, we could flip the array before iterating over it.
Also we're not bound to use only one property of our object for identifying duplications.
const arrayWithDuplicateData = [{ id: 5, name: 'Facebook'}, { id: 3, name: 'Twitter' }, { id: 5, name: 'Facebook' }];
const uniqueObj = {};
arrayWithDuplicateData.forEach(item => {
uniqueObj[`${item.id}_${item.name}`] = item;
});
const arrayWithoutDuplicates = Object.values(uniqueObj);
Or we could simply add a check, if the uniqueObj already holds a key and if yes, not overwrite it.
Overall this way is not very costly in terms of performance and served me well so far.
I would probably set up some kind of object. Since you've said ECMAScript 6, you have access to Set, but since you want to compare values on your objects, it will take a little more work than that.
An example might look something like this (removed namespace pattern for clarity):
var setOfValues = new Set();
var items = [];
function add(item, valueGetter) {
var value = valueGetter(item);
if (setOfValues.has(value))
return;
setOfValues.add(value);
items.push(item);
}
function addMany(items, valueGetter) {
items.forEach(item => add(item, valueGetter));
}
Use it like this:
var family = [
...
];
addMany(family, item => item.name);
// items will now contain the unique items
Explanation: you need to pull a value from each object as it's added and decide if it has already been added yet, based on the value you get. It requires a value getter, which is a function that given an item, returns a value (item => item.name). Then, you only add items whose values haven't already been seen.
A class implementation:
// Prevents duplicate objects from being added
class ObjectSet {
constructor(key) {
this.key = key;
this.items = [];
this.set = new Set();
}
add(item) {
if (this.set.has(item[this.key])) return;
this.set.add(item[this.key]);
this.items.push(item);
}
addMany(items) {
items.forEach(item => this.add(item));
}
}
var mySet = new ObjectSet('name');
mySet.addMany(family);
console.log(mySet.items);

Empty an array when function triggered

var names = {};
// PUTTING DATA TO tmpChatters output example is.
[ { name: 'aaa', age: '', sex: 'man'},
{ name: 'bbb', age: '', sex: 'female'} ]
function deleteFunction(currentName) {
}
deleteFunction('aaa');
So deleteFunction must empty where names eqauls the name inside the object.
How do i need to do this ?
Try it as a forEach();
names.forEach(function(a, b){
if(curretNick === a.name){
names.splice(b, 1);
}
});
Just loop over it and slice the object out of the array:
for(var i = yourArray.length; i--;){
if(yourArray[i].name === currentName){
yourArray.splice(i,1);
break;
}
}
Should give you what you want. If there can be multiple names that match, just remove the break to loop over them all.

Categories

Resources