I'm not sure if I phrased the question right. I'm fairly new to JavaScript, and I'd like to add multiple objects (?) to an array.
If I have this array:
let arr = [{
firstname: "John",
lastname: "Smith"
}];
How would I add, say
var firstname = "John";
var lastname = "Doe";
as
{ firstname: "John", lastname: "Doe" }
to the same array?
Items can be added to an array with the push method. Every array has this method build it, together with many other methods, and can be used to push a new value to the end of the array.
var arr = [
{
firstname: "John",
lastname: "Smith"
}
];
In the push method create an object with the keys and the values that you want to add.
var firstname = "John";
var lastname = "Doe";
arr.push({
firsName: firstName,
lastName: lastName
});
If the keys of the object are the same name as the variables then you can use the syntax below. This will give the object keys with the same name as the variable and set the value of the variable with it as the value of the key.
arr.push({ firstName, lastName });
Alternatively if you want to add an object to the beginning of the array, use the unshift method of the array.
arr.unshift({ firstName, lastName });
You can also do this with spread operator:
var arr = [{firstname: "John", lastname: "Smith"}];
arr= [...arr, {firstname: "Name1", lastname: "LName"}]
console.log(arr);
Take a look at push.
let arr = [{
firstname: "John",
lastname: "Smith"
}];
var firstname = "soham";
var lastname = "s";
arr.push({
firstname: firstname,
lastname: lastname
})
console.log(arr);
Related
I was wondering, if it's possible to ensure with Angular 12 / Typescript, that all objects within an array have the same properties, without declaring the properties explicitly (should be generic).
Here's an example of what I want to achieve:
// This should compile because all objects have the same properties
const correct = [
{firstname: 'Jack', lastname: 'Sanders'},
{firstname: 'Susanna', lastname: 'Marsaglia'},
{firstname: 'Walter', lastname: 'Walker'}
]
// This shouldn't compile because some object have different properties
const wrong = [
{firstname: 'Aline', lastname: 'Rose', phone: 'xxx-xxx-xx-xx'},
{firstname: 'Daniel', email: 'dan#gmail.com'},
{firstname: 'Louisa', email: 'louisa#icloud.com'}
]
I was able to create an Interface which only allows properties with type string, but I couldn't achieve the example above.
export interface Data {
[keys: string]: string
}
Update (Use-Case)
I need this check in a service which exports data. You should be able to pass an array of objects, which represent rows within a table.
For example:
const data = [
{firstname: 'Jack', lastname: 'Sanders'},
{firstname: 'Susanna', lastname: 'Marsaglia'},
]
this.exportService.export(data);
This code would generate a file with a table like this:
firstname
lastname
Jack
Sanders
Susanna
Marsaglia
The service should support any passed data, because it's used widely over our entire application. But to be sure that the service can export the data to a table, we need to ensure, that all passed objects have the same properties (e.g. columns).
function sameKeys(input) {
if (!input || input.length === 0) return;
const keys = new Set(Object.keys(input[0]));
return input.every((item) => Object.keys(item).every((key) => keys.has(key)));
}
If you want a compile time check, then doing a proper type definition makes sense have given in another answer. But that will only work if this data is hardcoded. if you are fetching it from backend it will not work as types are lost when the code is already build as javascript don't have types.
You can very well make your exportservice generic, ie something like this
class ExportService {
public export<T>(data: T[]) {
console.log(data);
}
}
Or you can also just use {[key:string]:string} as element type in you export service
class ExportService {
public export(data: {[key:string]:string}[]) {
console.log(data);
}
}
That doesn't hinder you from defining the type of your data correctly.
const data: { firstname: string, lastname: string}[] = [
{ firstname: "john", lastname: "foo"},
{ firstname: "jim", lastname: "bar"}
];
this.exportservice.export(data);
See also this fiddle
const data = [
{firstname: 'Jack', lastname: 'Sanders'},
{firstname: 'Susanna', lastname: 'Marsaglia'},
{firstname: 'Walter', lastname: 'Walker'}
]
const dataReference : Required<typeof data[number]>[] = data
You should achieve this by interface as below
interface IStructure {
firstname: string;
lastname: string;
}
const correct: Array<IStructure> = [
{firstname: 'Jack', lastname: 'Sanders'},
{firstname: 'Susanna', lastname: 'Marsaglia'},
{firstname: 'Walter', lastname: 'Walker'}
];
//wrong will throw error
i want to push items from one array to another but i'm getting only duplicates of last item. is there a way or better way of working this out? thanks
let nums = [{id:1, first_name: "sade", last_name: "Smith"}, {id:2, first_name: "Jon", last_name: "Doe"}];
let em = [];
let num2 = {id:null, name: ""}
nums.forEach(e => {
num2.id = e.id;
num2.name = `${e.first_name} ${e.last_name}`;
em.push(num2)
});
console.log(em)
As mentioned in the other answers, the issue is that you're changing an existing object every iteration instead of adding a new one.
I'd like to add that that you can also use reduce instead (I personally prefer the syntax and it's a bit shorter):
let nums = [{id:1, first_name: "sade", last_name: "Smith"}, {id:2, first_name: "Jon", last_name: "Doe"}];
let em = [];
let num2 = {id:null, name: ""}
em = nums.reduce((accumulator, item) => {
accumulator.push({
id: item.id,
name: `${item.first_name} ${item.last_name}`;
})
}, [])
More info about the reduce function can be found in the MDN docs.
Why does it work like this?
If you want to know more about why your solution didn't work, it's important to understand that in JS there's a difference between primitive values and objects.
By assigning a variable that contains an object to another variable, you are not assigning a new object, but only pointing to an existing one instead. This causes coupling between your objects, they are pointing to the same object, as can be demonstrated here:
var obj1 = {name: 'Sherlock Holmes', country: 'England'}
var obj2 = obj1;
obj2.country = 'US';
console.log(obj1.country) // US
console.log(obj2.country) // US
Because of this, when you want to assign an object to another variable you need to clone its content, but create a new object, therefor the variable will point to a new object and not to the old one.
There are many ways to do it, but few simple ones are:
Using the spread operator like this:
var obj1 = {name: 'Sherlock Holmes', country: 'England'}
var obj2 = { ...obj1 };
obj2.country = 'US';
console.log(obj1.country) // England
console.log(obj2.country) // US
Stringifying then parsing using JSON.stringify and JSON.parse
var obj1 = {name: 'Sherlock Holmes', country: 'England'}
var obj2 = JSON.parse(JSON.stringify(obj1));
obj2.country = 'US';
console.log(obj1.country) // US
console.log(obj2.country) // US
There are more ways, and differences between those ways, if your object has nested objects as well, the replications might not occur correctly, at this point it's best to use a function that does the cloning for you, like lodash's deepClone function.
Just clone num2 and push the cloned object.
let nums = [{id:1, first_name: "sade", last_name: "Smith"}, {id:2, first_name: "Jon", last_name: "Doe"}];
let em = [];
let num2 = {id:null, name: ""}
nums.forEach(e => {
const cloned = {...num2};
cloned.id = e.id;
cloned.name = `${e.first_name} ${e.last_name}`;
em.push(cloned)
});
console.log(em)
Your issue is that each time, you're adding the same object to the list, num2. num2 itself is not changing through each iteration of the loop.
This is an effect of you never reassigning num2 to anything new, and the fact that the list nums is keeping track of a list of pointers to objects, which means it doesn't actually copy num2 into itself each time, it just puts num2's pointer in.
You should either 1) clone it or just 2) make a new object then push it to the list.
let nums = [{id:1, first_name: "sade", last_name: "Smith"}, {id:2, first_name: "Jon", last_name: "Doe"}];
let em = [];
let num2 = {id:null, name: ""}
nums.forEach(e => {
let temp_num = {...num2};
temp_num.id = e.id;
temp_num.name = `${e.first_name} ${e.last_name}`;
em.push(temp_num)
});
console.log(em)
It is a fairly simple map() operation to create the new array from the original
let nums = [{id:1, first_name: "sade", last_name: "Smith"}, {id:2, first_name: "Jon", last_name: "Doe"}];
let res = nums.map(({id, first_name:fn, last_name:ln}) => ({id, name: `${fn} ${ln}`}));
console.log(res)
That's because you keep pushing the same object to the em array in each iteration in the forEach loop.
A simple approach would be to do this:
const nums = [{id:1, first_name: "sade", last_name: "Smith"}, {id:2, first_name: "Jon", last_name: "Doe"}];
const em = [];
nums.forEach(e => {
em.push({id: e.id, name: `${e.first_name} ${e.last_name}`});
});
console.log(em);
You could also use the map functionality on arrays:
const nums = [{id:1, first_name: "sade", last_name: "Smith"}, {id:2, first_name: "Jon", last_name: "Doe"}];
const em = nums.map((item) => ({id: item.id, name: `${item.first_name} ${item.last_name}`}));
console.log(em);
Essentially, we are creating a new object and pushing it into the em array in every iteration in the loop and in the process, removing the need for the num2 object that you've declared.
In addition, the em variable can be made const since using a const variable does not mean that the value it holds is immutable; we're simply pushing new elements into the array which is perfectly possible.
This question already has answers here:
Get all unique values in a JavaScript array (remove duplicates)
(91 answers)
Closed 4 years ago.
I need to loop through an array of objects and sum the total number of unique _id(s). Imagine a data structure that looks like this:
[
{ firstName: "John",
lastName: "Johnson",
_id: 23
},
{ firstName: "John",
lastName: "Johnson",
_id: 23
},
{ firstName: "Mary",
lastName: "Smith",
_id: 24
}
]
... for the above data set, my totalUniqueIDs should be 2.
If I were just looping through an array and getting the sum of "_id", I would do this:
let customersArray = docs.map(doc => doc._id);
let customersArrayLength = customersArray.length
console.log(customersArrayLength); // 3
This would of course give me 3 results.
How would I get just the sum of unique _id(s) in this situation? Do I first convert the array to a set, and then find the length or size?
Another option is using reduce to summarise the array into an object using the _id as the key. Use Object.values to convert back the object into an array.
var arr = [{"firstName":"John","lastName":"Johnson","_id":23},{"firstName":"John","lastName":"Johnson","_id":23},{"firstName":"Mary","lastName":"Smith","_id":24}]
var result = Object.values(arr.reduce((c, v) => Object.assign(c, {[v._id]:v}), {}));
console.log(result.length);
Another option is using new Set and size property
var arr = [{"firstName":"John","lastName":"Johnson","_id":23},{"firstName":"John","lastName":"Johnson","_id":23},{"firstName":"Mary","lastName":"Smith","_id":24}]
var result = new Set(arr.map(o => o._id)).size;
console.log(result);
you can use .map() to get an array of ids and use Set to dedupe it :
const data = [{
firstName: "John",
lastName: "Johnson",
_id: 23
},
{
firstName: "John",
lastName: "Johnson",
_id: 23
},
{
firstName: "Mary",
lastName: "Smith",
_id: 24
}
]
const result = [... new Set(data.map(({_id}) => _id))]
console.log(result.length)
Get all the _id from your array of object using map() and use Set to find unique _id and finally use size to get how many of ids are unique?
The Set object lets you store unique values of any type
The map() method creates a new array with the results of calling a provided function on every element in the calling array
var obj = [{
"firstName": "John",
"lastName": "Johnson",
"_id": 23
},
{
"firstName": "John",
"lastName": "Johnson",
"_id": 23
},
{
"firstName": "Mary",
"lastName": "Smith",
"_id": 24
}
];
function countUnique(iterable) {
return new Set(iterable).size;
}
finalArray = obj.map(function(obj) {
return obj._id;
});
console.log(countUnique(finalArray));
Is there a way to clone an object with only few properties of the object in JS?
For example..
var Person = {
name: "Bob",
age: 32,
salary: 20000
};
I have to create another person object with just the name and age property so that it will look something like this :
var clonedPerson = {
name: "Bob",
age: 32
};
I could do a deep clone of the object and delete. But I wanted to know if there are better ways to do it.
Using the latest ES6, you can achieve this by the following code..
const Person = {
name: "Bob",
age: 32,
salary: 20000
};
const { salary , ...clonedPerson } = Person
console.log(clonedPerson)
More simple?
var Person = {
name: "Bob",
age: 32,
salary: 20000
};
var ClonedPerson = jQuery.extend({}, Person);
delete ClonedPerson.salary;
console.log(JSON.stringify(Person));
console.log(JSON.stringify(ClonedPerson));
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
an alternative approach using Array member methods:
var clone = Object.keys(Person) // convert to an Array of Person keys
.filter(function(key){return ["salary"].indexOf(key) == -1;}) // exclude key salary
.reduce(function(clone, current){clone[current] = Person[current]; return clone;}, {}); // convert back the array to a cloned literal object
I've this json return
data = [
{ firstName: "Christophe",
lastName: "Coenraets"},
{ firstName: "John",
lastName: "Smith"}
];
I want to display each object in a li list and want to use Enumerable condition. I understand if it'd been like
data = { elem :[
{ firstName: "Christophe",
lastName: "Coenraets"},
{ firstName: "John",
lastName: "Smith"}
]};
I can use something like
{{#elem}}
<li>{{firstName}} {{lastName}}</li>
{{/elem}}
But in the first case, how do I check the condition?
I don't work with icanhaz, it very well may have a method to parse the data that you get, but you could always modify the JSON object and wrap it into a parent element like in your second case:
myData = { elem : data};