Related
i have to do a task, where i need to iterate over hardstructure with nested functions arrays objects and other data types. get all the numbers there are in string or not in string into the array and then with reduce method i need to calculate their sum, after calculating their sum i need to do memoisation on this function. but something doesnt work with my reduce even though i have written the most simple task there is, calculating the sum of numbers. my reduce doesnt really calculate the right way it skips some parts of the structure and doesnt gather all of the nubmers also it doesnt really calculate right i think
const ex1 = () => ({ a: 13 });
const ex2 = () => [1, 2, 3, 4, 5, "a,,,,,,", 2, 2, 2];
const ex3 = () => [...ex2()];
const ex4 = new Set([1, 2, 3, 4]);
const hardStructure = [
{
a: 1,
b: "2",
c: [
{
a: "123",
b: "#333z$34",
c: "122,333,4444,5555",
z: ex4,
d: [
[
123,
1,
"1111",
23323,
1222,
55,
[1212, 1212, 1212],
{
a: 111,
b: null,
c: () => 111,
d: 22,
e: "e",
f: () => "fffqqq",
},
],
[
2212,
1,
"111211",
23,
121,
22,
[33, 3, 3],
{
a: 3,
b: null,
c: () => 11221,
d: 2112,
e: "e11",
f: () => "fffqqq",
g: 2,
},
],
[
11,
22,
"dsds",
{
a: {
b: {
c: {
d: {
a: 1,
b: [ex1()],
c: {
a: {
b: {
c: {
d: {
a: new Map([
["a2134", 2123123],
["b", 3],
["c", 3],
]),
b: ex2,
c: [...ex3(), "1", 1],
},
},
},
},
},
},
},
},
},
},
],
],
},
],
},
{
d: [
[
123,
1,
"1111",
23323,
1222,
55,
[121322332, 12132322, 12323212],
{
a: 111,
b: null,
c: () => 1123231,
d: 22,
e: "e",
f: () => "fffqqq",
},
],
[
2212,
1,
"111211",
23,
121,
22,
[33, 3, 3],
{
a: 3,
b: null,
c: () => 1123221,
d: 211,
e: "e1231",
f: () => "fffqq1232312123q",
g: 2123,
},
],
[
11,
22,
"dsds",
{
a: {
b: {
c: {
d: {
a: 1,
b: [ex1()],
c: {
a: {
b: {
c: {
d: {
a: new Map([
[true, 222312],
[2, 322],
["c2", 32],
[() => {}, 32],
]),
b: ex2,
c: [...ex3(), "1121123", 1],
},
},
},
},
},
},
},
},
},
},
],
],
},
{
a: {
b: {
c: {
d: {
a: 112312,
b: [1],
c: {
a: {
b: {
c: {
d: {
a: "",
b: "",
c: "",
v: "v12312323",
},
},
},
},
},
},
},
},
},
},
];
const numbersArr = [];
const iterate = (hardStructure) => {
if (hardStructure === null || hardStructure === undefined) {
return [];
}
if (
hardStructure.constructor === new Set().constructor ||
hardStructure.constructor === new Map().constructor
) {
console.log("console from map or set");
hardStructure.forEach((element) => {
// console.log("123", element);
return iterate(element);
});
}
if (typeof hardStructure === "function") {
return iterate(hardStructure());
}
if (Array.isArray(hardStructure)) {
hardStructure.map((items) => {
return iterate(items);
});
}
if (typeof hardStructure === "object" && !Array.isArray(hardStructure)) {
for (let key in hardStructure) {
// console.log(hardStructure[key]);
return iterate(hardStructure[key]);
}
}
if (typeof hardStructure !== "string") {
const stringItem = String(hardStructure);
for (let i = 0; i < stringItem.length; i++) {
if (!isNaN(+stringItem)) {
numbersArr.push(+stringItem);
}
}
}
for (let i = 0; i < hardStructure.length; i++) {
// console.log(i);
if (!isNaN(+hardStructure[i])) {
// console.log("12345678910", isNaN(+hardStructure[2]));
numbersArr.push(+hardStructure[i]);
}
}
const sumWithInitial = numbersArr.reduce((accumulator, currentValue) => {
console.log(accumulator,currentValue)
return accumulator + currentValue;
},0);
// console.log(numbersArr)
console.log(sumWithInitial);
return sumWithInitial;
};
iterate(hardStructure);
Your requirements aren't entirely clear, especially as to handling of String and Function properties. This solution assumes that you want to call functions and that you can use parseInt for Strings. If you need to change that, it should be clear enough how and where to do so:
const sumNumbers = (xs) =>
xs == null
? 0
: xs .constructor == String
// ? parseInt (xs, 10) || 0 // original version not enough. Below might not be so either
? xs .includes (',') ? sumNumbers (xs .split (',')) : Number (xs .replaceAll (/\D/g, ''))
: xs .constructor == Number
? xs
: xs .constructor === Array
? xs .map (sumNumbers) .reduce ((a, b) => a + b, 0)
: xs .constructor === Set
? sumNumbers ([...xs])
: xs .constructor === Map
? sumNumbers ([...xs .values()])
: xs .constructor === Function
? sumNumbers (xs ()) // or just 0?
: xs .constructor == Object
? sumNumbers (Object .values (xs))
// TODO: Other types possible here?
: 0
const ex1 = () => ({a: 13}),
ex2 = () => [1, 2, 3, 4, 5, "a,,,,,,", 2, 2, 2],
ex3 = () => [...[1, 2, 3, 4, 5, "a,,,,,,", 2, 2, 2]],
ex4 = new Set ([1, 2, 3, 4]),
hardStructure = [{a: 1, b: "2", c: [{a: "123", b: "#333z$34", c: "122,333,4444,5555", z: ex4, d: [[123, 1, "1111", 23323, 1222, 55, [1212, 1212, 1212], {a: 111, b: null, c: () => 111, d: 22, e: "e", f: () => "fffqqq"}], [2212, 1, "111211", 23, 121, 22, [33, 3, 3], {a: 3, b: null, c: () => 11221, d: 2112, e: "e11", f: () => "fffqqq", g: 2}], [11, 22, "dsds", {a: {b: {c: {d: {a: 1, b: [{a: 13}], c: {a: {b: {c: {d: {a: new Map ([["a2134", 2123123], ["b", 3], ["c", 3]]), b: ex2, c: [...ex3(), "1", 1]}}}}}}}}}}]]}]}, {d: [[123, 1, "1111", 23323, 1222, 55, [121322332, 12132322, 12323212], {a: 111, b: null, c: () => 1123231, d: 22, e: "e", f: () => "fffqqq"}], [2212, 1, "111211", 23, 121, 22, [33, 3 , 3], {a: 3, b: null, c: () => 1123221, d: 211, e: "e1231", f: ()=> "fffqq1232312123q", g: 2123}], [11, 22, "dsds", {a: {b: {c: {d: {a: 1, b: [{a: 13}], c: {a: {b: {c: {d: {a: new Map ([[true, 222312], [2, 322], ["c2", 32], [() => {}, 32]]), b: ex2, c: [...ex3 (), "1121123", 1]}}}}}}}}}}]]}, {a: {b: {c: {d: {a: 112312, b: [1], c: {a: {b: {c: {d: {a: "", b: "", c: "", v: "v12312323"}}}}}}}}}}]
console .log (sumNumbers (hardStructure))
We have four base cases:
on a nil value (null or undefined), we return 0
on a Number, we return its value
on a String, we call parseInt on it and return the value. This is the part I think you would most likely need to change
on an unknown type (perhaps a regular expression or a date), we return 0
The others are recursive case:
for an Array, we recursively call our function on each element and then total them together.
for a Function, we call the function with no arguments, and recur on the result.
for our other known types (Object, Set, Map), we extract its values into an Array and recur on the result.
I have a given object to iterate and create another object in the below format (newObj)
Given object:
let obj = [
{a: 1, b: 232},
{a: 1, b: 2},
{a: 1, b: 256},
{a: 2, b: 3},
{a: 2, b: 3343},
{a: 3, b: 4}
];
Expected object:
newObj = {
1: [{a: 1, b: 232}, {a: 1, b: 2}, {a: 1, b: 256}],
2: [{a: 2, b: 3}],
3: [{a: 3, b: 4}]
}
Code:
let newObj = {};
obj.forEach(element => {
if (newObj[element.a]) {
let key = element.a;
newObj[key] = newObj[key].push(element);
}
newObj[element.a] = [element];
});
console.log(newObj);
We create a result object, loop through every object in obj array, if we don't have the object a key in the result object, we add him (a: []), and after that we push the entire object to result[a] array
let obj = [
{a: 1, b: 232},
{a: 1, b: 2},
{a: 1, b: 256},
{a: 2, b: 3},
{a: 2, b: 3343},
{a: 3, b: 4}
];
let result = {};
for(const {a, b} of obj) {
if(!result[a]) result[a] = []
result[a].push({a, b})
}
console.log(result)
To address your updated code snippet, you need to only create a new array for a given key if they key does not exist.
let obj = [
{ a: 1, b: 232 },
{ a: 1, b: 2 },
{ a: 1, b: 256 },
{ a: 2, b: 3 },
{ a: 2, b: 3343 },
{ a: 3, b: 4 }
];
let newObj = {};
obj.forEach(element => {
let key = element.a;
if (!newObj[key]) {
newObj[key] = []; // Only initialize if undefined/null
}
newObj[key].push(element); // Always push
});
console.log(newObj);
.as-console-wrapper { top: 0; max-height: 100% !important; }
A more modern approach would be to simply bin them by the a key by reducing and spreading.
const obj = [
{ a: 1, b: 232 },
{ a: 1, b: 2 },
{ a: 1, b: 256 },
{ a: 2, b: 3 },
{ a: 2, b: 3343 },
{ a: 3, b: 4 }
];
const newObj = obj.reduce((acc, o) => ({
...acc,
[o.a]: [...(acc[o.a] ?? []), o]
}), {});
console.log(newObj);
.as-console-wrapper { top: 0; max-height: 100% !important; }
you can use reduce for that
let obj = [
{a: 1, b: 232},
{a: 1, b: 2},
{a: 1, b: 256},
{a: 2, b: 3},
{a: 2, b: 3343},
{a: 3, b: 4}
];
const newObj = obj.reduce((res, {a, b}) => {
return {
...res,
[a] : [...(res[a] || []), {a, b}]
}
}, {})
console.log(newObj)
Input
dict = [{a: 1, b: 2, c: 3},{a: 4, b: 5, c: 6}, {a: 7, b: 8, c: 9} ]
Output to array having only values of key 'a' in typescript
array = [ 1, 4, 7 ]
Here is how you can use the Array.prototype.map() function:
> dict = [ { a: 1, b: 2, c: 3 }, { a: 4, b: 5, c: 6 }, { a: 7, b: 8, c: 9 } ]
[ { a: 1, b: 2, c: 3 }, { a: 4, b: 5, c: 6 }, { a: 7, b: 8, c: 9 } ]
> dict.map(({a}) => a)
[ 1, 4, 7 ]
>
Let's say we have an array of object:
var obj = [{a: 1, b: 2, c: 3, d: 4, e: 5 },{a: 6, b: 7, c:
8, d: 9, e: 0 }];
and we want to delete key c,e from both of the objects.
How can it be done? One of the methods I found is:
['c', 'e'].forEach(e => delete obj[e]); //for object
Is there any other way so we don't have to use double for loop.
One way to do it is to use .map() together with object destructuring:
var obj = [
{ a: 1, b: 2, c: 3, d: 4, e: 5 },
{ a: 6, b: 7, c: 8, d: 9, e: 0 },
];
var newObj = obj.map(({ c, e, ...rest }) => rest);
console.log(newObj)
This will create a new array with new objects which contain all of the other keys except for c and e.
You have 2 options to resolve it:
By using object destructuring: map(({ a,b,c,d,e }) => ({a,b,d})
Enhance option 1 by using using [Rest parameters] { c, e, ...rest }
Object destructuring like below
const obj = { a: 1, b: 2, c: 3, d: 4, e: 5 } var {c, e} = obj; // c = 3, e = 5
With option 2, you will have c,e implicit name and the remaining items named rest. After that, you just need to get rest items.
Option 1
var obj =
[
{ a: 1, b: 2, c: 3, d: 4, e: 5 },
{ a: 6, b: 7, c: 8, d: 9, e: 0 },
];
console.log(obj.map(({ a,b,c,d,e }) => ({a,b,d})));
Option 2
var obj =
[
{ a: 1, b: 2, c: 3, d: 4, e: 5 },
{ a: 6, b: 7, c: 8, d: 9, e: 0 },
];
console.log(obj.map(({ c, e, ...rest }) => rest));
// ...rest: the same as `a,b,d`
Lets say I have an array like the one below:
let arr = [ {A: 10, B: 25, C; 30, name: John}, {A: 5, B: 15, C; 20, name: John},
{A: 15, B: 22, C; 13, name: John}, {A: 10, B: 34, C; 60, name: John},
{A: 24, B: 5, C; 3, name: Jack}, {A: 15, B: 30, C; 30, name: Jack},
{A: 2, B: 12, C; 37, name: Jil}
]
So I am struggling on finding the best way to add all the A,B,C for the objects with the same name. For example I want all objects that have the name John to have {A: 40, B: 96, C: 123, name: John}.
The code below was one of my attempt to add the letter that was passed in as the parameter but this resulted in doing it individually and it wasn't really helping solve my issue.
addLetters(arr, name, gradeLetter){
const counter = 0;
return arr.reduce(function(prev, cur) {
if (name === cur.name){
counter = prev + parseInt(cur[gradeLetter]);
}
return counter
}, 0);
}
In your code you check for name1 it should be name, I have changed your code a bit and added some explanation
var arr = [ {A: 10, B: 25, C: 30, name: "John"}, {A: 5, B: 15, C: 20, name: "John"},
{A: 15, B: 22, C: 13, name: "John"}, {A: 10, B: 34, C: 60, name: "John"},
{A: 24, B: 5, C: 3, name: "Jack"}, {A: 15, B: 30, C: 30, name: "Jack"},
{A: 2, B: 12, C: 37, name: "Jil"}
]
function addLetters(arr, name){
return Object.values(arr.reduce(function(prev, cur) {
if (name === cur.name && !prev[name]){ // check for current name and prev is empty
prev[name]=cur
}
else if(name === cur.name && prev[name]) { // check for prev and name match curr.name
prev[name] ={...prev[name], A:prev[name].A+cur.A , B: cur.B+prev[name].B,C : cur.C+prev[name].C} // update prev
}
return prev
}, {}));
}
console.log(addLetters(arr, "John"))
You could minimise the code above into this
var arx = [ {A: 10, B: 25, C: 30, name: "John"}, {A: 5, B: 15, C: 20, name: "John"},
{A: 15, B: 22, C: 13, name: "John"}, {A: 10, B: 34, C: 60, name: "John"},
{A: 24, B: 5, C: 3, name: "Jack"}, {A: 15, B: 30, C: 30, name: "Jack"},
{A: 2, B: 12, C: 37, name: "Jil"}
]
res= arx.reduce((r,c) =>
{ (!r[c.name])?r[c.name] = c : r[c.name] = {...r[c.name], A : c.A + r[c.name].A ,
B : c.B + r[c.name].B, C : c.C + r[c.name].C} ; return r} , {})
console.log(Object.values(res))
So first, the input example has some errors:
let arr = [ {A: 10, B: 25, C: 30, name: 'John'}, {A: 5, B: 15, C: 20, name: 'John'},
{A: 15, B: 22, C: 13, name: 'John'}, {A: 10, B: 34, C: 60, name: 'John'},
{A: 24, B: 5, C: 3, name: 'Jack'}, {A: 15, B: 30, C: 30, name: 'Jack'},
{A: 2, B: 12, C: 37, name: 'Jil'}
]
And your code is fine, but counter is never defined, instead you should use prev, and the property is name and not name1:
addLetters(arr, name, gradeLetter){
return arr.reduce(function(prev, cur) {
if (name === cur.name){
// ^^^
prev = prev + parseInt(cur[gradeLetter]);
// ^^^^
}
return prev
// ^^^^
}, 0);
}
And for a "more fit version":
addLetters(arr, name, gradeLetter){
return arr.reduce((prev, cur) => prev + cur[gradeLetter] * (name === cur.name), 0);
}
let arr = [ {A: 10, B: 25, C: 30, name: 'John'}, {A: 5, B: 15, C: 20, name: 'John'},
{A: 15, B: 22, C: 13, name: 'John'}, {A: 10, B: 34, C: 60, name: 'John'},
{A: 24, B: 5, C: 3, name: 'Jack'}, {A: 15, B: 30, C: 30, name: 'Jack'},
{A: 2, B: 12, C: 37, name: 'Jil'}
];
let gradeLetter = 'A'
let name = 'John'
console.log(arr.reduce((prev, cur) => prev + cur[gradeLetter] * (name === cur.name), 0));
I would just convert it over into an Object, combining them if you are going to.have to look up more than one.
let arr = [
{A: 10, B: 25, C: 30, name: 'John'},
{A: 5, B: 15, C: 20, name: 'John'},
{A: 15, B: 22, C: 13, name: 'John'},
{A: 10, B: 34, C: 60, name: 'John'},
{A: 24, B: 5, C: 3, name: 'Jack'},
{A: 15, B: 30, C: 30, name: 'Jack'},
{A: 2, B: 12, C: 37, name: 'Jill'}
];
const lookup = arr.reduce(function (lookup, data) {
if (!lookup[data.name]) {
lookup[data.name] = Object.assign({}, data);
} else {
['A','B','C'].forEach(function (key) {
lookup[data.name][key] += data[key];
});
}
return lookup
}, {})
console.log(lookup['John'])
console.log(lookup['John']['A'])
console.log(lookup['Jack']['B'])