Need help in transformation logic of Javascript array - javascript

I have an JS array of objects as below:
[
{
key1:"value1",
key2:"value2",
key3:"value3"
},
{
key1:"value1",
key2_updated:"value2_updated",
key3_updated:"value3_updated"
}
]
Post transformation , it must be of type object as below:
{
value1: {
key2:"value2",
key3:"value3",
key2_updated:"value2_updated",
key3_updated:"value3_updated"
}
}
Notice In array , first key-value of each object is same and hence i wanted to merge them and create new object with value1:mergecontent and if it is not same ,, then create new k-v in same object.

Group the array of object by key1 first, then assign the attributes
var data = [
{
key1:"value1",
key2:"value2",
key3:"value3"
},
{
key1:"value1",
key2_updated:"value2_updated",
key3_updated:"value3_updated"
},
{
key1:"value2",
key2_updated:"value2_updated",
key3_updated:"value3_updated"
}
];
var result = data.reduce((x, v) => {
x[v.key1] = x[v.key1] || {}
const { key1, ...res } = v
x[v.key1] = Object.assign(x[v.key1], res)
return x
}, {})
var newResult = data.reduce((x, v) => {
x[v.key1] = x[v.key1] || {}
const { key1, ...res } = v
var newObj = {}
var currentKey
for (let [key, value] of Object.entries(res)) {
if (currentKey) {
newObj[currentKey] = value;
currentKey = null;
} else {
newObj[value] = "";
currentKey = value
}
}
x[v.key1] = Object.assign(x[v.key1], newObj)
return x
}, {})
function transform(d, k){
return d.reduce((x, v) => {
x[v[k]] = x[v[k]] || {}
const { key1, ...res } = v
var newObj = {}
var currentKey
for (let [key, value] of Object.entries(res)) {
if (currentKey) {
newObj[currentKey] = value;
currentKey = null;
} else {
newObj[value] = "";
currentKey = value
}
}
x[v[k]] = Object.assign(x[v[k]], newObj)
return x
}, {})
}
console.log(transform(data, "key1"))

Related

How to recursively loop through an object in javascript and sum all the values?

If this is my object
{
"a":{
"a1":5,
"b":{
"b1":10,
"b2":15,
"c":{
"c1":15
}
}
}
}
the output I want is:
{a:45 b:40, c: 15}
c => 15
b => 10 + 15 + c
a => 5 + b + c
how do I achieve this? been banging my head against a brick wall all day
so far I've tried:
let constructedTotals = {};
const calculateVals = (vals) => {
return vals
.map((val) => {
if (typeof val === "object" && Object.keys(val).length > 0) {
return Object.values(val);
}
return val;
})
.flatMap((x) => x)
.filter((x) => typeof x === "number")
.reduce((a, b) => a + b, 0);
};
const constructing = (construct) => {
return Object.entries(construct).map((entry) => {
if (typeof entry[1] === "object") {
constructing(entry[1]);
constructedTotals = {
...constructedTotals,
[entry[0]]: calculateVals(Object.values(entry[1])),
};
} else {
console.log('here')
}
});
};
const data = {
a: {
a1: 5,
b: {
b1: 10,
b2: 15,
c: {
c1: 15,
},
},
},
};
const outputObj = {};
function addValue(data) {
for (const [key, value] of Object.entries(data)) {
const outKey = key.at(0);
outputObj[outKey] ??= 0;
if (typeof value === "object") addValue(value);
else for (const svKey in outputObj) outputObj[svKey] += value;
}
}
addValue(data);
console.log(outputObj);
You could handover the parent key and add the total of nested keys.
const
sum = (object, parent = '') => Object
.entries(object)
.reduce((r, [k, v]) => {
if (v && typeof v === 'object') {
Object.assign(r, sum(v, k));
if (parent) r[parent] += r[k];
} else {
r[parent] = (r[parent] || 0) + v;
}
return r;
}, {}),
data = { a: { a1: 5, b: { b1: 10, b2: 15, c: { c1: 15 } } } },
result = sum(data);
console.log(result);
You could create a reducer function that:
Builds an object by key
Accumulates the total of the numbered keys for each node, and adds the previous total
const main = () => {
const result = reduce(tree, (acc, node) => {
let currKey, prevKey, currVal = 0;
for (const prop in node) {
const [, key] = prop.match(/^(\w)\d$/) ?? [];
currKey ??= key;
if (key) currVal += +node[prop];
prevKey ??= prop.match(/^(\w)$/)?.[1];
}
if (currKey) {
acc[currKey] = (acc[prevKey] ?? 0) + currVal;
}
});
console.log(result); // { "c": 15, "b": 40, "a": 45 }
};
const reduce = (node, visitor) => {
const result = {};
traverse(node, visitor, result);
return result;
};
const traverse = (node, visitor, result) => {
if (typeof node === 'object') {
for (const prop in node) {
traverse(node[prop], visitor, result);
}
}
visitor(result, node);
};
const tree = {
a: {
a1: 5,
b: {
b1: 10,
b2: 15,
c: {
c1: 15
}
}
}
};
main();
.as-console-wrapper { top: 0; max-height: 100% !important; }
you can try this:
let obj = {
"a":{
"a1":5,
"b":{
"b1":10,
"b2":15,
"c":{
"c1":15
}
}
}
}
let recusive = (obj,output)=>{
if(typeof(obj) == "object"){
let keys = Object.keys(obj)
let sum = 0;
keys.forEach(key => {
if(typeof(obj[key]) == "object"){
output[key] = recusive(obj[key],output)
sum += output[key]
}
else
sum+= obj[key]
});
return sum
}
else
return obj;
}
let warp = (obj) => {
let output = {};
recusive(obj, output);
return output;
}
console.log(warp(obj))
The output will hold the result, it worked for the example you gave, might throw if you give it an object that is build differently

JavaScript Filter Loop Not Looping Through All Item In Array

In the following code I am trying to filter the data. However, I see in the algorithm that it loops through the first item in the userPassedFilter array and returns the filtered data but doesn't loop again to check the second item in the userPassedFilter array. I know this is happening because I call return true before it iterates through the entire userPassedFilter array. How can I assure that in the algorythm that it loops through all the items in the userPassedFilter before returning the final result?
**User Selected Filter**
let userPassedFilter = [{"phase":1},{"phase":2}]
**Data**
let dataList = [
{"voltage":35, "phase":2},
{"voltage":12, "phase":2},
{"voltage":12, "phase":3},
{"voltage":35, "phase":1}
]
**Filter Data Algorithm**
module.exports = {
filterData: (dataList, userPassedFilter)=>{
let filteredData = [];
filteredData = dataList.filter((data) =>{
for(let item of userPassedFilter){
for(let key in item){
if(data[key] === undefined || data[key] !== item[key])
return false
}
}
return true
})
return filteredData
}
}
filter over the dataList and return every object where some of its object properties are included in the userFilter.
const userPassedFilter = [{voltage:122},{phase:1},{phase:2},{voltage:44}];
const dataList = [
{voltage:44, phase:12},
{voltage:35, phase:2},
{voltage:12, phase:2},
{voltage:12, phase:3},
{voltage:35, phase:1},
{voltage:122, phase:156}
];
function filterData(dataList, userPassedFilter) {
return dataList.filter(obj => {
return userPassedFilter.some(inner => {
const [[ key, value ]] = Object.entries(inner);
return obj[key] === value;
});
});
}
console.log(filterData(dataList, userPassedFilter));
Introduce variable for each loop, so the result will match any of the elements in the userPassedFilter by matching all properties for the element.
let userPassedFilter = [{"phase":1},{"phase":2}];
let dataList = [{"voltage":35, "phase":2},{"voltage":12, "phase":2},{"voltage":12, "phase":3},{"voltage":35, "phase":1}];
const f = (dataList, userPassedFilter) => {
let filteredData = dataList.filter((data) => {
let filtered = true;
for (let item of userPassedFilter) {
let matched = true;
for (let key in item) {
if (data[key] === undefined || data[key] !== item[key]) {
matched = false;
break;
}
}
if (matched) {
filtered = false;
break;
}
}
return !filtered;
});
return filteredData;
};
console.log(f(dataList, userPassedFilter));
A shorter version:
let userPassedFilter = [{"phase":1},{"phase":2}];
let dataList = [{"voltage":35, "phase":2},{"voltage":12, "phase":2},{"voltage":12, "phase":3},{"voltage":35, "phase":1}];
const f = (dataList, userPassedFilter) => {
let filteredData = dataList.filter((data) => {
return userPassedFilter.some(item => Object.entries(item).every(([key, value]) => data[key] === value))
});
return filteredData;
};
console.log(f(dataList, userPassedFilter));
try adding a variable
filteredData = dataList.filter((data) => {
let myvar = true;
for(let item of userPassedFilter){
for(let key in item){
if(data[key] === undefined || data[key] !== item[key])
myvar = false
}
}
return myvar
})
try adding a variable to hold the values:
let userPassedFilter = [{
"phase": 1
}, {
"phase": 2
}]
let dataList = [{
"voltage": 35,
"phase": 2
},
{
"voltage": 12,
"phase": 2
},
{
"voltage": 12,
"phase": 3
},
{
"voltage": 35,
"phase": 1
}
]
function filterData(dataList, userPassedFilter) {
let filteredData = [];
filteredData = dataList.filter((data) => {
var throwVar = 0 //add this variable to hold the value
for (let item of userPassedFilter) {
for (let key in item) {
if (data[key] === undefined || data[key] !== item[key]) {
throwVar = 0
} else {
return true
}
}
}
if (throwVar == 0) {
return false
}
})
return filteredData
}
console.log(filterData(dataList, userPassedFilter))

Javascript updating object from string [duplicate]

This question already has answers here:
How to set object property (of object property of..) given its string name in JavaScript?
(16 answers)
Closed 1 year ago.
I have this object {country:{town:{company:{boss:{}}}}} and this string country.town.cityhouse.major, I need to updatr the object from the string, but keeping the previous properties and data.
{
country: {
town: {
company: {
boss: {}
},
cityhouse: {
major: {}
}
}
}
}
This is what I have so far:
function updateObj(object, path) {
const newPath = path.split('.');
let temp = {...object};
for (let i = 0; i < newPath.length; i++) {
let mid = temp[newPath[i]];
if (mid) {
temp = mid;
} else {
temp[newPath[i]] = {};
}
}
return temp;
}
const obj = { country: { town: { company: { boss: {} }}}};
const r = updateObj(obj, 'country.town.cityhouse.major');
console.log(r);
but it responds:
{
company: {
boss: {}
},
cityhouse: {},
major: {}
}
Any hint on this?
You can clean this up a little using logical nullish assignment(??=) and a for...of loop.
function updateObj(object, path) {
let result = { ...object };
let temp = result;
for (const k of path.split('.')) {
temp = temp[k] ??= {};
}
return result;
}
const obj = { country: { town: { company: { boss: {} } } } };
const r = updateObj(obj, 'country.town.cityhouse.major');
console.log(r);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Recursive option
function updateObj(object, path) {
const result = { ...object };
const [prop, ...pathArr] = path.split('.');
result[prop] = pathArr.length
? updateObj((result[prop] ??= {}), pathArr.join('.'))
: (result[prop] ??= {});
return result;
}
const obj = { country: { town: { company: { boss: {} } } } };
const r = updateObj(obj, 'country.town.cityhouse.major');
console.log(r);
.as-console-wrapper { max-height: 100% !important; top: 0; }
This code would normally be written recursively, so you need to have a variable to hold the current scope (the path you walked on through the object) to do the job, and so i created the variable called scope to do that job.
function updateObj(object, path) {
const newPath = path.split('.');
let temp = {...object};
let scope = temp;
for (let i = 0; i < newPath.length; i++) {
let cur = scope[newPath[i]];
if (!cur) {
scope = scope[newPath[i]] = {};
} else {
scope = cur;
}
}
return temp;
}
const obj = { country: { town: { company: { boss: {} }}}};
const r = updateObj(obj, 'country.town.cityhouse.major');
console.log(r);
This is a recursive implementation, but since it requires copying the object and passing it to the next recursive call it's not an efficient one, If i find a better more efficient implementation, I'll update this.
function updateObjRec(object, path, depth = 0) {
// base case
// if depth is equal to path length then it's over
if (depth === path.length) {
return {};
}
const cur = path[depth];
const scope = object[cur];
// here we have 2 cases
// current field already exists
update = {};
if (scope) {
update = updateObjRec({ ...scope}, path, depth + 1);
} else {
update = updateObjRec({}, path, depth + 1);
}
// merge with given object
object[cur] = update;
return object
}
const obj = { country: { town: { company: { boss: {} }}}};
const r = updateObjRec(obj, 'country.town.cityhouse.major'.split('.'));
console.log(r);
Update
The recursive code can be rewritten this way to be more efficient
function updateObj(obj, path) {
const temp = { ...obj };
const p = path.split('.');
const updateRec = (scope, depth = 0) => {
// base case
if (depth === p.length) return;
const cur = p[depth];
if (!scope[cur]) {
scope[cur] = {};
}
updateRec(scope[cur], depth + 1);
}
updateRec(temp);
return temp;
}
const obj = { country: { town: { company: { boss: {} }}}};
const r = updateObj(obj, 'country.town.cityhouse.major');
console.log(r);
This isn't ideal, but it's a start.
Basically, you're returning temp, which is the lowest layer. you want to return the root.
Also when you can't find the next layer, you were creating it, but you weren't updating temp.
function updateObj(object, path) {
const newPath = path.split('.');
let temp = {...object};
const result = temp; // need to return this
for (let i = 0; i < newPath.length; i++) {
let mid = temp[newPath[i]];
if (mid) {
temp = mid;
} else {
temp[newPath[i]] = {};
temp = temp[newPath[i]] // need this
}
}
return result;
}
const obj = { country: { town: { company: { boss: {} }}}};
const r = updateObj(obj, 'country.town.cityhouse.major');
console.log(r);
I think this is what you want to achieve
const obj = {
country: {
town: {
company: { boss: {} },
},
},
};
obj.country.town.cityhouse = {
major: {},
};
console.log(obj);

How to map Array of Objects and return the length of each Object's value?

I want to check the value of every key in each object and write its length.
I tried doing this:
const a = [
{
name:"Bill",
age:'',
old:''
}
]
const myF = (arr) => {
return arr.map((i,k) => {
console.log(Object.keys(i))
return{ [Object.keys(i)]: ''}
})
}
console.log(myF(a))
I expect to get:
{
name:4,
age:0,
old:0
}
You can map it by taking entries. Let me know if this is what something you need:
var a = [ { name:"Bill", age:'', old:''}];
var result = a.map(obj=>Object.fromEntries(Object.entries(obj).map(([k,v])=>[k, v ? v : v.length])));
var result2 = a.map(obj=>Object.fromEntries(Object.entries(obj).map(([k,v])=>[k, v.length])));
console.log(result);
console.log(result2)
const a = [
{
name:"Bill",
age:'',
old:''
}
]
var b = a.map((x) =>{
if(x.age == '') {
x.age = 0;
}
if(x.old == '') {
x.old = 0;
}
return x;
})
console.log(b)

Why my recursive function works only for one level?

I am trying to learn how to cope with the objects and arrays and I saw many ways of iterating objects but recursing doesn't work for me and I don't understand why. What am I doing wrong?
I need to loop through an object and just slightly change something in an array. In my case, it's uppercasing the keys
Here is what I've got for now
const development = {
port: 8080,
db: {
username: "jkdfs",
password: "dsfsdg",
name: "kslfjskd",
test: { test: 12, another: 'value' }
},
token_secret: "jfkjdsj",
hash_rounds: "kjsfkljdfkl"
};
function throughObject(obj) {
let collection = {};
for (const key in obj) {
if (obj.hasOwnProperty(key)) {
let value = obj[key];
if (typeof obj[key] !== 'object') {
collection[key.toUpperCase()] = value;
} else {
collection[key.toUpperCase()] = nestedObject(obj[key]);
}
}
function nestedObject(nested) {
const sub = {};
for (const k in nested) {
let v = nested[k];
if (typeof nested[k] !== 'object') {
sub[k.toUpperCase()] = v;
} else {
nestedObject(v);
}
}
return sub;
}
}
return collection;
}
const r = throughObject(development);
console.log(r);
When you're recursively calling the function on an object value, you still need to assign it to the sub object: sub[k.toUpperCase()] = nestedObject(v). Also, you don't need 2 different functions.
const development = {
port: 8080,
db: {
username: "jkdfs",
password: "dsfsdg",
name: "kslfjskd",
test: { test: 12, another: 'value' }
},
token_secret: "jfkjdsj",
hash_rounds: "kjsfkljdfkl"
};
function nestedObject(nested) {
const sub = {};
for (const k in nested) {
const v = nested[k];
if (typeof nested[k] !== 'object')
sub[k.toUpperCase()] = v;
else
sub[k.toUpperCase()] = nestedObject(v); // <- HERE
}
return sub;
}
console.log(nestedObject(development))
Here's a shorter version using Object.fromEntries()
const development={port:8080,db:{username:"jkdfs",password:"dsfsdg",name:"kslfjskd",test:{test:12,another:"value"}},token_secret:"jfkjdsj",hash_rounds:"kjsfkljdfkl"};
const convert = o =>
Object.fromEntries(
Object.entries(o).map(([k, v]) =>
[k.toUpperCase(), Object(v) === v ? convert(v) : v]
)
)
console.log(convert(development))

Categories

Resources