Converting object format in Javascript - javascript

I have an input array of objects, which each object has the following format:
{
titleID: string,
titleName: string,
1af23_red: number,
45ua6_blue: number
}
What I know is that:
In every object, there will be always the keys titleID and titleName and then I will have several keys that have the format number_string.
The titleID and titleName values will be different among the different objects
The rest of the keys (1af23_red, 45ua6_blue, etc) will be the same in all objects and they will all have the same format 'id_name' So, if the first object has 1af23_red and 45ua6_blue as keys, all the rest will also have just those keys.
The type of array that I want back has the following format:
{
color: {
id
name
},
data: Array<
{
title: {
id
name
},
rating
}
>
}
So, example of input:
[
{
titleId: 'a',
titleName: 'atitle',
'1af_red': 50
'ba2_blue': 40
},
{
titleId: 'b',
titleName: 'btitle',
'1af_red': 30
'ba2_blue': null
},
{
titleId: 'c',
titleName: 'ctitle',
'1af_red': null
'ba2_blue': 10
}
]
I would expect back:
[
{
color: {
id: '1af',
name: 'red'
},
data: [
{
title: {
id: 'a',
name: 'atitle',
},
rating: 50
},
{
title: {
id: 'b',
name: 'btitle',
},
rating: 30
},
{
title: {
id: 'c',
name: 'ctitle',
},
rating: null
}
]
},
{
color: {
id: 'ba2',
name: 'blue'
},
data: [
{
title: {
id: 'a',
name: 'atitle',
},
rating: 40
},
{
title: {
id: 'b',
name: 'btitle',
},
rating: null
},
{
title: {
id: 'c',
name: 'ctitle',
},
rating: 10
}
]
}
]
I have tried doing this conversion with map and reduce but I am stuck. Is there an easy way to accomplish this?

Here you go.
Brief logic : Getting all the keys from the object at 0th index from data array. Looping over the keys, if key contains '_', pick the key, break it to form id and name pair, then map over all the data objects, get the score for that key and append it to the object with id and name values. Finally append this object to result array. Doing this for all the keys which contains '_'.
const data = [
{
titleId: 'a',
titleName: 'atitle',
'1af_red': 50,
'ba2_blue': 40
},
{
titleId: 'b',
titleName: 'btitle',
'1af_red': 30,
'ba2_blue': null
},
{
titleId: 'c',
titleName: 'ctitle',
'1af_red': null,
'ba2_blue': 10
}
];
const keys = Object.keys(data[0]);
const result = []
keys.map(key=> {
if(key.indexOf('_')!==-1){
const item = {}
const keyData = key.split('_')
item.color = {
id : keyData[0],
name : keyData[1]
}
item.data = []
data.map(obj => {
const newObj = {}
newObj.title = {
id : obj.titleId,
name : obj.titleName
}
newObj.rating = obj[key];
item.data.push(newObj);
});
result.push(item);
}
});
console.log(result);

You could try that
let elements = [
{
titleId: 'a',
titleName: 'atitle',
'1af_red': 50,
'ba2_blue': 40
},
{
titleId: 'b',
titleName: 'btitle',
'1af_red': 30,
'ba2_blue': null
},
{
titleId: 'c',
titleName: 'ctitle',
'1af_red': null,
'ba2_blue': 10
}
]
let colors = []
let result = []
elements.forEach(currElem => {
for(let attr in currElem){
if(attr != "titleId" && attr != "titleName"){
let color = attr.split("_")
if(!colors.some(currColor => {return currColor == color[1]})){
colors.push({
"id": color[0],
"name": color[1]
})
}
}
}
})
colors.forEach(currColor => {
result.push({
"color" : currColor,
"data": []
})
elements.forEach(currElement => {
for(let attr in currElement){
let color = []
if(attr != "titleId" && attr != "titleName"){
color = attr.split("_")
if(color[1] == currColor.name){
for(let i=0; i<result.length;i++){
if(result[i].color.name == color[1]){
result[i].data.push({
"title" : {
"id": currElement.titleId,
"name": currElement.titleName
},
"rating":currElement[attr]
})
break
}
}
}
}
}
})
})
console.log(result)

Related

JavaScript: Get non-repeating items from 2d array of objects

Compare 2d array of objects and convert it into single array of objects by getting the unique items (non-repeating in terms of id) using Javascript.
Sample input:
const data = [
[ { name: 'x', id: 1 }, { name: 'a', id: 13 }, { name: 'a', id: 14 }, { name: 'a', id: 15 }, { name: 'a', id: 16 } ],
[ { name: 'y', id: 12 }, { name: 'a', id: 13 }, { name: 'a', id: 14 }, { name: 'a', id: 15 }, { name: 'a', id: 16 } ],
[ { name: 'z', id: 22 }, { name: 'a', id: 13 }, { name: 'a', id: 14 }, { name: 'a', id: 15 }, { name: 'a', id: 16 } ]
];
Expected output:
const out = [
{ name: 'a', id: 1 },
{ name: 'b', id: 12 },
{ name: 'b', id: 22 }
]
Using Array#flat, convert the 2d array into one
Using Array#reduce, iterate over the latter while updating a Map where the id is the key and the count is the value
Using Map#entries, get the list of id-count pairs from the Map. Then, using Array#filter, get the ids whose count is 1. Finally, using Array#map, get the list of resulting ids
Using Array#filter, iterate over the flattened array of objects and return the elements whose ids belong to the non-repeating ids list
const data = [
[ { name: 'x', id: 1 }, { name: 'a', id: 13 }, { name: 'a', id: 14 }, { name: 'a', id: 15 }, { name: 'a', id: 16 } ],
[ { name: 'y', id: 12 }, { name: 'a', id: 13 }, { name: 'a', id: 14 }, { name: 'a', id: 15 }, { name: 'a', id: 16 } ],
[ { name: 'z', id: 22 }, { name: 'a', id: 13 }, { name: 'a', id: 14 }, { name: 'a', id: 15 }, { name: 'a', id: 16 } ]
];
const arr = data.flat();
const idCountMap = arr.reduce((map, { id }) => map.set(id, (map.get(id) ?? 0) + 1), new Map);
const nonRepeatingIds =
[...idCountMap.entries()]
.filter(([ id, count ]) => count === 1)
.map(([ id ]) => id);
const nonRepeatingItems = arr.filter(({ id }) => nonRepeatingIds.includes(id));
console.log(nonRepeatingItems);
You can do this by converting the use case in two parts.
Part 1 : Concat the array of objects to a new array
var array = [];
data.forEach(val => {
array = [...array, ...val];
});
Part 2 : Find the unique values in the new array
const result = [];
const map = new Map();
for (const item of array) {
if(!map.has(item.id)){
map.set(item.id, true); // set any value to Map
result.push({
id: item.id,
name: item.name
});
}
}
console.log(result)
you have to loop the array of array and check if you already have added the id or not. In this way you can make the id unique in the result
const data= [
[{name:"x" , id:1},{name:"a" , id:13},{name:"a" , id:14},{name:"a" , id:15},{name:"a" , id:16},],
[{name:"x" , id:1},{name:"a" , id:13},{name:"a" , id:14},{name:"a" , id:15},{name:"a" , id:16},],
[{name:"x" , id:1},{name:"a" , id:13},{name:"a" , id:14},{name:"a" , id:15},{name:"a" , id:16},]
]
//loop for each array and filter
var addedId = [];
//init result
var out = [];
//loop array
data.forEach(function(arr){
//loop element in array
arr.forEach(function(obj){
// check if the id has been already added to the result
if(!addedId.includes(obj.id)){
addedId.push (obj.id);
out.push(obj);
}
})
})

How to update a value in nested array based on the given index and return original array in javascript?

I have an index '3_1_0' and the following array:-
var fields = [
{
name: 'a'
},
{
name: 'b'
},
{
name: 'c'
},
{
name: 'd',
fields: [
{
name: 'd1'
},
{
name: 'd2',
fields: [
{
name: 'd2.1'
}
]
}
]
}
]
I need to extract the element from the above fields array based on the index. so 3_1_0 will extract following
{
name: 'd2.1'
}
Update the value from d2.1 to some other value like 'new_d2.1' and attach the updated value at the same index in original fields array and return the updated fields array. How this can be done?
You can use Array.reduce to get the desired result. We start by splitting the index into an array, then reducing to get the result.
We'll use some Optional Chaining to ensure we'll return undefined if no value is found (say our index was '7_10_20').
Once we've found our object, we can set the required property.
const fields = [ { name: 'a' }, { name: 'b' }, { name: 'c' }, { name: 'd', fields: [ { name: 'd1' }, { name: 'd2', fields: [ { name: 'd2.1' } ] } ] } ];
const index = '3_1_0'
function setValue(fields, index, property, value) {
const obj = index.split('_').reduce((acc, key) => {
return acc?.[key] || acc?.fields?.[key];
}, fields);
// Only update if we actually find anything
if (obj) {
obj[property] = value
}
}
setValue(fields, '3_1_0', 'name', 'new_d2.1');
console.log("Fields:", fields);
const data = [{ name: 'a' }, { name: 'b' }, { name: 'c' }, { name: 'd', fields: [ { name: 'd1' }, { name: 'd2', fields: [ { name: 'd2.1' } ] } ] } ];
let givenIdxs = "3_1_0";
let indexes = givenIdxs.split("_");
let result = data[indexes[0]];
for(let idx = 1; idx < indexes.length; idx++){
result = result.fields[indexes[idx]];
}
console.log(result);

Filter Array of Objects with a Object reside in Nested Array property

I have the following use-case,
I have,
An array of objects that contains a list of courses
An array of objects that contains students with a nested array: studies
I need to find a courses which are not studied by any student.
How to achieve that?
follow is the code sinnpient.
let courses = [
{ id: 'A' },
{ id: 'B' },
{ id: 'C' },
{ id: 'D' }, <-- not studied by any one
{ id: 'E' },
{ id: 'F' }, <-- not studied by any one
];
let students = [
{
name: 'STD1',
study: [
{ id: 'A' },
{ id: 'C' }
]
},
{
name: 'STD2',
study: [
{ id: 'B' },
{ id: 'E' }
]
}
];
expected output
const notUsedCourse = [{ id: 'D' }, { id: 'F' }];
You can save course ids which have been studied by students into a Set so that we can check if a course has been studied later.
The advantage over the solution with filter and some combination is that this solution will be much faster when the size of courses and students gets bigger since the former has the time complexity of O(n^3) .
const courses = [
{ id: 'A' },
{ id: 'B' },
{ id: 'C' },
{ id: 'D' },
{ id: 'E' },
{ id: 'F' },
];
const students = [
{
name: 'STD1',
study: [
{ id: 'A' },
{ id: 'C' }
]
},
{
name: 'STD2',
study: [
{ id: 'B' },
{ id: 'E' }
]
}
];
const usedCourseIds = new Set(students.flatMap(student => student.study).map(course => course.id));
const notUsedCourses = courses.filter(course => !usedCourseIds.has(course.id));
console.log(notUsedCourses);
You can use .filter with .some to loop through and search if a student has the course:
let courses = [
{ id: 'A' },
{ id: 'B' },
{ id: 'C' },
{ id: 'D' },
{ id: 'E' },
{ id: 'F' },
];
let students = [
{
name: 'STD1',
study: [
{ id: 'A' },
{ id: 'C' }
]
},
{
name: 'STD2',
study: [
{ id: 'B' },
{ id: 'E' }
]
}
];
let notUsedCourse = courses.filter(
course => !students.some(
student => student.study.some(
study => study.id === course.id
)
)
);
console.log(notUsedCourse);
You could get the visited courses first and then filter all courses.
var courses = [{ id: 'A' }, { id: 'B' }, { id: 'C' }, { id: 'D' }, { id: 'E' }, { id: 'F' }],
students = [{ name: 'STD1', study: [{ id: 'A' }, { id: 'C' }] }, { name: 'STD2', study: [{ id: 'B' }, { id: 'E' }] }],
seen = students.reduce(
(seen, { study }) => study.reduce((s, { id }) => s.add(id), seen),
new Set
),
missing = courses.filter(({ id }) => !seen.has(id));
console.log(missing)

how to transform or sort array against different array?

const r = ['a', 'b', 'c', 'l', 'p'];
const arr = [{
name: "ss3",
id: 'c'
}, {
name: "ss2",
id: 'b'
}, {
name: "ss4",
id: 'p'
}, {
name: "ss1",
id: 'a'
}]
var newArray =arr.map((i)=>{
let e = r[i];
if(i.id===e){
return i
}
})
console.log(newArray)
Expected output
const arr = [{
name: "ss1",
id: 'a'
}, {
name: "ss2",
id: 'b'
}, {
name: "ss3",
id: 'c'
}, {
name: "ss4",
id: 'p'
}
]
Given two arrays r and arr, I wish to sort arr with respect to r, i.e. in alphabetical order by id.
https://jsbin.com/yitijiboso/edit?html,js,output
I think this might be a concise (although not very performant) way to achieve the desired output:
const arr1 = ['a', 'b', 'c', 'l', 'p'];
const arr2 = [
{
name: "ss3",
id: 'c'
},
{
name: "ss2",
id: 'b'
}, {
name: "ss4",
id: 'p'
},
{
name: "ss1",
id: 'a'
}
];
arr2.sort((a, b) => arr1.indexOf(a.id) - arr1.indexOf(b.id));
console.log(arr2);
Easy:
make a map from main 'arr' keyBy 'id' https://www.npmjs.com/package/lodash.keyby
loop across 'r', if key exist in new map, get value and push to new array
const arrMap = _.keyBy(arr, 'id');
let newR = [];
r.forEach( key => {
if ( arrMap[key] ) {
newR.push( arrMap[key] );
}
} );
console.log( 'new array', newR );
Taking a clue from #Petr Broz, here's my suggestion:
const r = ['a', 'b', 'c', 'l', 'p'];
const arr = [
{
name: "ss3",
id: 'c'
},
{
name: "ss2",
id: 'b'
}, {
name: "ss4",
id: 'p'
},
{
name: "ss1",
id: 'a'
}
];
arr.sort((a, b) => r.indexOf(a.id) > r.indexOf(b.id));
console.log(arr);
Main difference is that this code utilizes the arrays as named by the OP and uses a greater than comparison operator. However, if you just want to have the array arr sorted in alphabetical order you don't need to compare it with array r:
const arr = [
{
name: "ss3",
id: 'c'
},
{
name: "ss2",
id: 'b'
}, {
name: "ss4",
id: 'p'
},
{
name: "ss1",
id: 'a'
}
];
arr.sort(function(a, b)
{
if (a.id > b.id) {
return 1;
}
else
if (a.id < b.id) {
return -1;
}
else
{
return 0;
}
});
console.log(arr);
Note, in this example the return values are numeric instead of boolean values which would be helpful if the array to be sorted were to have duplicate values.

JavaScript operation array object merge

I have two arrays, and now I want to merge the two arrays.
The first array:
var data = [
{ name: 'aa', value: 1 },
{ name: 'bb', value: 2 },
{ name: 'cc', value: 3 }
];
Two arrays:
var data2 = [
{ name: 'aa' },
{ name: 'bb' },
{ name: 'cc' },
{ name: 'dd' },
{ name: 'ee' }
];
I want to merge them into this:
var data3 = [
{name: 'aa', value: 1},
{name: 'bb', value: 2},
{name: 'cc', value: 3},
{name: 'dd', value: 0},
{name: 'ee', value: 0}
];
console.log(data3)
At present, my experience is not enough. Please help me solve this problem.
Thanks in advance.
You can try following based on following assumptions
data2 is a collection of names and expecting its length to be always more than length of data
Order of objects can be different
var data = [
{ name: 'aa', value: 1 },
{ name: 'bb', value: 2 },
{ name: 'cc', value: 3 }
];
var data2 = [
{ name: 'aa' },
{ name: 'bb' },
{ name: 'cc' },
{ name: 'dd' },
{ name: 'ee' }
];
// Iterate over the names array
var data3 = data2.map(({name}) => {
// get the matched object in data corresponding to the name
var match = data.find((obj) => obj.name === name);
// if found, return value else default value to 0
return match ? match : {name, value : 0};
});
console.log(data3);
If the input arrays are indeed in order like that, then a simple .map would suffice:
var data = [
{ name: 'aa', value: 1 },
{ name: 'bb', value: 2 },
{ name: 'cc', value: 3 }
];
var data2 = [
{ name: 'aa' },
{ name: 'bb' },
{ name: 'cc' },
{ name: 'dd' },
{ name: 'ee' }
];
const output = data2.map(({ name }, i) => ({ name, value: data[i] ? data[i].value : 0 }));
console.log(output);
Create an object lookup for each name using array#reduce. Extract all the values using the Object.values() from the object lookup.
const data1 = [ { name: 'aa', value: 1 }, { name: 'bb', value: 2 }, { name: 'cc', value: 3 } ],
data2 = [ { name: 'aa' }, { name: 'bb' }, { name: 'cc' }, { name: 'dd' }, { name: 'ee' } ],
result = Object.values([data1, data2].reduce((r,a) => {
a.forEach(({name, value = 0}) => {
r[name] = name in r ? r[name] : {name, value};
});
return r;
},{}));
console.log(result);
You can array#concat both the arrays and using array#reduce create an object lookup and then get all the values using the Object.values().
const data1 = [ { name: 'aa', value: 1 }, { name: 'bb', value: 2 }, { name: 'cc', value: 3 } ],
data2 = [ { name: 'aa' }, { name: 'bb' }, { name: 'cc' }, { name: 'dd' }, { name: 'ee' } ],
result = Object.values(data1.concat(data2).reduce((r,{name, value=0}) => {
r[name] = name in r ? r[name] : {name, value};
return r;
},{}));
console.log(result);
var data = [
{ name: 'aa', value: 1 },
{ name: 'bb', value: 2 },
{ name: 'cc', value: 3 }
];
var data2 = [
{ name: 'aa' },
{ name: 'bb' },
{ name: 'cc' },
{ name: 'dd' },
{ name: 'ee' }
];
let output = new Array(data2.length).fill(data2.length).map(v => new Object());
// Logic
data.forEach((val2)=> {
data2.forEach((val, i)=> {
if (val.name == val2.name){
output[i]["name"] = val.name
output[i]["value"] = val2.value
} else{
output[i]["name"] = val.name
}
})
})
output.map((val,i) => {
if (!val.hasOwnProperty("value")){
console.log(val)
val["value"] = 0
}
})
console.log("------Your Expected Format", output)

Categories

Resources