mapping arrays together with unique keys - javascript

I am trying to map two arrays together and then create unique keys for the values in that new array. I am working with multiple different arrays.
My arrays look like this
var arr =
[
{
"title": "title 1"
"projects": [
"project1",
"project2",
"project3",
"project4",
"project5",
"project6"
],
"project_links": [
"link1",
"link2",
"link3",
"link4",
"link5",
"link6"
]
},
{
"title": "title 2"
"projects": [
"project1",
"project2",
"project3"
],
"project_links": [
"link1",
"link2",
"link3"
]
},
{
"title": "title 3"
"projects": [
"project1",
"project2",
"project3",
"project4",
"project5"
],
"project_links": [
"link1",
"link2",
"link3",
"link4",
"link5"
]
},
{
"title": "title 4"
"projects": [
"project1",
"project2",
"project3",
"project4",
"project5"
],
"project_links": [
"link1",
"link2",
"link3",
"link4",
"link5"
]
},
{
"title": "title 5"
"projects": [
"project1"
],
"project_links": [
"link1"
]
}
]
This is what I have tried
for (let i = 0; i < arr.length; i++) {
var test = arr[i].projects.map((x, y) => [x, arr[i].project_links[y]])
for (let n = 0; n < test.length; n++) {
arr[i].custom = {};
arr[i].custom["projects"] = [];
arr[i].custom["projects"].push({
name: test[n][0],
link: test[n][1]
});
}
}
I want my end result to look like this
var arr =
[
{
"title": "title 1"
"custom": {
"projects": [
{
"project_name": "project1",
"link": "link1"
},
{
"project_name": "project2",
"link": "link2"
},
{
"project_name": "project3",
"link": "link3"
},
{
"project_name": "project4",
"link": "link5"
},
{
"project_name": "project5",
"link": "link5"
},
{
"project_name": "project6",
"link": "link6"
}
]
}
},
{
"title": "title 2"
"custom": {
"projects": [
{
"project_name": "project1",
"link": "link1"
},
{
"project_name": "project2",
"link": "link2"
},
{
"project_name": "project3",
"link": "link3"
}
]
}
},
{
"title": "title 3"
"custom": {
"projects": [
{
"project_name": "project1",
"link": "link1"
},
{
"project_name": "project2",
"link": "link2"
},
{
"project_name": "project3",
"link": "link3"
},
{
"project_name": "project4",
"link": "link4"
},
{
"project_name": "project5",
"link": "link5"
}
]
}
},
...etc
]
I'm able to map the arrays together and create unique key names for the values, however I don't know how I can have those arrays in the correct objects. I want to be able to push it into the original arr instead of creating a brand new array. I can delete the unwanted parts of the array later. Thanks in advance.

Using Array#map, iterate over the array.
In every iteration, to get custom.projects, again using Array#map, iterate over the current projects array and using the second parameter (index) get the corresponding links:
const arr = [
{
title: "title 1",
projects: [ "project1", "project2", "project3", "project4", "project5", "project6" ],
project_links: ["link1", "link2", "link3", "link4", "link5", "link6"]
},
{
title: "title 2",
projects: ["project1", "project2", "project3"],
project_links: ["link1", "link2", "link3"]
},
{
title: "title 3",
projects: ["project1", "project2", "project3", "project4", "project5"],
project_links: ["link1", "link2", "link3", "link4", "link5"]
},
{
title: "title 4",
projects: ["project1", "project2", "project3", "project4", "project5"],
project_links: ["link1", "link2", "link3", "link4", "link5"]
},
{
title: "title 5",
projects: ["project1"],
project_links: ["link1"]
}
];
const res = arr.map(({ title, projects = [], project_links = [] }) => ({
title,
custom: {
projects: projects.map((project_name, i) => ({ project_name, link: project_links[i] }))
}
}));
console.log(res);

Related

javascript print nested array to screen

I have a data array, there are multiple objects in this array, and the data object is an array. There may be more than one object in this array. How can I copy these objects under a single array?
const test = []
const data = [
{
"_id": "124141",
"name": "test",
"data": [
{
"price":10,
"title": "sda"
},
]
},
{
"_id": "2525",
"name": "test2",
"data": [
{
"price":20,
"title": "asdas"
},
]
}
]
[{
"price":10,
"title": "sda"
},
{
"price":20,
"title": "asdas"
},
]
If this is the output I expect, it should be like this. how can I do that
const data = [
{
"_id": "124141",
"name": "test",
"data": [
{
"price":10,
"title": "sda"
},
{
"price":99,
"title":"aaaaa"
}
]
},
{
"_id": "2525",
"name": "test2",
"data": [
{
"price":20,
"title": "asdas"
},
]
}
];
console.log(data.map(e => e.data).flat());
// OR
console.log(data.flatMap(e => e.data));

Retrun whole path of all matching items in a nested array of objects

I'm having really tough time while searching a deeply nested array of objects and return the whole path of all matching items. I already found partial answer to my problem but that returns path of only the first matched item, Whereas i need path of all matched items.
Now I believe instead of articulating the problem further, The code itself would be more helpful here. For instance, I need to search string "sofa" in label field
The Input Data
{
"children":[
{
"label":"Home",
"key":"home",
"level":1,
"children":[
{
"label":"Furniture",
"key":"furniture",
"level":2,
"children":[
{
"label":"Chair",
"key":"chair",
"level":3
},
{
"label":"Table",
"key":"table",
"level":3
},
{
"label":"Lamp",
"key":"lamp",
"level":3
}
]
}
]
},
{
"label":"Outdoor",
"key":"outdoor",
"level":1,
"children":[
{
"label":"Furniture",
"key":"furniture",
"level":2,
"children":[
{
"label":"Trampoline",
"key":"trampoline",
"level":3
},
{
"label":"Swing",
"key":"swing",
"level":3
},
{
"label":"Large sofa",
"key":"large sofa",
"level":3
},
{
"label":"Medium Sofa",
"key":"mediumSofa",
"level":3
},
{
"label":"Small Sofa Wooden",
"key":"smallSofaWooden",
"level":3
}
]
},
{
"label":"Games",
"key":"games",
"level":2,
"children":[
]
}
]
},
{
"label":"Refurbrished Items",
"key":"refurbrished items",
"level":1,
"children":[
]
},
{
"label":"Indoor",
"key":"indoor",
"level":1,
"children":[
{
"label":"Electicity",
"key":"electicity",
"level":2,
"children":[
]
},
{
"label":"Living Room Sofa",
"key":"livingRoomSofa",
"level":2,
"children":[
]
}
]
}
]
}
**The Expected Output - Search for sofa **
{
"children":[
// if the object or any of its children label doesn't includes
//sofa remove the entire object itself
{
"label":"Outdoor",
"key":"outdoor",
"level":1,
"children":[
{
"label":"Indoor Furniture",
"key":"indoorFurniture",
"level":2,
"children":[ // Contains "sofa", Hence retrun path to its
root, the object itself and all children if any. Remove unmatched siblings
{
"label":"Large sofa",
"key":"large sofa",
"level":3
},
{
"label":"Medium Sofa",
"key":"mediumSofa",
"level":3
},
{
"label":"Small Sofa Wooden",
"key":"smallSofaWooden",
"level":3
}
]
}
]
},
{
"label":"Indoor",
"key":"indoor",
"level":1,
"children":[
{ // Contains "sofa", Hence retrun path to its
root, the object itself and all children if any. Remove
unmatched siblings
"label":"Living Room Sofa",
"key":"livingRoomSofa",
"level":2,
"children":[
]
}
]
}
]
}
**The Expected Output - Search for furniture **
{
"children":[
{
"label":"Home",
"key":"home",
"level":1,
"children":[
{ // Contains furniture, Hence retrun path to its
// root, the object itself and all children if any. Remove
// unmatched siblings
"label":"Indoor Furniture",
"key":"indoorFurniture",
"level":2,
"children":[
{
"label":"Chair",
"key":"chair",
"level":3
},
{
"label":"Table",
"key":"table",
"level":3
},
{
"label":"Lamp",
"key":"lamp",
"level":3
}
]
}
]
},
{
"label":"Outdoor",
"key":"outdoor",
"level":1,
"children":[
{ // Contains furniture, Hence retrun path to its
// root, the object itself and all children if any. Remove
// unmatched siblings
"label":"Outdoor Furniture",
"key":"outdoorFurniture",
"level":2,
"children":[
{
"label":"Trampoline",
"key":"trampoline",
"level":3
},
{
"label":"Swing",
"key":"swing",
"level":3
},
{
"label":"Large sofa",
"key":"large sofa",
"level":3
},
{
"label":"Medium Sofa",
"key":"mediumSofa",
"level":3
},
{
"label":"Small Sofa Wooden",
"key":"smallSofaWooden",
"level":3
}
]
}
]
}
]
}
What i have tried
function findChild(obj, condition) {
if (Object.entries(condition).every( ([k,v]) => obj[k] === v )) {
return obj;
}
for (const child of obj.children || []) {
const found = findChild(child, condition);
// If found, then add this node to the ancestors of the result
if (found) return Object.assign({}, obj, { children: [found] });
}
}
var search = { label: 'sofa' };
console.log(findChild(input, search));
//https://stackoverflow.com/a/48501349/10414881
// it return only the first matched item, but i need all of the
items
I would really appreciate any help. I'm really stuck here. Please help.
Hope this is what you are looking for:
const input = {
"children": [{
"name": "test",
"title": "test 1",
"id": "t1",
"children": [
]
},
{
"name": "test",
"title": "test 2",
"id": "t2",
"children": [{
"name": "Dummy 1",
"title": "dummy",
"id": "dummy1",
"children": [
]
},
{
"name": "Dummy 2",
"title": "dummy2",
"id": "dummy2",
"children": [{
"name": "Dummy 2.1",
"title": "dummy2.1",
"id": "dummy2.1",
"children": [
]
}]
}
]
},
{
"name": "home 1",
"title": "home 1",
"id": "h1",
"children": [{
"name": "room 1",
"title": "room 1",
"id": "room1",
"children": [{
"name": "Dummy 4.1",
"title": "dummy4.1",
"id": "dummy4.1",
"children": [
]
},
{
"name": "test",
"title": "test 4",
"id": "test4",
"children": [
]
}
]
}]
},
{
"name": "home 2",
"title": "home 2",
"id": "h2",
"children": [{
"name": "room 2",
"title": "room 2",
"id": "room2",
"children": [{
"name": "Dummy 5.1",
"title": "dummy5.1",
"id": "dummy5.1",
"children": [
]
},
{
"name": "test",
"title": "test 6",
"id": "test6",
"children": [
]
},
{
"name": "test",
"title": "test 7",
"id": "test7",
"children": [
]
}
]
}]
},
{
"name": "home 3",
"title": "home 3",
"id": "h3",
"children": [{
"name": "room 2",
"title": "room 2",
"id": "room2",
"children": [{
"name": "Dummy 5.1",
"title": "dummy5.1",
"id": "dummy5.1",
"children": [
]
},
{
"name": "test",
"title": "test 6",
"id": "test6",
"children": [
]
},
{
"name": "computer",
"title": "computer1",
"id": "computer1",
"children": [{
"name": "Dummy 7.1",
"title": "dummy7.1",
"id": "dummy7.1",
"children": [
]
},
{
"name": "test",
"title": "test 10",
"id": "test10",
"children": [
]
}
]
}
]
}]
}
]
}
function findChild(obj, condition) {
if (Object.entries(condition).every(([k, v]) => obj[k] === v)) {
return obj;
}
const children = []
if (obj.children.length > 0) {
for (const child of obj.children) {
const found = findChild(child, condition);
// If found, then add this node to the ancestors of the result
if (found)
children.push(found);
}
obj.children = children;
return obj;
}
return null;
}
var search = {
name: 'test'
};
console.dir(findChild(input, search), {
depth: null
});

Filter inside a nested array with objects

I have an array that contains three book objects. Each book object has an array of bookIds . I want to filter by bookId (3,1) in a fast and efficient way since my array will grow up easly in the future. I tried with map, but it change my original array even with a deepCopy ! Is there a way to use the filter function instead without using recursivity ?
this.booksList =
[
{
"books": [
{
"bookId": 3
},
{
"bookId": 2
}
],
"id": 1,
"name": "Name 1",
"description": "desc 1"
},
{
"books": [
{
"bookId": 5
},
{
"bookId": 2
}
],
"id": 2,
"name": "Name 2",
"description": "desc 2"
},
{
"books": [
{
"bookId": 1
},
{
"bookId": 3
}
],
"id": 3,
"name": "Name 3",
"description": "desc 3"
}
]
The map approach :
let results = this.books.map(function (book) {
book.books = book.books.filter(x => x.bookId == 1 || x.bookId == 3);
return book;
}).filter(({ books }) => books.length);
Result with map : not expected result !
[
{
"books": [
{
"bookId": 3
}
],
"id": 1,
"name": "Name 1",
"description": "desc 1"
},
{
"books": [
{
"bookId": 1
},
{
"bookId": 3
}
],
"id": 3,
"name": "Name 3",
"description": "desc 3"
}
]
expected results :
[
{
"books": [
{
"bookId": 3
},
{
"bookId": 2
}
],
"id": 1,
"name": "Name 1",
"description": "desc 1"
},
{
"books": [
{
"bookId": 1
},
{
"bookId": 3
}
],
"id": 3,
"name": "Name 3",
"description": "desc 3"
}
]
Thanks,
I think you are looking for filter and some -
const input =
[{books:[{bookId:3},{bookId:2}],id:1,name:"Name 1",description:"desc 1"},{books:[{bookId:5},{bookId:2}],id:2,name:"Name 2",description:"desc 2"},{books:[{bookId:1},{bookId:3}],id:3,name:"Name 3",description:"desc 3"}]
const query =
[3, 1]
const result =
input.filter(({ books = [] }) =>
books.some(({ bookId = null }) => query.includes(bookId))
)
console.log(JSON.stringify(result, null, 2))
Output -
[
{
"books": [
{
"bookId": 3
},
{
"bookId": 2
}
],
"id": 1,
"name": "Name 1",
"description": "desc 1"
},
{
"books": [
{
"bookId": 1
},
{
"bookId": 3
}
],
"id": 3,
"name": "Name 3",
"description": "desc 3"
}
]
const booksList=[
{books:[{bookId:3},{bookId:2}],id:1,name:"Name 1",description:"desc 1"},
{books:[{bookId:5},{bookId:2}],id:2,name:"Name 2",description:"desc 2"},
{books:[{bookId:1},{bookId:3}],id:3,name:"Name 3",description:"desc 3"},
];
const byBookIDs = (...IDs) =>
booksList.filter(b => b.books.some(b => IDs.includes(b.bookId)));
console.log(byBookIDs(1, 3));
MDN Array Filter - to return a subset
MDN Array Some - to match (and return) as soon as some
MDN Array Includes - to find item in array

Exclude items from Array.map()

I am trying to exclude items that contain Packages in packageData.type. To show only the packageData that has items with packageData.type as Add-on.
Array is as example
{
"packageData": [
{
"title": "Title 1",
"type": [
"Packages"
]
},
{
"title": "Title 2",
"type": [
"Add-on"
]
},
{
"title": "Title 3",
"type": [
"Add-on"
]
},
{
"title": "Title 4",
"type": [
"Add-on"
]
}
]
}
and this is how I am currently trying to remove results which is giving zero results.
<ul>
{packageData.map(function() {
if (packageData.type ==! "Packages") {
return (
<li key={packageData.id}>
<a>
<img src={packageData.heroImage.sizes.src} alt=""/>
<h3>{packageData.title}</h3>
</a>
</li> );
} else {
return null;
};
})}
</ul>
How can I make this work? Or should I be filtering these results prior to displaying and then map the returned items?
You have to use filter before map, Filter will filter the array and then map will iterate through array. Below is the sample code
var data = {
"packageData": [
{
"title": "Title 1",
"type": [
"Packages"
]
},
{
"title": "Title 2",
"type": [
"Add-on"
]
},
{
"title": "Title 3",
"type": [
"Add-on"
]
},
{
"title": "Title 4",
"type": [
"Add-on"
]
}
]
};
data.packageData.filter((item) => { return item.type[0] !== 'Packages' }).map((item)=> { console.log(item); });

Merging Two Objects with arrays inside of it

I'm trying to merge two javascript objects that has inside of it arrays and other elements. Let me give you an example.
{
"addresses": [
{
"type": "email",
"tags": [
"Responsável",
"Pai"
],
"address": "johndoepai1#gmail.com"
},
{
"type": "phone",
"tags": [
"Responsável",
"Mãe"
],
"address": "551138839332"
},
{
"type": "email",
"tags": [
"Mãe"
],
"address": "johndoemae1#gmail.com"
},
{
"type": "email",
"tags": [
"Aluno"
],
"address": "johndoealuno1#gmail.com"
}
],
"class": [
"Sala 1",
"Sala 2",
"Sala 3"
],
"fullname": "John Doe 1",
"eid": "2",
"invisible": true,
"see_all": false
},
{
"addresses": [
{
"type": "email",
"tags": [
"Responsável",
"Pai"
],
"address": "johndoepai2#gmail.com"
},
{
"type": "email",
"tags": [
"Responsável",
"Pai"
],
"address": "johndoepai3#gmail.com"
},
{
"type": "phone",
"tags": [
"Pai"
],
"address": "5519985504400"
},
{
"type": "phone",
"tags": [
"Responsável",
"Mãe"
],
"address": "551138839333"
},
{
"type": "email",
"tags": [
"Mãe"
],
"address": "11 983340440"
},
{
"type": "email",
"tags": [
"Aluno"
],
"address": ""
}
],
"class": [
"Sala 4",
"Sala 5",
"Sala 6"
],
"fullname": "John Doe 1",
"eid": "2",
"invisible": false,
"see_all": true
}
As you can see, we can have arrays inside with some strings in those arrays.
I've tried to do it using some recursion, but had no success.
function mergeObjects(target, source){
var item, tItem, o, idx;
if (typeof source == 'undefined') {
return source;
} else if (typeof target == 'undefined') {
return target;
}
for (var prop in source) {
item = source[prop];
//check if the first element is indeed an object.
if (typeof item == 'object' && item !== null) {
//if the first item is an array
if (_.isArray(item) && item.length) {
//dealing with array of primitives
if (typeof item[0] != 'object') {
item.forEach(function(conteudo){
//push to the target all the elements;
target[prop].push(conteudo);
});
}else{
//dealing with array of objects;
for(var attr in item){
idx = {};
tItem = target[attr]
mergeObjects(tItem,item);
}
}
}//if its a normal object
else {
// deal with object
mergeObjects(target[prop],item);
}
} else {
// item is a primitive, just copy it over
target[prop] = item;
}
}
return target;
}
I Expected this:
{
"addresses": [
{
"type": "email",
"tags": [
"Responsável",
"Pai"
],
"address": "johndoepai2#gmail.com"
},
{
"type": "email",
"tags": [
"Responsável",
"Pai"
],
"address": "johndoepai3#gmail.com"
},
{
"type": "phone",
"tags": [
"Pai"
],
"address": "5519985504400"
},
{
"type": "phone",
"tags": [
"Responsável",
"Mãe"
],
"address": "551138839333"
},
{
"type": "email",
"tags": [
"Mãe"
],
"address": "11 983340440"
},
{
"type": "email",
"tags": [
"Aluno"
],
"address": ""
}
],
"class": [
"Sala 4",
"Sala 5",
"Sala 6",
"Sala 1",
"Sala 2",
"Sala 3"
],
"fullname": "John Doe 1",
"eid": "2",
"invisible": true,
"see_all": false
}
"fullname": "John Doe 1",
"eid": "1234",
"classes": [
"Sala 1",
"Sala 2",
"Sala 3",
"Sala 4",
"Sala 5",
"Sala 6"
],
"addresses": [{
"type": "phone",
"tags": [
"Responsável",
"Mãe"
],
"address": "551138839332"
}, {
"type": "email",
"tags": [
"Mãe"
],
"address": "johndoemae1#gmail.com"
}, {
"type": "email",
"tags": [
"Aluno"
],
"address": "johndoealuno1#gmail.com"
}, {
"type": "email",
"tags": [
"Responsável",
"Pai"
],
"address": "johndoepai2#gmail.com"
}, {
"type": "email",
"tags": [
"Responsável",
"Pai"
],
"address": "johndoepai3#gmail.com"
}, {
"type": "phone",
"tags": [
"Pai"
],
"address": "5519985504400"
}, {
"type": "phone",
"tags": [
"Responsável",
"Mãe"
],
"address": "551138839333"
}],
"invisible": true,
"see_all": true
}
But what i got was this, as you can see, some email elements are missing.
{
"addresses": [
{
"type": "email",
"tags": [
"Responsável",
"Pai"
],
"address": "johndoepai2#gmail.com"
},
{
"type": "email",
"tags": [
"Responsável",
"Pai"
],
"address": "johndoepai3#gmail.com"
},
{
"type": "phone",
"tags": [
"Pai"
],
"address": "5519985504400"
},
{
"type": "phone",
"tags": [
"Responsável",
"Mãe"
],
"address": "551138839333"
},
{
"type": "email",
"tags": [
"Mãe"
],
"address": "11 983340440"
},
{
"type": "email",
"tags": [
"Aluno"
],
"address": ""
}
],
"class": [
"Sala 4",
"Sala 5",
"Sala 6",
"Sala 1",
"Sala 2",
"Sala 3"
],
"fullname": "John Doe 1",
"eid": "2",
"invisible": true,
"see_all": false
}
Order of elements is not a problem.
Which point of the recursion tree did i miss?
Short answer: you have to merge the arrays yourself first. Or you can use something nice like Lodash's mergeWidth Ramda's R.mergeWith (see below for sample code for Ramda).
You want something like the native Object.assign (limited browser support, so it will have to be polyfilled) or whatever merge your JS library has.
The problem you're running into is how all of these merge implementations handle duplicate keys. Usually the key will be set to the last value passed in:
var thing1 = {
someProperty: 'foo'
};
var thing2 = {
someProperty: 'bar'
};
var result1 = Object.assign({}, thing1, thing2);
// -> {someProperty: 'bar'} (set to the last value passed in, in thing2)
var result2 = Object.assign({}, thing2, thing1);
// -> {someProperty: 'foo'} (again set to the last value passed in, in thing1)
// Make the Stackoverflow snippet display the output.
document.body.innerHTML += JSON.stringify(result1, null, 2);
document.body.innerHTML += '<br>' + JSON.stringify(result2, null, 2);
Works the same way with your example, except the property is a more complicated array. It's just being set to the last array passed in:
var thing1 = {
someList: [1, 2, 3]
};
var thing2 = {
someList: [4, 5, 6]
};
var result = Object.assign({}, thing1, thing2);
// -> {someList: [4, 5, 6]}
// Make the Stackoverflow snippet display the output.
document.body.innerHTML = JSON.stringify(result, null, 2);
If you use something nice like Ramda, you can merge and specify a function to control the behavior when keys are equal, like in your case. Here we can check if the value is an array, then concatenate if so. Otherwise, return the latest value (as described above):
var thing1 = {someList: [1, 2, 3]};
var thing2 = {someList: [4, 5, 6]};
var dupeMergeFn = function(a, b) {
return (Array.isArray(a)) ? a.concat(b) : b;
};
var result = R.mergeWith(dupeMergeFn, thing1, thing2);
// Make the Stackoverflow snippet display the output.
document.body.innerHTML = JSON.stringify(result, null, 2);
<script src="//cdnjs.cloudflare.com/ajax/libs/ramda/0.19.1/ramda.min.js"></script>

Categories

Resources