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 😊
Related
So I have a series of objects that are pulled from an API and inputted into an array, something like such:
array = [
{id: 0, name: "First", relationship: "Friend"},
{id: 1, name: "Second", relationship: "Friend"}
]
The user is allowed to add and remove objects to the list freely (they will appear within a Vue.JS DataTable), and said user is allowed a maximum of 4 objects within the array (lets say 4 "friends")
How should I go about implementing a function that searches the existing array (say, if its populated from the API), and inputs the new object with the corresponding ID that is missing (so if the user deletes the object with the id 2, and adds another, it will search said array with objects, find the missing id 2 slot in the array, and input the object in its place)?
Previously I have gone about it via implement array.find() with conditionals to see if the array contains or does not contain the certain id value, however, it searches through each entry and can end up inserting the same object multiple times. Another method I haven't attempted yet would be having a separate map that contains ids, and then when a user removes an object, having it correspond with the map, and vice versa when adding.
Any suggestions? Thanks
Instead of an array, I'd keep an object in data. Have it keyed by id, like this:
let objects = {
0: { id: 0, name: 'name0', relationship: 'relationship0' },
1: { id: 1, name: 'name1', relationship: 'relationship1' },
}
Integer keys in modern JS will preserve insertion order, so you can think of this object as ordered. The API probably returns an array, so do this...
// in the method that fetches from the api
let arrayFromApi = [...];
this.objects = array.reduce((acc, obj) => {
acc[obj.id] = obj; // insertion order will be preserved
return acc;
}, {});
Your UI probably wants an array, so do this (refer to "array" in the markup):
computed: {
array() {
return Object.values(this.objects);
},
To create a new object, insert it in order, minding the available keys. Note this is a linear search, but with small numbers of objects this will be plenty fast
methods: {
// assumes maxId is const like 4 (or 40, but maybe not 400)
createObject(name, relationship) {
let object = { name, relationship };
for (let i=0; i< maxId; i++) {
if (!this.objects[i]) {
object.id = i;
this.objects[i] = object;
break;
}
}
try this,
let array = [
{id: 0, name: "First", relationship: "Friend"},
{id: 4, name: "Second", relationship: "Friend"},
{id: 2, name: "Second", relationship: "Friend"},
]
const addItem = (item) => {
let prevId = -1
// this is unnecessary if your array is already sorted by id.
// in this example array ids are not sorted. e.g. 0, 4, 2
array.sort((a, b) => a.id - b.id)
//
array.forEach(ob => {
if(ob.id === prevId + 1) prevId++
else return;
})
item = {...item, id: prevId + 1 }
array.splice(prevId+1, 0, item)
}
addItem({name: "x", relationship: "y"})
addItem({name: "a", relationship: "b"})
addItem({name: "c", relationship: "d"})
console.log(array)
You can simply achieve this with the help of Array.find() method along with the Array.indexOf() and Array.splice().
Live Demo :
// Input array of objects (coming from API) and suppose user deleted 2nd id object from the array.
const arr = [
{id: 0, name: "First", relationship: "Friend" },
{id: 1, name: "Second", relationship: "Friend" },
{id: 3, name: "Fourth", relationship: "Friend" }
];
// find the objects next to missing object.
const res = arr.find((obj, index) => obj.id !== index);
// find the index where we have to input the new object.
const index = arr.indexOf(res);
// New object user want to insert
const newObj = {
id: index,
name: "Third",
relationship: "Friend"
}
// Insert the new object into an array at the missing position.
arr.splice(index, 0, newObj);
// Output
console.log(arr);
I've got two arrays that have multiple objects
[
{
"name":"paul",
"employee_id":"8"
}
]
[
{
"years_at_school": 6,
"department":"Mathematics",
"e_id":"8"
}
]
How can I achieve the following with either ES6 or Lodash?
[
{
"name":"paul",
"employee_id":"8"
"data": {
"years_at_school": 6
"department":"Mathematics",
"e_id":"8"
}
}
]
I can merge but I'm not sure how to create a new child object and merge that in.
Code I've tried:
school_data = _.map(array1, function(obj) {
return _.merge(obj, _.find(array2, {employee_id: obj.e_id}))
})
This merges to a top level array like so (which is not what I want):
{
"name":"paul",
"employee_id":"8"
"years_at_school": 6
"department":"Mathematics",
"e_id":"8"
}
The connector between these two is "employee_id" and "e_id".
It's imperative that it's taken into account that they could be 1000 objects in each array, and that the only way to match these objects up is by "employee_id" and "e_id".
In order to match up employee_id and e_id you should iterate through the first array and create an object keyed to employee_id. Then you can iterate though the second array and add the data to the particular id in question. Here's an example with an extra item added to each array:
let arr1 = [
{
"name":"mark",
"employee_id":"6"
},
{
"name":"paul",
"employee_id":"8"
}
]
let arr2 = [
{
"years_at_school": 6,
"department":"Mathematics",
"e_id":"8"
},
{
"years_at_school": 12,
"department":"Arr",
"e_id":"6"
}
]
// empObj will be keyed to item.employee_id
let empObj = arr1.reduce((obj, item) => {
obj[item.employee_id] = item
return obj
}, {})
// now lookup up id and add data for each object in arr2
arr2.forEach(item=>
empObj[item.e_id].data = item
)
// The values of the object will be an array of your data
let merged = Object.values(empObj)
console.log(merged)
If you perform two nested O(n) loops (map+find), you'll end up with O(n^2) performance. A typical alternative is to create intermediate indexed structures so the whole thing is O(n). A functional approach with lodash:
const _ = require('lodash');
const dataByEmployeeId = _(array2).keyBy('e_id');
const result = array1.map(o => ({...o, data: dataByEmployeeId.get(o.employee_id)}));
Hope this help you:
var mainData = [{
name: "paul",
employee_id: "8"
}];
var secondaryData = [{
years_at_school: 6,
department: "Mathematics",
e_id: "8"
}];
var finalData = mainData.map(function(person, index) {
person.data = secondaryData[index];
return person;
});
Sorry, I've also fixed a missing coma in the second object and changed some other stuff.
With latest Ecmascript versions:
const mainData = [{
name: "paul",
employee_id: "8"
}];
const secondaryData = [{
years_at_school: 6,
department: "Mathematics",
e_id: "8"
}];
// Be careful with spread operator over objects.. it lacks of browser support yet! ..but works fine on latest Chrome version for example (69.0)
const finalData = mainData.map((person, index) => ({ ...person, data: secondaryData[index] }));
Your question suggests that both arrays will always have the same size. It also suggests that you want to put the contents of array2 within the field data of the elements with the same index in array1. If those assumptions are correct, then:
// Array that will receive the extra data
const teachers = [
{ name: "Paul", employee_id: 8 },
{ name: "Mariah", employee_id: 10 }
];
// Array with the additional data
const extraData = [
{ years_at_school: 6, department: "Mathematics", e_id: 8 },
{ years_at_school: 8, department: "Biology", e_id: 10 },
];
// Array.map will iterate through all indices, and gives both the
const merged = teachers.map((teacher, index) => Object.assign({ data: extraData[index] }, teacher));
However, if you want the data to be added to the employee with an "id" matching in both arrays, you need to do the following:
// Create a function to obtain the employee from an ID
const findEmployee = id => extraData.filter(entry => entry.e_id == id);
merged = teachers.map(teacher => {
const employeeData = findEmployee(teacher.employee_id);
if (employeeData.length === 0) {
// Employee not found
throw new Error("Data inconsistency");
}
if (employeeData.length > 1) {
// More than one employee found
throw new Error("Data inconsistency");
}
return Object.assign({ data: employeeData[0] }, teacher);
});
A slightly different approach just using vanilla js map with a loop to match the employee ids and add the data from the second array to the matching object from the first array. My guess is that the answer from #MarkMeyer is probably faster.
const arr1 = [{ "name": "paul", "employee_id": "8" }];
const arr2 = [{ "years_at_school": 6, "department": "Mathematics", "e_id": "8" }];
const results = arr1.map((obj1) => {
for (const obj2 of arr2) {
if (obj2.e_id === obj1.employee_id) {
obj1.data = obj2;
break;
}
}
return obj1;
});
console.log(results);
My initial state is like below and if new Book added or price is changed then new updated array is coming from service whose result i need to merge in my initial state.
const initialState = {
booksData: [
{"Code":"BK01","price":"5"},
{"code":"BK02","price":"30"},
{"code":"BK03","price":"332"},
{"code":"BK04","price":"123"}
]
};
Updated array from server with few records updated/new
data: [
{"Code":"BK01","price":"10"},
{"code":"BK02","price":"25"},
{"code":"BK05","price":"100"}
]
updated state should become after merging updated array with old array.
booksData: [
{"Code":"BK01","price":"10"},
{"code":"BK02","price":"25"},
{"code":"BK03","price":"332"},
{"code":"BK04","price":"123"},
{"code":"BK05","price":"100"}
]
I would filter out elements of the old data that are in the new data, and concat.
const oldBooks = booksData.filter(book => !newData.some(newBook => newBook.code === book.code));
return oldBooks.concat(newData);
Keep in mind you must NOT push values into the old array. In your reducer you MUST create new instances, here a new array. 'concat' does that.
You can first merge both the array together and then reduce it to remove duplicates like
var booksData = [
{"code":"BK01","price":"5"},
{"code":"BK02","price":"30"},
{"code":"BK03","price":"332"},
{"code":"BK04","price":"123"}
]
var newData = [
{"code":"BK01","price":"10"},
{"code":"BK02","price":"25"},
{"code":"BK05","price":"100"}
]
const result = [...newData, ...booksData].reduce((res, data, index, arr) => {
if (res.findIndex(book => book.code === data.code ) < 0) {
res.push(data);
}
return res;
}, [])
console.log(result);
Merge the two array and filter using 'Code' property
const initialState = {
booksData: [
{ "Code": "BK01", "price": "5" },
{ "code": "BK02", "price": "30" },
{ "code": "BK03", "price": "332" },
{ "code": "BK04", "price": "123" }
]
};
const data =
[
{ "Code": "BK01", "price": "10" },
{ "code": "BK02", "price": "25" },
{ "code": "BK05", "price": "100" }
]
let newState = [...initialState.booksData, ...data];
newState = newState.filter((obj, pos, arr) => {
return arr.map(mapObj => mapObj['Code']).indexOf(obj['Code']) !== pos;
});
console.log(newState);
Collection of Objects
Filter a merged array to pick only non-existent items by iterating every item in the merged array which its index is before the current index of the "parent" filter iterator
const mergedUnique = [
...[{id:1}, {id:2}, {id:3}],
...[{id:1}, {id:4}, {id:2}]
]
.filter((item, idx, arr) =>
!arr.some(({id}, subIdx) => subIdx < idx && id == item.id)
)
console.log( mergedUnique )
Basic technique for "simple" arrays
Merge some arrays and filter them to pick only non-existent items by checking if the same item exists anywhere before the current item's index in the merged array.
lastIndexOf is used to check backwards, if the current value exists already, which contributes to keeping the order of the merged array in a certain way which might be desirable, which can only be achieved by checking backward and not forward.
Skip checking the first item - is obviously not a duplicate.
const mergedUniqe = [...[1,2,3], ...[1,3,4,5,2]] // [1, 2, 3, 1, 3, 4, 5, 2]
.filter((item, idx, arr) =>
!~arr.lastIndexOf(item, idx-1) || !idx
)
console.log( mergedUniqe )
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)
*/
I have this array of objects
[ { id: '573267d06b2957ab24c54d59' },
{ id: '573267d06b2957ab24c54d5a' },
{ id: '573267d06b2957ab24c54d5b' },
{ id: '573267d06b2957ab24c54d5c' },
{ id: '573267d06b2957ab24c54d5d' }
]
I wish to convert it to the following in NodeJs
[ '573267d06b2957ab24c54d59',
'573267d06b2957ab24c54d5a',
'573267d06b2957ab24c54d5b',
'573267d06b2957ab24c54d5c',
'573267d06b2957ab24c54d5d'
]
It seems like it should be easy given the right library/package, but I am struggling to find the right wording to "flatten" the array into the IDs of the contained objects.
Say your array of objects is called arr, just do this:
var arrayOfStrings = arr.map(function(obj) {
return obj.id;
});
map will iterate over the array and create a new array based on how you define your function. In this case we return the value of the id key in each case to build out the desired array of ids.