Using .map() to add incrementing values to JS objects - javascript

I'd like to know if one can use .map() to dynamically change the added value to JS objects.
For example, a static use of .map() allows to add a similar ID to all objects of the array.
friends = [
{
"age": 10,
"name": "Castillo"
},
{
"age": 11,
"name": "Daugherty"
},
{
"age": 12,
"name": "Travis"
}
]
// Static mapping --> adds 1 to all objects
friends_static=friends;
friends.map(elem => elem["id"] = 1);
console.log(friends_static)
This returns [{age=10, name="Castillo", id=1}, {age=11, name="Daugherty", id=1}, {age=12, name="Travis", id=1}]
Is it possible to add a unique ID which increments by 1 for each object in a similar way?
Cf. the illustrative JSfiddle and example code below. I know the 1++ is not legal, but just shows the idea I'm trying to realize.
//Dynamic mapping? --> should add 1,2,3...to objects incrementally
/*
friends_dynamic=friends;
friends.map(elem => elem["id"] = 1++);
console.log(friends_dynamic)
*/
This should return [{age=10, name="Castillo", id=1}, {age=11, name="Daugherty", id=2}, {age=12, name="Travis", id=3}]

You could just use the index provided to the Array#map callback:
friends.map((friend, index) => Object.assign({}, friend, { id: index + 1 }))
It's not a good idea to mutate objects in Array#map. The whole purpose of the method is to return new objects that are mapped from the original objects. Thus use Object.assign to avoid mutation.
Of course, if you wanted mutation, thus just use forEach without mapping to new values. It would be more "semantically correct" in that case.

Is this what you mean?
const friends = [
{
"age": 10,
"name": "Castillo"
},
{
"age": 11,
"name": "Daugherty"
},
{
"age": 12,
"name": "Travis"
}
]
friends.forEach((friend, index) => friend.id = index + 1);
console.log(friends)

if you only need an incremental value from 0 on, you can simply use a counter and increment it, like this:
let id = 1;
friends.map(elem => {elem.id = id++;});

Use a local variable and increment it. As per method definition
"The map() method calls the provided function once for each element in an array, in order". In Order would make sure that ids do not collide.
friends = [
{
"age": 10,
"name": "Castillo"
},
{
"age": 11,
"name": "Daugherty"
},
{
"age": 12,
"name": "Travis"
}
]
// Static mapping --> adds 1 to all objects
friends_static=friends;
var i = 1;
friends_static.map(elem => elem["id"] = i++);
console.log(friends_static)
//Dynamic mapping? --> should add 1,2,3...to objects incrementally
/*
friends_dynamic=friends;
friends_dynamic.map(elem => elem["id"] = 1++);
console.log(friends_dynamic)
*/

Related

JavaScript Build Arrays from Array [duplicate]

This question already has answers here:
From an array of objects, extract value of a property as array
(24 answers)
Closed 1 year ago.
I currently have an array that has 2 levels. I am attempting to build two new arrays from the initial array but seem to be stuck with the method to use. I have attempted a forEach(), while loop, as well as push to no avail.
My current array structure:
[
{
"attributes": {
"Summary": 10,
"class": "Blue"
}
},
{
"attributes": {
"Summary": 63,
"class":"Red"
}
}
]
I am looking to build two arrays, namely one for summary values, and one for class values.
Are my approaches of a forEach or while loop on the correct path?
If you have an array and want to transform that into another array, the simplest way is to use map (which basically creates a new array containing the results of running each element through a function):
const arr = [
{
"attributes": {
"Summary": 10,
"class": "Blue"
}
},
{
"attributes": {
"Summary": 63,
"class":"Red"
}
}
];
const summaries = arr.map(e => e.attributes.Summary);
const classes = arr.map(e => e.attributes.class);
If you want to accomplish this using forEach, here's one way to do it:
const aryInitial = [
{
"attributes": {
"Summary": 10,
"class": "Blue"
}
},
{
"attributes": {
"Summary": 63,
"class":"Red"
}
}
];
let arySummary = [];
let aryClass = [];
aryInitial.forEach((obj)=>
{
arySummary.push(obj.attributes.Summary);
aryClass.push(obj.attributes.class);
});
console.log("Summary Array:",arySummary);
console.log("Class Array:",aryClass);

Combining two objects from two different arrays

I have two arrays, orders and cartitems
I want to create a singel payload with information of both of arrays combined. to post to my API using Axios.
I've tried mapping one array (since I only need one item from the other array) and then trying to add the objects together like this:
const payload = []
let newArray = []
this.props.cartItems.map((item) => {
let payloadobject = {
productName: item.productname,
amount: item.qty,
price: item.price,
order_id: this.props.cart.id,
}
newArray = appendObjTo(payload, payloadobject);
})
Hoping newArray would hold the combined combined array. But get met with the error:
can't find variable: appendObjTo
How do I combine both objects? That are each in side of their own array
edit
current data structure
catritems
cartItems Array [
Object {
"id": 2,
"price": "6.50",
"productname": "Baco",
"qty": 2,
}
]
orders
orders Array [
Object {
"id": 2,
}
]
desired output
newArray Array [
Object {
"id": 2,
"price": "6.50",
"productname": "Baco",
"qty": 2,
"order_id": 1 (hold id from order object),
}
]
You get the error message since appendObjTo isn't defined. It's not a standard function, and if you've defined it yourself it's probably in another scope.
Instead of appendObjTo you could use the Object.assign function (MDN Reference). It could be used like this:
newArray = Object.assign({}, payload, payloadobject);
However, there's another fault in your code. Right now your assigning each combined object to newArray, and at the en it will hold the last combined object, not an array.
The lambda function you supply to map should return a new object that you want to replace the input object in the new array. When all objects are looped through the map function returns a new array (MDN Reference). In your case it could be used like this:
const payload = [];
let newArray = this.props.cartItems.map((item) => {
let payloadobject = {
productName: item.productname,
amount: item.qty,
price: item.price,
order_id: this.props.cart.id
};
return Object.assign({ }, payload, payloadobject);
});
This will make newArray be an array of object where each object is a combination of the whole payload, and payloadobject.
Hope this helps 😊

"Flatten" the an array of objects? [closed]

Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
This question does not appear to be about programming within the scope defined in the help center.
Closed 5 years ago.
Improve this question
What is the best way to "flatten" JSON array of objects using pure JS or Lodash?
For example I have an array
[
{
"name": "Mat",
"age": "18",
"studies": [
{
"subject": "English",
"mark": 5
},
{
"subject": "Maths",
"mark": 4
}
],
},
{
"name": "Alice",
"age": 20,
"city": "New York"
}
]
And I want to get something like
[
{
"name": "Mat",
"age": "18",
"subject": "English",
"mark": 5
},
{
"name": "Mat",
"age": "18",
"subject": "Maths",
"mark": 4
},
{
"name": "Alice",
"age": 20,
"city": "New York"
}
]
EDIT: working code is something like
rows.forEach(row => {
let newRow = {}
_.forOwn(row, (value, key) => {
value.forEach(item => {
_.forOwn(item, (value, key) => {
newRow[key] = value
})
})
} else {
newRow[key] = value
}
})
})
It doesn't provide first-level properties like name and for now it was enough for my reasons but now I need to get all properties except for fields like studies in my example.
Modern syntax will let you do it like this:
var d = [{"name":"Mat","age":"18","studies":[{"subject":"English","mark":5},{"subject":"Maths","mark":4}]},{"name":"Alice","age":20,"city":"New York"}];
var r = d.reduce((a, {studies, ...rest}) =>
[...a, ...(studies || [{}]).map(s => ({...s, ...rest}))]
, []);
console.log(r);
Browser support is limited, so use a transpiler if needed.
This uses the new rest syntax for object literals in the second parameter to the .reduce() callback. So basically, studies array is put into its own variable and rest will be an object with all the remaining properties.
Then we use spread syntax for array literals to put the members of the current accumulator array as well as a mapping of the new objects from studies into the callback result.
Within the .map() callback, we use object literal spread syntax to assign the properties of the rest object from the .reduce() callback, as well as the properties of the current "study" object to a new object literal, which is returned.
If there were no studies, we substitute a blank array with an empty object so that it at least gets the rest properties.
If the key to flatten is dynamic, you can still do it, though it's a little longer.
var d = [{"name":"Mat","age":"18","studies":[{"subject":"English","mark":5},{"subject":"Maths","mark":4}]},{"name":"Alice","age":20,"city":"New York"}];
function flatten(key, data) {
return data.reduce((a, user) => {
const arr = user[key];
delete user[key];
return [...a, ...(arr || [{}]).map(s => ({...s, ...user}))]
}, []);
}
console.log(flatten("studies", d));
If the destructuring syntax allowed the square bracket expression evaluation like this {[key], ...user}, that would clean it up, but right now they don't

Merge Arrays Combining Matching Objects in Angular Javascript

I have 2 array objects in Angular JS that I wish to merge (overlap/combine) the matching ones.
For example, the Array 1 is like this:
[
{"id":1,"name":"Adam"},
{"id":2,"name":"Smith"},
{"id":3,"name":"Eve"},
{"id":4,"name":"Gary"},
]
Array 2 is like this:
[
{"id":1,"name":"Adam", "checked":true},
{"id":3,"name":"Eve", "checked":true},
]
I want the resulting array after merging to become this:
[
{"id":1,"name":"Adam", "checked":true},
{"id":2,"name":"Smith"},
{"id":3,"name":"Eve", "checked":true},
{"id":4,"name":"Gary"},
]
Is that possible? I have tried angular's array_merge and array_extend like this:
angular.merge([], $scope.array1, $scope.array2);
angular.extend([], $scope.array1, $scope.array2);
But the above method overlap the first 2 objects in array and doesn't merge them based on matching data. Is having a foreach loop the only solution for this?
Can someone guide me here please?
Not sure if this find of merge is supported by AngularJS. I've made a snippet which does exactly the same:
function merge(array1, array2) {
var ids = [];
var merge_obj = [];
array1.map(function(ele) {
if (!(ids.indexOf(ele.id) > -1)) {
ids.push(ele.id);
merge_obj.push(ele);
}
});
array2.map(function(ele) {
var index = ids.indexOf(ele.id);
if (!( index > -1)) {
ids.push(ele.id);
merge_obj.push(ele);
}else{
merge_obj[index] = ele;
}
});
console.log(merge_obj);
}
var array1 = [{
"id": 1,
"name": "Adam"
}, {
"id": 2,
"name": "Smith"
}, {
"id": 3,
"name": "Eve"
}, {
"id": 4,
"name": "Gary"
}, ]
var array2 = [{
"id": 1,
"name": "Adam",
"checked": true
}, {
"id": 3,
"name": "Eve",
"checked": true
}, ];
merge(array1, array2);
Genuinely, extend in Angular works with object instead of array. But we can do small trick in your case. Here is another solution.
// a1, a2 is your arrays
// This is to convert array to object with key is id and value is the array item itself
var a1_ = a1.reduce(function(obj, value) {
obj[value.id] = value;
return obj;
}, {});
var a2_ = a2.reduce(function(obj, value) {
obj[value.id] = value;
return obj;
}, {});
// Then use extend with those two converted objects
var result = angular.extend([], a1_, a2_).splice(1)
Notes:
For compatibility, reduce may not work.
The after array will replace the previous one. This is because of implementation of extend in Angular.

JSON/Javascript: return INDEX of array object containing a certain property

Given a JSON object such as this:
{
"something": {
"terms": [
{
"span": [
15,
16
],
"value": ":",
"label": "separator"
},
{
"span": [
16,
20
],
"value": "12.5",
"label": "number"
}
],
"span": [
15,
20
],
"weight": 0.005,
"value": ":12.5"
}
}
I asked a question about parsing the object out where label: number here:
JSON/Javascript: return which array object contains a certain property
I got a sufficient answer there (use filter()), but now need to know the original index of the object.
This issue seems to have the answer, but I simply don't know enough about javascript to translate it into something useful for my particular problem.
The following code successfully returns the object. Now I need to modify this to return the original index of the object:
var numberValue, list = parsed.something.terms.filter(function(a){
return a.label==='number';
});
numberValue = list.length ? list[0].value : -1;
This needs to be a pure javascript solution, no external libraries, etc.
I don't think you can modify the filter solution as within the filter you've lost the indexes.
The solution you've linked to uses the angular external library.
So here is a pure JS solution:
var numberValue = parsed.something.terms
.map(function(d){ return d['label']; })
.indexOf('number');
Array.prototype.indexOf()
Array.prototype.map()
Use forEach and collect the indices of objects that satisfy the a.label==='number' predicate :
var target = parsed.something.terms;
var list = [];
target.forEach(function(element, index){
if (element.label==='number') {
list.push(index)
};
});
var numberValue = list.length ? target[list[0]].value : -1;
console.log(list); // [1]
console.log(numberValue); // 12.5

Categories