Get sum of length of nested array in an object - javascript

I have an object like this
const obj = {
name: "abc",
arr: [{
key1: "value1",
arr1: [1, 2, 3]
}, {
key1: "value2",
arr1: [4, 5, 6]
}]
}
Here, i want to add the lengths of arrays arr1 and arr2, and return 6 as an answer. I know looping and calculating lenghts by for-in is one solution, but what can be a faster and more precise solution?

this is the simplest implementation I can think of using reduce
const obj = {
name: "abc",
arr: [{
key1: "value1",
arr1: [1, 2, 3]
}, {
key1: "value2",
arr1: [4, 5, 6]
}]
}
const result = obj.arr.reduce((res, {arr1}) => res + arr1.length, 0)
console.log(result)

It looks you want to count the lengths of arrays that only have primitive values as members, not of arrays which have (some) objects/arrays as members.
Here is a proposed recursive solution:
const isPrimitive = val => Object(val) !== val;
const isArrayOfPrimitive = arr => arr?.every?.(isPrimitive);
const deepLength = obj => isPrimitive(obj) ? 0
: Object.values(obj).reduce((sum, val) => sum + deepLength(val),
isArrayOfPrimitive(obj) ? obj.length : 0);
// Example run:
const obj = {
name: "abc",
arr: [{
key1: "value1",
arr1: [1, 2, 3]
}, {
key2: "value2",
arr2: [4, 5, 6]
}]
};
console.log(deepLength(obj)); // 6

const obj = {
name: "abc",
arr: [
{ key1: "value1", arr1: [1, 2, 3, 4, 6, 7, 9] },
{ key2: "value2", arr2: [4, 5, 6] }
]
}
function getNumbers(arr) {
let a = arr['arr'][0].arr1.length;
let b = arr['arr'][1].arr2.length;
let sum = a + b;
return sum;
}
console.log(getNumbers(obj));

Related

How to get the number difference between two or more objects in an array?

So for example I have an array as such:
const obj = [
{
key1: 3,
key2: 5,
key3: 6,
},
{
key1: 2,
key2: 3,
key3: 4,
},
{
key1: 6,
key2: 5,
key3: 5,
}
]
I want to be able to get the difference between the objects as such:
// RESULT
[
// Object filled with difference of obj[1] - obj[0]
{
key1: -1,
key2: -2,
key3: -2,
},
// Object filled with difference of obj[2] - obj[1]
{
key1: 4,
key2: 2,
key3: 1,
}
]
Is there a way I can achieve this?
I was able to find a snippet of code as such but this only find the difference of elements in an array not an object.
var arr = [23, 53, 66, 11, 67]
const elementDifferenceArray = (arr) => {
const differenceArray = [];
for (let i = 1; i < arr.length; i++) {
differenceArray.push(Math.abs(arr[i] - arr[i - 1]));
};
return differenceArray;
}
console.log(elementDifferenceArray(arr));
You could get the keys and map new keys with delta of the array and a sliced array.
const
array = [{ key1: 3, key2: 5, key3: 6 }, { key1: 2, key2: 3, key3: 4 }, { key1: 6, key2: 5, key3: 5 }],
keys = Object.keys(array[0]),
result = array
.slice(1)
.map((o, i) => Object.fromEntries(keys.map(k => [
k,
o[k] - array[i][k]
])));
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
const obj = [
{
key1: 3,
key2: 5,
key3: 6,
},
{
key1: 2,
key2: 3,
key3: 4,
},
{
key1: 6,
key2: 5,
key3: 5,
}
];
const differences = [];
for(var i= obj.length -1; i > 0; i--) {
var j = i - 1;
differences.push({
key1: obj[i].key1 - obj[j].key1,
key2: obj[i].key2 - obj[j].key2,
key3: obj[i].key3 - obj[j].key3,
});
};
const result = differences.reverse();

How to convert object to array but not array of arrays?

const foo = {
A: {
id: 1231,
f1: "Asdasd",
f2: [1, 2]
},
B: {
id: 2324,
f1: "Asdasd",
f2: [1, 2]
}
}
console.log(Object.entries(foo));
So this creates Array of arrays which first index of each array is key and second index of each array is value.
But is there a easier way to convert object to array of objects
something like this;
const bar = [
{
"some key name": "A",
...rest of the object A
},
{
"some key name": "B",
...rest of the object B
}
]
could map over Object.entries
const foo = {
A: {
id: 1231,
f1: "Asdasd",
f2: [1, 2]
},
B: {
id: 2324,
f1: "Asdasd",
f2: [1, 2]
}
}
var arr = Object.entries(foo)
.map(entry => ({
"some key name":entry[0], ...entry[1]
}))
console.log(arr);
Original answer was using values and reduce, but I misunderstood the question
var arr = Object.values(foo).reduce(function(res, v) {
return res.concat(v);
}, []);

Make a new array with all the similar key values from previous array using .reduce()

How can I turn the array:
data = [
{key1: a, key2: 1},
{key1: b, key2: 2},
{key1: c, key2: 3}]
into the array:
newArray = [1, 2, 3]
using reduce?
You do not want to reduce (transform an array into a single element) but you try to map (transform an array into another array)
data = [
{key1: 'a', key2: 1},
{key1: 'b', key2: 2},
{key1: 'c', key2: 3}
]
console.log(data.map(el => el.key2))
I don't know what are you really want, but seeing your example if you want to create a new array with the values of particular key in the object with reduce you can do it something like this:
const data = [
{key1: "a", key2: 1},
{key1: "b", key2: 2},
{key1: "c", key2: 3}
];
const ans = data.reduce((prev, curr) => {
prev.push(curr.key2);
return prev;
}, []); // start with empty array
// ans: [ 1, 2, 3 ]
But, if you want to separate all the keys in a new set of arrays you can do it something like this:
const data = [
{key1: "a", key2: 1},
{key1: "b", key2: 2},
{key1: "c", key2: 3}
];
const ans = data.reduce((prev, curr) => {
Object.keys(curr).forEach((key) => {
if (!prev[key]) {
prev[key] = [curr[key]];
} else {
prev[key].push(curr[key]);
}
});
return prev;
}, {}); // start with empty object
// ans: { key1: [ 'a', 'b', 'c' ], key2: [ 1, 2, 3 ] }
As my recommendation, I prefer using for..of is cleaner and faster than reduce or forEach or map
Example of both:
// Example 1:
const ans = [];
for (const obj of data) {
ans.push(obj.key2);
}
// ans: [ 1, 2, 3 ]
// Example 2:
const ans = {};
for (const obj of data) {
for (const key of Object.keys(obj)) {
if (!ans[key]) {
ans[key] = [obj[key]];
} else {
ans[key].push(obj[key]);
}
}
}
// ans: { key1: [ 'a', 'b', 'c' ], key2: [ 1, 2, 3 ] }

Javascript merge/reduce same multi dimensional objects

based on my question: https://stackoverflow.com/a/40661953/2392461, i open a new question with sample data.
I want to merge/reduce this:
var array = [{
'key1': {
'key11': 0,
'key12': 1
},
'key2': 0,
'key3': {
'key31': [1, 2],
'key32': {
'key321': 3,
'key322': [1, 2]
}
},
'key4': 'test'
}, {
'key1': {
'key11': 1,
'key12': 9
},
'key2': 2,
'key3': {
'key31': [4, 3],
'key32': {
'key321': 6,
'key322': [8, 9]
}
},
'key4': 'test'
}, {
'key1': {
'key11': 3,
'key12': 4
},
'key2': 7,
'key3': {
'key31': [3, 2],
'key32': {
'key321': 6,
'key322': [7, 8]
}
},
'key4': 'test'
}];
to this:
{
'key1': {
'key11': [0, 1, 3],
'key12': [1, 9, 4]
},
'key2': [0, 2, 7],
'key3': {
'key31': [[1, 2], [4, 3], [3, 2]],
'key32': {
'key321': [3, 6, 6],
'key322': [[1, 2], [8, 9], [7, 8]]
}
},
'key4': 'test'
}
the reduce function (https://stackoverflow.com/a/40668315/2392461) from #stasovlas with lodash looks good but i need to go deeper in the object.
_.reduce(data, function(result, item) {
var added = _.find(result, {
key4: item.key4
});
if (_.isObject(added)) {
//!! better to merge with new object and add result to array again to avoid mutable
added = _.mergeWith(added, item, function(addedVal, itemVal, key) {
if (key === 'key4') {
return addedVal;
}
return _.concat(addedVal, itemVal);
});
return result;
}
return _.concat(result, item);
}, []);
result is here a merged object only in layer 1 of the object.
[ { key1: [ [Object], [Object], [Object] ],
key2: [ 0, 2, 7 ],
key3: [ [Object], [Object], [Object] ],
key4: 1 } ]
i have no idea how to get my result. i think i have to iterate each object n times. n is the depth of the object.
is this the right way or is it easier than i think?
greetings mok
You could merge each level by iterating the entries of the source object and create either a new object or an array for adding the result. Proceed with child objects.
key4 gets a special treatment.
function merge(target, source) {
var singleKey = 'key4';
Object.entries(source).forEach(([key, value]) => {
if (value && typeof value === 'object' && !Array.isArray(value)) {
merge(target[key] = target[key] || {}, value);
return;
}
if (key === singleKey) {
target[key] = value;
return;
}
target[key] = target[key] || [];
target[key].push(value);
});
return target;
}
var array = [{ key1: { key11: 0, key12: 1 }, key2: 0, key3: { key31: [1, 2], key32: { key321: 3, key322: [1, 2] } }, key4: "test" }, { key1: { key11: 1, key12: 9 }, key2: 2, key3: { key31: [4, 3], key32: { key321: 6, key322: [8, 9] } }, key4: "test" }, { key1: { key11: 3, key12: 4 }, key2: 7, key3: { key31: [3, 2], key32: { key321: 6, key322: [7, 8] } }, key4: "test" }],
result = array.reduce(merge, {});
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
I have made a few improvements, it is more flexible for any kind of this problem.
function merge(target, source) {
var fixedKeys = ['key1', 'key2', 'keyn'];
Object.entries(source).forEach(([key, value]) => {
if (value && value.toString() === '[object Object]') {
merge(target[key] = target[key] || {}, value);
return;
}
if (value && Array.isArray(value)) {
merge(target[key] = target[key] || [], value);
return;
}
if (fixedKeys.indexOf(key) !== -1) {
target[key] = value;
return;
}
target[key] = target[key] || [];
target[key].push(value);
});
return target;
}
Now u can merge/reduce also deeper values/arrays/object, there is no converting from JS Arrays to Objects or otherwise and it is JSON.stringify compatible. You can set an Array of keys which should occur only once.
hope this is helping not only me :)

Filter method and that objects are passed by ref

How can I do the below without changing the "list" variable? As far as I can understand from the docs (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/filter) the filter method should return a New variable but the below says to me that it is just a reference since the "list" variable changes?
Can someone explain this behavior and how to go around it (do not want to change the original "list" var)?
var list = [{topic : "fussball", arr : [1,2]}, {topic : "soccer", arr : [3,4]},
{topic : "fussball", arr : [5,6]},{topic : "soccer", arr : [7,8]}];
function someFilterMethod(list, topic){
let tops = list.filter( function(obj){
if(obj.topic == topic){
return obj;}
});
for(let i = 0; i < tops.length ; i++){
if(i < (tops.length)) {
for(let j = (i+1) ; j<tops.length ; j++){
if( tops[i].topic.trim() == tops[j].topic.trim() ){
tops[i].arr.push.apply(tops[i].arr, tops[j].arr);
tops.splice(j, 1);
}
}
}
}
return tops;
}
var a = someFilterMethod(list, "fussball");
console.log(a);
//> Array [Object { topic: "fussball", arr: Array [1, 2, 5, 6] }]
console.log(list);
//> Array [Object { topic: "fussball", arr: Array [1, 2, 5, 6] }, Object { topic: "soccer", arr: Array [3, 4] }, Object { topic: "fussball", arr: Array [5, 6] }, Object { topic: "soccer", arr: Array [7, 8] }, Object { topic: "hockey", arr: Array [9, 10] }, Object { topic: "golf", arr: Array [11, 12] }, Object { topic: "hockey", arr: Array [13, 14] }, Object { topic: "golf", arr: Array [15, 16] }]
The someFilterMethod just takes the elements of the same "topic", concatenates their arrays and returns that.
You need to parse and strigify json, otherwise it will modify the existing object
var list = [{topic : "fussball", arr : [1,2]}, {topic : "soccer", arr : [3,4]},
{topic : "fussball", arr : [5,6]},{topic : "soccer", arr : [7,8]}];
function someFilterMethod(list, topic){
let tops = JSON.parse(JSON.stringify(list)).filter( function(obj){
if(obj.topic == topic){
return obj;}
});
for(let i = 0; i < tops.length ; i++){
if(i < (tops.length)) {
for(let j = (i+1) ; j<tops.length ; j++){
if( tops[i].topic.trim() == tops[j].topic.trim() ){
tops[i].arr.push.apply(tops[i].arr, tops[j].arr);
tops.splice(j, 1);
}
}
}
}
return tops;
}
var a = someFilterMethod(list, "fussball");
console.log(a);
//> Array [Object { topic: "fussball", arr: Array [1, 2, 5, 6] }]
console.log(list);
//> Array [Object { topic: "fussball", arr: Array [1, 2, 5, 6] }, Object { topic: "soccer", arr: Array [3, 4] }, Object { topic: "fussball", arr: Array [5, 6] }, Object { topic: "soccer", arr: Array [7, 8] }, Object { topic: "hockey", arr: Array [9, 10] }, Object { topic: "golf", arr: Array [11, 12] }, Object { topic: "hockey", arr: Array [13, 14] }, Object { topic: "golf", arr: Array [15, 16] }]
With Array.filters, new reference for the Array is created, however, objects continue to share the same reference. Hence, any change in objects of the filtered array will mean a change in original array.
You can try following
var list = [{topic : "fussball", arr : [1,2]}, {topic : "soccer", arr : [3,4]}, {topic : "fussball", arr : [5,6]},{topic : "soccer", arr : [7,8]}];
function someFilterMethod(list, topic){
return list.reduce((a,c) => {
if(c.topic == topic) a.arr = [...a.arr, ...c.arr];
return a;
}, {topic, arr: []});
}
var a = someFilterMethod(list, "fussball");
console.log(a);
console.log(list);

Categories

Resources