copying data from one array to another array - javascript

Array One:
array1 = [{
"id": 1,
"name": "aaaaa",
"attr": [{"attr_code": "a_id", "value": "5"}]
},
{
"id": 2,
"name": "bbbbb",
"attr": [{"attr": "a_id", "value": "4"}]
}]
Array Two:
array2 = [{
"id": 4,
"name": "bef",
},
{
"id": 5,
"name": "bcd",
}]
Resulting Array:
resultingArray = [{
"id": 1,
"name": "aaaaa",
"attr": [{"attr_code": "a_id", "value": "5"}],
"a_id" : {"id": 5, "name": "bcd"}
},
{
"id": 2,
"name": "bbbbb",
"attr": [{"attr": "a_id", "value": "4"}],
"a_id" : {"id": 4, "name": "bef"}
}]
I am looking to add the array2 objects into array1 based on id's of array2. I have tried using map function on both the arrays to compare and add the object but I didn't succeed. Can you please suggest me how to do it?
Thank you

Add the array2 objects into array1 based on ids of array2.
let array1 =
[
{
"id": 1,
"name": "aaaaa",
"attr": [{"attr_code": "a_id", "value": "5"}]
},
{
"id": 2,
"name": "bbbbb",
"attr": [{"attr": "a_id", "value": "4"}]
}
];
let array2 = [{
"id": 4,
"name": "bef",
},
{
"id": 5,
"name": "bcd",
}
];
let resultingArray=[];
array1.forEach(function(element) {
element['a_id'] = [];
element['attr'].forEach(function(attr) {
element['a_id'].push(array2.find(function(item) {
return item.id == attr.value;
}));
});
resultingArray.push(element)
});
console.log(resultingArray);

I presume you intend to extract the object whose ID is equal to the value field the in the each object in array1.
var array1 = [{
"id": 1,
"name": "aaaaa",
"attr": [{"attr_code": "a_id", "value": "5"}]
},
{
"id": 2,
"name": "bbbbb",
"attr": [{"attr": "a_id", "value": "4"}]
}];
var array2 = [{
"id": 4,
"name": "bef",
},
{
"id": 5,
"name": "bcd",
}];
var resultingArray = [];
for(var i = 0; i < array1.length; i++) {
resultingArray[i] = array1[i];
for(var j = 0; j < array2.length; j++) {
if(resultingArray[i].attr[0].attr_code.value === array2[j].id) {
resultingArray[i].push("a_id": array2[j]);
}
}
}
You just need to lop through array1, and for each object in array1, you need to find corresponding objects in array2 which match the criterion.

You can use array map and array index to do:
var array1 = [{
"id": 1,
"name": "aaaaa",
"attr": [{"attr_code": "a_id", "value": "5"}]
},
{
"id": 2,
"name": "bbbbb",
"attr": [{"attr": "a_id", "value": "4"}]
}];
var array2 = [{
"id": 4,
"name": "bef",
},
{
"id": 5,
"name": "bcd",
}];
var result = array1.map(current=>{
//find index of attr in array2
let index = array2.findIndex(c=>{
if (c['id']===(Number(current['attr'][0]['value'])))
return c;
});
current["a_id"] = array2[index];
return current;
});
console.log(result);

Please check if the following code suites your requirement. You may need to make some changes.
function mergeArrays3 (arr1, arr2) {
return arr1.map((value, index) => {
let object = null;
let result = {...value};
for (let element of arr2) {
if (element.id == parseInt(value.attr[0].value)) {
object = element;
break;
}
}
if (object != null) {
let attr = value.attr[0];
if (attr.hasOwnProperty("attr")) {
result[value.attr[0].attr] = object;
} else if (attr.hasOwnProperty("attr_code")) {
result[value.attr[0].attr_code] = object;
}
}
return result;
});
}
I loop over first array and find an element in second array matching id of value.attr[0].value. If found then i added this object in the first array at key of value.attr[0].attr or value.attr[0].attr_code.

I have tried using map function on both the arrays to compare and add
the object but I didn't succeed
Below is the functional programming approach using map():
/* GIVEN */
const array1 = [{
"id": 1,
"name": "aaaaa",
"attr": [{
"attr_code": "a_id",
"value": "5"
}]
},
{
"id": 2,
"name": "bbbbb",
"attr": [{
"attr": "a_id",
"value": "4"
}]
}
]
const array2 = [{
"id": 4,
"name": "bef",
},
{
"id": 5,
"name": "bcd",
}]
/* From array2, make an object keyed by the 'id' field. We'll use this as a key-value lookup table */
const lookupTable = array2.reduce((accum, item) => {
accum[item.id.toString()] = item
return accum
}, {})
console.log('***LOOKUP TABLE***\n', lookupTable) // result is an object we use to lookup
/* From array1, we append data from the lookup table */
const final = array1.map(item => {
item.a_id = lookupTable[item.attr[0].value]
return item
})
console.log("***RESULT***\n", final)
Hope this helps.
Cheers,

Related

How can I inner join with two object arrays in JavaScript?

I need inner join with two array in javascript like this:
array1 =
[
{
"id": 1,
"name": "Tufan"
},
{
"id": 2,
"name": "Batuhan"
},
{
"id": 3,
"name": "Hasan"
}
]
array2 =
[
{
"name": "yyy",
"externalid": "1",
"value": "Asd"
},
{
"name": "aaaa"
"externalid": "2",
"value": "ttt"
}
]
expectedArray =
[
{
"id": 1,
"name": "Tufan",
"externalid": "1",
"value": "Asd"
},
{
"id": 2,
"name": "Batuhan",
"externalid": "2",
"value": "ttt"
}
]
rules:
on: array2.externalid = array1.id
select: array1.id, array1.name, array2.externalid, array2.value
My approach:
array1.filter(e => array2.some(f => f.externalid == e.id));
// I need help for continue
How can I make this?
Doesn't matter information: I use ES5 and pure javascript
You can do it like this:
const res = array2.map((item) => {
const related = array1.find((el) => el.id == item.externalid);
return { ...item, ...related };
});
Using a map to loop over the array2 and a find to get the array1 relative.

Convert JSON Array to a JSON Object using Javascript

I would like to know how to convert the input json array to a json object in the expected format using Javascript
Here is my input array
[
{
"Id": 1,
"Name": "One"
},
{
"Id": 2,
"Name": "Two"
},
{
"Id": 3,
"Name": "Three"
}
]
Expected json object output
{ "1" : "One",
"2" :"Two",
"3" :"Three"
}
You can use array reduce and pass an empty object in the accumulator. Then inside the reduce callback update the accumulator array by adding key and value
let obj = [{
"Id": 1,
"Name": "One"
}, {
"Id": 2,
"Name": "Two"
}, {
"Id": 3,
"Name": "Three"
}]
let newObj = obj.reduce(function(acc, curr) {
acc[curr.Id] = curr.Name;
return acc;
}, {})
console.log(newObj)
let arr = [{
"Id": 1,
"Name": "One"
},
{
"Id": 2,
"Name": "Two"
},
{
"Id": 3,
"Name": "Three"
}
]
let json1 = {}
for (const s of arr) {
json1[s.Id] = s.Name
}
console.log(json1)
You only need a simple for loop to iterate trough the array and then assign new properties to the resulting object, like so:
let array = [{ "Id": 1, "Name": "One"}, {"Id": 2, "Name": "Two"}, {"Id": 3, "Name": "Three"}];
let obj = {};
for (let i = 0; i < array.length; i++) {
const elem = array[i];
obj[elem.Id] = elem.Name;
}
console.log(obj);
Iterate over the array of objects, use Object.values() to get the values for each object and then create new obects using the first value as the key.
var arr = [ { "Id": 1, "Name": "One" }, { "Id": 2, "Name": "Two" }, { "Id": 3, "Name": "Three" } ];
var jsonObj = {};
arr.forEach(function(item){
var values = Object.values(item);
jsonObj[values[0]] = values[1];
})
console.log(jsonObj); // gives {"1": "One","2": "Two","3": "Three"}

Filtering an array based on multiple arrays inputs

I have three arrays.
1. Existing viewers array - existingViewers
New viewers array - newViewers
Permitted Viewers array - permittedViewers
permittedViewers is used for rendering the drop-down. And I wish to filter the newViewers and existingViewers entries from the permittedViewers.
I am doing this as three steps. And I am afraid this is not the optimized way. Can someone suggest the ideal way of doing this?
The expected result is
[
{
"id": 4,
"name": "name4"
},
{
"id": 5,
"name": "name5"
},
{
"id": 6,
"name": "name6"
}
]
let existingViewers = [{
"viewerId": 1,
"name": "name1"
},
{
"viewerId": 2,
"name": "name2"
}
],
newViewers = [
{
"viewerId": 3,
"name": "name3"
}
],
permittedViewers = [{
"id": 1,
"name": "name1"
},
{
"id": 2,
"name": "name2"
},
{
"id": 3,
"name": "name3"
},
{
"id": 4,
"name": "name4"
},
{
"id": 5,
"name": "name5"
},
{
"id": 6,
"name": "name6"
}
]
let grouped = [...existingViewers, ...newViewers]
let viewerFilter = grouped.map(viewer => { return viewer.viewerId; });
let filteredPermittedViewers = permittedViewers.filter(viewer => !viewerFilter.includes(viewer.id));
console.log(filteredPermittedViewers)
I'd make a Set of the ids of the first two arrays, and then filter the third by whether the set includes the id. (Sets have O(1) lookup time)
let existingViewers=[{"viewerId":1,"name":"name1"},{"viewerId":2,"name":"name2"}],newViewers=[{"viewerId":3,"name":"name3"}],permittedViewers=[{"id":1,"name":"name1"},{"id":2,"name":"name2"},{"id":3,"name":"name3"},{"id":4,"name":"name4"},{"id":5,"name":"name5"},{"id":6,"name":"name6"}];
const ids = new Set([...existingViewers, ...newViewers].map(({ viewerId }) => viewerId));
const output = permittedViewers.filter(({ id }) => !ids.has(id));
console.log(output);
You can compress all three statements into a single statement -- just replace the variable name with the statement that creates it:
let existingViewers = [{
"viewerId": 1,
"name": "name1"
},
{
"viewerId": 2,
"name": "name2"
}
],
newViewers = [
{
"viewerId": 3,
"name": "name3"
}
],
permittedViewers = [{
"id": 1,
"name": "name1"
},
{
"id": 2,
"name": "name2"
},
{
"id": 3,
"name": "name3"
},
{
"id": 4,
"name": "name4"
},
{
"id": 5,
"name": "name5"
},
{
"id": 6,
"name": "name6"
}
]
let filteredPermittedViewers = permittedViewers.filter(viewer => ! [...existingViewers, ...newViewers].map(viewer => viewer.viewerId).includes(viewer.id));
console.log(filteredPermittedViewers)

mapping JSON Data reverse?

I got stuck on a maybe simple task, but could not find any solution.
I have some JSON Data - lets say:
[{
"_id": 1,
"type": "person",
"Name": "Hans",
"WorksFor": ["3", "4"]
}, {
"_id": 2,
"type": "person",
"Name": "Michael",
"WorksFor": ["3"]
}, {
"_id": 3,
"type": "department",
"Name": "Marketing"
}, {
"_id": 4,
"type": "department",
"Name": "Sales"
}]
As I learned here it is quite simple to get all the persons and the departments they work for together using a map array for the departments.
Then I can map the corresponding department to the Person and receive something like:
[{
"_id": 1,
"type": "person",
"Name": "Hans",
"WorksFor": ["3", "4"],
"Readable": ["Marketing", "Sales"]
}, {
"_id": 2,
"type": "person",
"Name": "Michael",
"WorksFor": ["3"],
"Readable": ["Sales"]
}]
But for another interface I need the data "the other way round" e.g.
[{
"_id": 3,
"type": "department",
"Name": "Marketing",
"employees": [
"Hans", "Michael"
]
}, {
"_id": 4,
"type": "department",
"Name": "Sales",
"employees": [
"Hans"
]
}]
Is there any decent way to achieve this structure? Two days of trying didn't get me anywhere...
var data = [{ "_id": 1, "type": "person", "Name": "Hans", "WorksFor": ["3", "4"] }, { "_id": 2, "type": "person", "Name": "Michael", "WorksFor": ["3"] }, { "_id": 3, "type": "department", "Name": "Marketing" }, { "_id": 4, "type": "department", "Name": "Sales" }];
var departments = [],
persons = [];
data.forEach(e => {
if (e.type === "person") {
persons.push(e);
} else if (e.type === "department") {
departments.push(e);
e.employees = [];
}
});
departments.forEach(d => {
var workers = persons.filter(p => p.WorksFor.indexOf(d._id.toString()) > -1)
/*.map(p => p.Name)*/ // add this if you only need the name instead of the complete "person"
d.employees = d.employees.concat(workers);
});
console.log(JSON.stringify(departments, null, 4));
You can try something like this:
var data = [{ "_id": 1, "type": "person", "Name": "Hans", "WorksFor": ["3", "4"]}, { "_id": 2, "type": "person", "Name": "Michael", "WorksFor": ["3"]}, { "_id": 3, "type": "department", "Name": "Marketing"}, { "_id": 4, "type": "department", "Name": "Sales"}]
var ignoreDept = ['person'];
var result = data.reduce(function(p,c,i,a){
if(ignoreDept.indexOf(c.type) < 0){
c.employees = a.reduce(function(arr,emp){
if(emp.WorksFor && emp.WorksFor.indexOf(c._id.toString()) > -1){
arr.push(emp.Name)
}
return arr;
},[]);
p.push(c);
}
return p;
}, []);
console.log(result)
The solution using Array.prototype.filter() and Array.prototype.forEach() functions:
var data = [{ "_id": 1, "type": "person", "Name": "Hans", "WorksFor": ["3", "4"]}, { "_id": 2, "type": "person", "Name": "Michael", "WorksFor": ["3"]}, { "_id": 3, "type": "department", "Name": "Marketing"}, { "_id": 4, "type": "department", "Name": "Sales"}],
// getting separated "lists" of departments and employees(persons)
deps = data.filter(function(o){ return o.type === "department"; }),
persons = data.filter(function(o){ return o.type === "person"; });
deps.forEach(function (d) {
d['employees'] = d['employees'] || [];
persons.forEach(function (p) {
if (p.WorksFor.indexOf(String(d._id)) !== -1) { // check the `id` coincidence between the employee and the department
d['employees'].push(p.Name);
}
});
});
console.log(deps);
You could use a hash table and a single loop for each array.
Methods:
Array#reduce for iterating an array and returning the result,
Array#forEach for looping the inner array WorksFor,
Object.create(null) to generate an object without any prototypes,
some other pattern, like a closure over hash and
the use of logical OR || for checking a falsy value and taking an object as default.
hash[b] = hash[b] || { _id: b, employees: [] };
var data = [{ _id: 1, type: "person", Name: "Hans", WorksFor: [3, 4] }, { _id: 2, type: "person", Name: "Michael", WorksFor: [3] }, { _id: 3, type: "department", Name: "Marketing" }, { _id: 4, type: "department", Name: "Sales" }],
result = data.reduce(function (hash) {
return function (r, a) {
if (a.type === 'person') {
a.WorksFor.forEach(function (b) {
hash[b] = hash[b] || { _id: b, employees: [] };
hash[b].employees.push(a.Name);
});
}
if (a.type === 'department') {
hash[a._id] = hash[a._id] || { _id: b, employees: [] };
hash[a._id].type = a.type;
hash[a._id].Name = a.Name;
r.push(hash[a._id]);
}
return r;
};
}(Object.create(null)), []);
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Here's a way you can get the first mapping. I've added some comments so you can follow along, and with it I hope you can find the answer to your second problem.
// First, let's get just the items in this array that identify persons
// I've called this array "data"
data.filter(x => x.type === 'person')
// Now let's map over them
.map(person =>
// We want all of the data associated with this person, so let's
// use Object.assign to duplicate that data for us
Object.assign({}, person, {
// In addition, we want to map the ID of the WorksFor array to the Name
// of the corresponding department. Assuming that the _id key is unique,
// we can due this simply by mapping over the WorksFor array and finding
// those values within the original array.
Readable: person.WorksFor.map(wfId =>
// Notice here the parseInt. This will not work without it due to
// the type difference between WorksFor (string) and _id (integer)
data.find(d => d._id === parseInt(wfId)).Name
)
})
);
var data = [{ "_id": 1, "type": "person", "Name": "Hans", "WorksFor": ["3", "4"]}, { "_id": 2, "type": "person", "Name": "Michael", "WorksFor": ["3"]}, { "_id": 3, "type": "department", "Name": "Marketing"}, { "_id": 4, "type": "department", "Name": "Sales"}];
var dep = {};
data.forEach(e => (e.type === 'person' && e.WorksFor.forEach(d => dep[d]? dep[d].push(e.Name): dep[d] = [e.Name])));
data.forEach(e => (e.type == 'department' && (e.employees = dep[e._id] || [])));
data = data.filter(e => e.type == 'department');
console.log(data);

Nesting a parent child relationship in lodash, given the parent id and children

How would I be able to nest json object if the parent and its children was given as a property.
The data looks like:
"1": {
"id": 1,
"name": "foo",
"parent": null,
"root": 1,
"children": [2, 4, 6],
"posts":[
{ "id": "1", "name": "item1" },
{ "id": "2", "name": "item2" },
{ "id": "3", "name": "item3" }
]
},
"2": {
"id": 2,
"name": "bar",
"parent": 1,
"root": 1,
"children": null,
"posts":[
{ "id": "4", "name": "item4" }
]
},
"3": {
"id": 3,
"name": "bazz",
"parent": null,
"root": 3,
"children": [5, 7],
"posts":[
{ "id": "5", "name": "item5" },
{ "id": "6", "name": "item6" }
]
},
....
A simple groupby using lodash won't do it.
var group = _.groupBy(data, 'parent');
Here is a fiddle:
http://jsfiddle.net/tzugzo8a/1/
The context of question is a nested categories with subcategories, and categories can have categories and posts in them.
Basically I don't want to have a different property for children and posts, since they are all children of a parent.
Desired output
"1": {
"id": 1,
"name": "foo",
"parent": null,
"root": 1,
"isCategory": true,
"children": [
{
"id": 2,
"name": "bar",
"parent": 1,
"root": 1,
"isCategory": true,
"children": null
},
{ "id": "1", "name": "item1", isCategory: false },
{ "id": "2", "name": "item2", isCategory: false },
{ "id": "3", "name": "item3", isCategory: false }
]
...
}
This is my take on the question (fiddle):
var data = getData();
var group = getTree(data);
console.log(group);
function getTree(flat) {
return _.reduce(flat, function (treeObj, item, prop, flatTree) {
var children = _.map(item.children, function (childId) {
return _.set(flatTree[childId], 'isCategory', true);
}).concat(_.map(item.items, function(item) {
return _.set(item, 'isCategory', false);
}));
item.children = !!children.length ? children : null;
delete item.items;
item.parent === null && (treeObj[prop] = item);
return treeObj;
}, {});
}
Take a look on the updated fiddle:
var data = getData();
_.keys(data).forEach(function(id){
var element = data[id];
if (element.children === null){
element.children = [];
}
element.isCategory = true;
element.items.forEach(function(item){
item.isCategory = false;
})
});
_.keys(data).forEach(function(id){
var element = data[id];
element.children = element.children.map(function(childId){
return data[childId];
}).concat(element.items);
});
_.keys(data).forEach(function(id){
delete data[id].items;
});
console.log(JSON.stringify(_.findWhere(_.values(data), {'parent': null})));

Categories

Resources