I have an object name config in which i have "from" and "to".
const config = {
"0": {
id: 0,
from: 0,
to: 10,
hex: null
},
"1": {
id: 1,
from: 11,
to: 20,
hex: null
},
"2": {
id: 2,
from: 21,
to: 30,
hex: null
},
"3": {
id: 3,
from: 31,
to: 40,
hex: null
},
"4": {
id: 4,
from: 41,
to: 50,
hex: null
}
};
I have to check that now range will contradict with each other eg: form:0 => to:10 and from:5=> to:20
here the from of second is contradict because 5 lies between 0 to 10
i have tried following but doesn't full-fill my requirement
function found(conf) {
let isFound = false;
for (let obj in conf) {
for (let x in conf) {
if (
conf[obj].id !== conf[x].id &&
(conf[x].from >= conf[obj].from && conf[x].to <= conf[obj].from)
) {
console.log(conf[obj], conf[x]);
isFound = true;
break;
}
}
if (isFound) break;
}
return isFound;
}
console.log(found(config));
Create a single array by combining all ranges
const arr = Object.entries(config).map(([a, b]) => b).flatMap(({from, to}) => RANGE(from, to))
where RANGE is method which return array of given ranges:
const RANGE = (a,b) => Array.from((function*(x,y){
while (x <= y) yield x++;
})(a,b));
Then find duplicates in the given arr using the following function:
function findDuplicate(array) {
var object = {};
var result = [];
array.forEach(function(item) {
if (!object[item]) object[item] = 0;
object[item] += 1;
});
for (var prop in object) {
if (object[prop] >= 2) {
result.push(prop);
}
}
return result;
}
const duplicates = findDuplicate(arr)
Then finally check duplicates.length
Try renaming your variables so they make sense.
Your logic is: IDs don't match and inner is after outer, but before outer's from.
There will never be a case where this will return true.
const config = {
"0": { id: 0, from: 0, to: 10, hex: null },
"1": { id: 1, from: 11, to: 20, hex: null },
"2": { id: 2, from: 21, to: 30, hex: null },
"3": { id: 3, from: 31, to: 40, hex: null },
"4": { id: 4, from: 41, to: 50, hex: null }
};
console.log(found(config));
function found(conf) {
for (let outer in conf) {
for (let inner in conf) {
let idsDontMatch = conf[outer].id !== conf[inner].id;
let innerFromGteOuterFrom = conf[inner].from >= conf[outer].from;
let innerToLteOuterFrom = conf[inner].to <= conf[outer].from;
let innerAfterOuterButBeforeOuterFrom = innerFromGteOuterFrom && innerToLteOuterFrom;
if (idsDontMatch && innerAfterOuterButBeforeOuterFrom) {
console.log(conf[outer], conf[inner]);
return true;
}
}
}
return false;
}
.as-console-wrapper { top: 0; max-height: 100% !important; }
Related
I have tried a couple of methods using findIndex, map, Object.entires
someone help me find the best solution?
**
remove 2 from customerNumber array [1,2,3,4,5]
set to customerNumber value with array[1,3,4,5]
and spread customerNumber to filterState array
**
let filterState = [
{'customerNumber': [1,2,3,4,5]},
{'ward': [10, 20, 30, 40, 50]},
{'enrolledDate': [111, 222,333, 444,555]},
{'district': ['AAA', 'BBB','CCCC', 'DDD']},
{'onBoardingSmsStatus': false}
]
search and delete 2 from customerNumber//customerNumber : 2
function removedChip(type='', value=0, filterState=[]) {
for(let i=0; i<filterState.length; i++) {
let entries = Object.keys(filterState)
.forEach(function eachKey(key) {
console.log(key); // alerts key
console.log(filterState[key]); // alerts value
});
console.log(entries)
let searchIndex = entries.findIndex(type);
console.log('searchIndex', searchIndex)
console.log('type of ', filterState[searchIndex])
for(let i=0; i<filterState[searchIndex]; i++) {
//remove 2 from customerNumber array [1,2,3,4,5]
// set to customerNumber value with array[1,3,4,5]
// and spread customerNumber to filterState array
}
}
}
function invoking with values
removedChip('customerNumber', 10, filterState)
the expected output is
let filterState = [
{'customerNumber': [1,3,4,5]},
{'ward': [10, 20, 30, 40, 50]},
{'enrolledDate': [111, 222,333, 444,555]},
{'district': ['AAA', 'BBB','CCCC', 'DDD']},
{'onBoardingSmsStatus': false}
]
This might help :
function removedChip(type='', value=0, filterState=[]) {
const filterStateTypeArray = filterState.filter(fs =>
Object.keys(fs)[0] === type);
const filterStateTypeItem = filterStateTypeArray ?
filterStateTypeArray[0] : null;
if(!filterStateTypeItem){return;}
let valueArray = filterStateTypeItem[type];
valueArray = valueArray.filter(vA => vA !== value);
filterStateTypeItem[type] = valueArray;
console.log(filterState);
}
let filterState = [
{'customerNumber': [1,2,3,4,5]},
{'ward': [10, 20, 30, 40, 50]},
{'enrolledDate': [111, 222,333, 444,555]},
{'district': ['AAA', 'BBB','CCCC', 'DDD']},
{'onBoardingSmsStatus': false}
]
removedChip('customerNumber', 2, filterState);
Not much of a change from other answers which are all feasible - I'd just split out the functions in 2 to have the filtering handled for an array which can then be tested independently of the parent function or independently from whatever list of objects is inputted
I.e you can have a generic filtering method that can be tested in isolation from the input list of objects.
let filterState = [
{ customerNumber: [1, 2, 3, 4, 5] },
{ ward: [10, 20, 30, 40, 50] },
{ enrolledDate: [111, 222, 333, 444, 555] },
{ district: ['AAA', 'BBB', 'CCCC', 'DDD'] },
{ onBoardingSmsStatus: false },
];
// Independent testable filtering
const removeChipFromArray = (array, removeValue = 0) => {
return array.filter(e => e !== removeValue);
};
// Function to handle the removal of any value from any list of objects
const removeChips = (listOfObjects, value) => {
listOfObjects.forEach((element, index) => {
const key = Object.keys(element);
// General type checker (which would be easier in TS than JS but here is a half-safe way of ensuring you're operating against a list
// You could also convert it to an Array if you think that's better
if (typeof(element[key]) === 'object') {
element[key] = removeChipFromArray(element[key], value);
}
});
};
removeChips(filterState, 2);
console.log(filterState);
In your removedChip You can filter it like..
function removedChip(type = "", value = 0, filterState = []) {
const result = filterState.map((data) => {
if (data[type]) {
// Modify only the given field in the type params
return { [type]: data[type].filter((du) => du !== value) };
}
return data;
});
return result;
}
let filterState = [
{ customerNumber: [1, 2, 3, 4, 5] },
{ ward: [10, 20, 30, 40, 50] },
{ enrolledDate: [111, 222, 333, 444, 555] },
{ district: ["AAA", "BBB", "CCCC", "DDD"] },
{ onBoardingSmsStatus: false }
];
console.log(removedChip("customerNumber", 2, filterState));
My target is to create a key and append them in a DIV. My old function works good but I have made adjustments so I changed my code to a better one. The problem is, I cannot append anymore when the array is = 1.
This is my old code: (We can see here after being matched, they're appended to the DIV using keys. Even if length = 1, there's also a key to append on my div).
//just for demo....
var data = {
"data2": [{
"entryID": "1",
"player": "testing1",
"level": "3"
}, {
"entryID": "2",
"player": "testing2",
"level": "1"
}, {
"entryID": "3",
"player": "testing3",
"level": "2"
}, {
"entryID": "4",
"player": "testing4",
"level": "2"
}, {
"entryID": "5",
"player": "testing5",
"level": "1"
}, {
"entryID": "6",
"player": "testing6",
"level": "5"
}]
}
const combine = (source) => {
return source.reduce((acc, curr) => {
if (acc[curr.level]) {
const levelArr = acc[curr.level];
const last = levelArr[levelArr.length - 1];
if (last.length === 2) {
levelArr.push([curr])
} else {
last.push(curr)
}
} else {
acc[curr.level] = [
[curr]
];
}
return acc;
}, {})
};
function removeDuplicates(result) {
return Object.values(result.reduce((acc, curr) => {
acc[curr.player] = acc[curr.player] || curr;
return acc;
}, {}))
}
result = combine(removeDuplicates(data.data2));
var keys = Object.keys(result)
var html = ""
for (var i = 0; i < keys.length; i++) {
result[keys[i]].forEach(function(val) {
var length_ = val.length; //length of the json aray inside obj
val.forEach(function(value, index) {
var entryIDs = index == 0 ? "entryIDM[]" : "entryIDW[]"
var players = index == 0 ? "playerM[]" : "playerW[]"
var levels = index == 0 ? "levelM[]" : "levelW[]"
html += `<input type="text" name="${entryIDs}" value="${value.entryID}">
<input type="text" name="${players}" value="${value.player}">
<input type="text" name="${levels}" value="${value.level}">`
//if length is only one
if (length_ == 1) {
//just add inputs with nm..
html += `<input type="text" name="entryIDW[]" value="nm"> <input type="text" name="playerW[]" value="nm"><input type="text" name="levelW[]" value="nm">`
}
})
})
}
document.getElementById("result").innerHTML = html
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="result"></div>
This is my new codes and i can't append it when the length is = 1 or 2.
const source = [
{
entryID: 1,
entryName: "player1",
weight: 1900,
},
{
entryID: 2,
entryName: "player1",
weight: 1900,
},
{
entryID: 3,
entryName: "player3",
weight: 1905,
},
{
entryID: 4,
entryName: "player4",
weight: 1905,
},
{
entryID: 5,
entryName: "player5",
weight: 1910,
},
];
function combine(
data = [],
different = 0,
maxGroupSize = 2,
sortedStatement = (a, b) => a.weight - b.weight
) {
const sortedData = [...data].sort(sortedStatement);
const dataGroups = sortedData.reduce((acc, item) => {
const findedAccItem = acc.find(
(accItem) =>
accItem.length < maxGroupSize &&
accItem[0].weight + different >= item.weight &&
!accItem.find((obj) => obj.entryName === item.entryName )
);
if (findedAccItem) {
findedAccItem.push(item);
} else {
acc.push([item]);
}
return acc;
}, []);
const namedDataGroups = dataGroups.reduce((acc, item, index) => {
const key = [index, ...item.map((item) => item.weight)].join("_");
acc[key] = item;
return acc;
}, {});
return namedDataGroups;
}
console.log("Example #1: ", combine(source));
My target is to append the keys. Same as the first snippet. Any help will be appreciated. Thank you so much
You can get the length of the JSON Array outside result[keys[i]] each loop and then using that length you can change your code to append "no match" for length 1 .
Demo Code :
const source = [{
entryID: 1,
entryName: "player1",
weight: 1900,
},
{
entryID: 2,
entryName: "player2",
weight: 1900,
},
{
entryID: 3,
entryName: "player3",
weight: 1905,
},
{
entryID: 4,
entryName: "player4",
weight: 1905,
},
{
entryID: 5,
entryName: "player5",
weight: 1910,
},
];
function combine(
data = [],
different = 0,
maxGroupSize = 2,
sortedStatement = (a, b) => a.weight - b.weight
) {
const sortedData = [...data].sort(sortedStatement);
const dataGroups = sortedData.reduce((acc, item) => {
const findedAccItem = acc.find(
(accItem) =>
accItem.length < maxGroupSize &&
accItem[0].weight + different >= item.weight &&
!accItem.find((obj) => obj.entryName === item.entryName)
);
if (findedAccItem) {
findedAccItem.push(item);
} else {
acc.push([item]);
}
return acc;
}, []);
const namedDataGroups = dataGroups.reduce((acc, item, index) => {
const key = [index, ...item.map((item) => item.weight)].join("_");
acc[key] = item;
return acc;
}, {});
return namedDataGroups;
}
var result = combine(source);
var keys = Object.keys(result)
var html = ""
for (var i = 0; i < keys.length; i++) {
var length_ = result[keys[i]].length; //get length of the json array per keys
result[keys[i]].forEach(function(value, index) {
var entryIDs = index == 0 ? "entryIDM[]" : "entryIDW[]";
var players = index == 0 ? "playerM[]" : "playerW[]";
var levels = index == 0 ? "levelM[]" : "levelW[]";
//change to correct key name
html += `<input type="text" name="${entryIDs}" value="${value.entryID}">
<input type="text" name="${players}" value="${value.entryName}">
<input type="text" name="${levels}" value="${value.weight}">`
//if length is only one
if (length_ == 1) {
//just add inputs with nm..
html += `<input type="text" name="entryIDW[]" value="nm"> <input type="text" name="playerW[]" value="nm"><input type="text" name="levelW[]" value="nm">`
}
})
}
document.getElementById("result").innerHTML = html //append to dom
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="result"></div>
Sorry for the title, I'm not even sure how to phrase what is happening here.
I'm working on an expense tracking program in React that supports multiple currencies. The expenses being tracked can be nested arbitrarily deep in a JSON object.
entertainment: {
_values: {
USD: 23,
AUD: 5,
},
'food & drink': {
_values: {
AUD: 83,
},
'local bar': {
_values: {
AUD: 28,
USD: 2,
},
},
},
minigolf: {
_values: {
USD: 112,
},
}
}
An expense can have an amount stored directly in it, but it can also act as a 'parent' category to further detailed sub-expenses.
To display the total value of an expense I've written a pair of functions:
sumValues(values)
Sums up an array of _values objects (a value object is a key-value store of currency codes and integers)
totalExpense(expense)
Returns the total value of an expense. ie any _values it has, + the totalExpense of any children expenses.
I thought I'd written these as pure functions, but when calling totalExpense() recursively the first child of an expense returns the wrong total.
totalExpense(entertainment);
//-> Object { USD: 137, AUD: 116 }
OK
totalExpense(entertainment['food & drink']);
//-> Object { AUD: 111, USD: 2 }
OK
totalExpense(entertainment);
totalExpense(entertainment['food & drink']);
//-> Object { AUD: 139, USD: 4 }
NOT OK
I've been poking at this code for hours now, but for the life of me can't see what is happening:
sumValues = values => {
return values.reduce((acc, cur) => {
for (const currency in cur) {
acc[currency]
? (acc[currency] = acc[currency] + cur[currency])
: (acc[currency] = cur[currency]);
}
return acc;
});
};
totalExpense = expense => {
const values = [];
if (expense['_values']) {
values.push(expense['_values']);
}
const subExpenses = Object.keys(expense).filter(child => {
return child[0] !== '_';
});
if (subExpenses.length > 0) {
for (const subExpense of subExpenses) {
let subtotal = this.totalExpense(expense[subExpense]);
values.push(subtotal);
}
}
if (values.length) {
return this.sumValues(values);
} else {
throw Error('No values in this expense');
}
};
render() {
const entertainment = {
_values: {
USD: 23,
AUD: 5,
},
'food & drink': {
_values: {
AUD: 83,
},
'local bar': {
_values: {
AUD: 28,
USD: 2,
},
},
},
minigolf: {
_values: {
USD: 112,
},
},
};
console.log(this.totalExpense(entertainment));
console.log(this.totalExpense(entertainment['food & drink']));
console.log(this.totalExpense(entertainment['minigolf']));
return;
}
The problem is that your reduce callback's initial value is the first item in the values array, and then you proceed to assign to that item:
acc[currency]
? (acc[currency] = acc[currency] + cur[currency])
: (acc[currency] = cur[currency]);
So, the first item gets mutated every time sumValues is called. Instead, provide an empty object as the initial value for the reduce:
sumValues = values => {
return values.reduce((acc, cur) => {
for (const currency in cur) {
acc[currency]
? (acc[currency] = acc[currency] + cur[currency])
: (acc[currency] = cur[currency]);
}
return acc;
}, {});
};
sumValues = values => {
return values.reduce((acc, cur) => {
for (const currency in cur) {
acc[currency] ?
(acc[currency] = acc[currency] + cur[currency]) :
(acc[currency] = cur[currency]);
}
return acc;
}, {});
};
totalExpense = expense => {
const values = [];
if (expense['_values']) {
values.push(expense['_values']);
}
const subExpenses = Object.keys(expense).filter(child => {
return child[0] !== '_';
});
if (subExpenses.length > 0) {
for (const subExpense of subExpenses) {
let subtotal = this.totalExpense(expense[subExpense]);
values.push(subtotal);
}
}
if (values.length) {
return this.sumValues(values);
} else {
throw Error('No values in this expense');
}
};
const entertainment = {
_values: {
USD: 23,
AUD: 5,
},
'food & drink': {
_values: {
AUD: 83,
},
'local bar': {
_values: {
AUD: 28,
USD: 2,
},
},
},
minigolf: {
_values: {
USD: 112,
},
},
};
console.log(totalExpense(entertainment));
console.log(totalExpense(entertainment['food & drink']));
I'm trying to solve this problem involving linkedlists. Partition a linked list so that values less than the partition come first followed by values equal to or greater than the partition.
Example:
input: 90 -> 30 -> 40 -> 50 -> 100 -> 40
partition: 50
output: 30 -> 40 -> 40 -> 50 -> 100 -> 90
Everything less than the partition(50) comes before all nodes greater than the partition(50).
function partitionLl(node) {
let list = {
"head": {
"data": 90,
"next": {
"data": 30,
"next": {
"data": 40,
"next": {
"data": 50,
"next": {
"data": 100,
"next": {
"data": 40,
"next": {
"data": 15,
"next": {
"data": 90,
"next": {
"data": 200,
"next": {
"data": 90,
"next": {
"data": 10,
"next": {
"data": 90,
"next": null
}
}
}
}
}
}
}
}
}
}
}
}
}
let test;
let current = list.head;
let p1 = {
data: null,
next: null
};
let p2 = current;
while (current !== null) {
if (current.data < node) {
p1 = current;
p1 = p1.next;
} else {
p2 = current;
p2 = p2.next;
}
current = current.next;
}
console.log(p1)
console.log(p2)
}
partitionLl(50)
This is the code I have and the list I am aiming to get is great while in the loop, it has the list that I need. The problem is that I need to attach these lists(p1 and p2) when the loop is completed, but the variables log something completely different and inaccurate when outside the while loop.
The current variable is being tracked both in side and outside the loop. Not sure why this is or what kind of scope loop might have that causes this. How would I access the values out side the loop?
The problem with the OPs program is that it never actually changes the list and also does not build a new list for the result, i.e. no assignment to a data or next property ever happens. Only the "pointers" p1 and p2 are moved around, until the end of the list is reached. The way the assignments are done, either p1, or p2 are bound to be null in the end.
A solution would create copies of the current element and append them to either p1 or p2 by setting the next property.
Like so:
function partitionLl(node) {
let list = {
"head": {
"data": 90,
"next": {
"data": 30,
"next": {
"data": 40,
"next": {
"data": 50,
"next": {
"data": 100,
"next": {
"data": 40,
"next": {
"data": 15,
"next": {
"data": 90,
"next": {
"data": 200,
"next": {
"data": 90,
"next": {
"data": 10,
"next": {
"data": 90,
"next": null
}
}
}
}
}
}
}
}
}
}
}
}
}
let p1 = {
"head": null
}
let t1 = p1.head
let p2 = {
"head": null
}
let t2 = p2.head
let current = list.head
while (current !== null) {
if (current.data < node) {
if(p1.head === null) {
p1.head = {
"data": current.data,
"next": null
}
t1 = p1.head
} else {
t1.next = {
"data": current.data,
"next": null
}
t1 = t1.next
}
} else {
if(p2.head === null) {
p2.head = {
"data": current.data,
"next": null
}
t2 = p2.head
} else {
t2.next = {
"data": current.data,
"next": null
}
t2 = t2.next
}
}
current = current.next;
}
console.log(p1)
console.log(p2)
}
partitionLl(50)
Typically working with linked lists are exercises in using recursion.
I'd build a couple of primitives for working with linked lists and then combine them to produce the result that you want - partition can be built from a filter and concat:
// given a list return a new list that contains only those items than pass the test function
const filter = (list, test) => {
const next = list.next ? filter(list.next, test) : null;
if (test(list.data)) {
return { data: list.data, next };
}
return next;
};
// given two lists return a new list with them concatenated together
const concat = (l1, l2) => {
if (!l1.next) {
return { data: l1.data, next: l2 };
}
return { data: l1.data, next: concat(l1.next, l2) };
};
const partition = (list, value) => {
const smaller = filter(list, d => d < value);
const bigger = filter(list, d => d >= value);
return concat(smaller, bigger);
};
You could take three lists for smaller values: (a) left; (b) for greater or equal values right; and (c) split the right part into first and last, where all values goes into the last list until the pivot value is found, and then all values goes into first.
At the end, combine all lists to a single one, and return a new list.
function partition(list, pivot) {
var leftHead = {},
left = leftHead,
firstHead = {},
lastHead = {},
right = lastHead,
isLast = true,
node = list.head;
while (node) {
if (node.data === pivot && isLast) {
right = firstHead;
isLast = false;
}
if (node.data < pivot) {
left.next = { data: node.data };
left = left.next;
} else {
right.next = { data: node.data };
right = right.next;
}
node = node.next;
}
if (firstHead.next) {
right.next = lastHead.next;
left.next = firstHead.next;
} else {
left.next = lastHead.next;
}
return { head: leftHead.next };
}
var list1 = { head: { data: 90, next: { data: 30, next: { data: 40, next: { data: 50, next: { data: 100, next: { data: 40, next: { data: 15, next: { data: 90, next: { data: 200, next: { data: 90, next: { data: 10, next: { data: 90, next: null } } } } } } } } } } } } },
list2 = { head: { data: 90, next: { data: 30, next: { data: 40, next: { data: 50, next: { data: 100, next: { data: 40 } } } } } } };
console.log(partition(list1, 50));
console.log(partition(list2, 50));
.as-console-wrapper { max-height: 100% !important; top: 0; }
I have a JSON array of objects (a collection) like:
[{
"x": {
"x1": 1
},
"y": {
"yt": 0,
"zt": 4,
"qa": 3,
"ft": 0,
...
}
},
{
"x": {
"x1": 5
},
"y": {
"yt": 10,
"zt": 2,
"qa": 0,
"ft": 0,
...
}
}]
I'd like to calculate average for each field. The result structure should be same. Like:
{
"x": {
"x1": 3
},
"y": {
"yt": 5,
"zt": 3,
"qa": 1.5,
"ft": 0,
...
}
}
Thanks
You can merge the objects using the spread syntax and lodash's _.mergeWith().
When merging, if the 2nd parameter (b) is a number divide it by the number of items in the original array to get it's respective contribution to the total average. If the 1st parameter (a) is a number, just add it without dividing (to avoid dividing the sum multiple times), or add 0 if it's undefined.
I've added examples of 2 objects array, and 3 objects array.
const getAvg = (data) => _.mergeWith({}, ...data, (a, b) => {
if(_.isNumber(b)) {
return ((b || 0) / data.length) + (_.isNumber(a) ? (a || 0) : 0);
}
});
const data1 = [
{"x":{"x1":1},"y":{"yt":0,"zt":4,"qa":3,"ft":0}},
{"x":{"x1":5},"y":{"yt":10,"zt":2,"qa":0,"ft":0}}
];
const data2 = [
{"x":{"x1":1},"y":{"yt":0,"zt":4,"qa":3,"ft":0}},
{"x":{"x1":5},"y":{"yt":10,"zt":2,"qa":0,"ft":0}},
{"x":{"x1":3},"y":{"yt":2,"zt":6,"qa":3,"ft":0}}
];
const result1 = getAvg(data1);
console.log('2 objects in the array: ', result1);
const result2 = getAvg(data2);
console.log('3 objects in the array: ', result2);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.4/lodash.min.js"></script>
You could first collect and sum all values in the same data structure and then calculkate the average by a division with the length of the given array.
function getParts(array, result) {
function iter(o, r) {
Object.keys(o).forEach(function (k) {
if (o[k] && typeof o[k] === 'object') {
return iter(o[k], r[k] = r[k] || {});
}
r[k] = (r[k] || 0) + o[k];
});
}
function avr(o) {
Object.keys(o).forEach(function (k) {
if (o[k] && typeof o[k] === 'object') {
return avr(o[k]);
}
o[k] = o[k] /data.length;
});
}
data.forEach(function (a) {
iter(a, result);
});
avr(result);
}
var data = [{ x: { x1: 1 }, y: { yt: 0, zt: 4, qa: 3, ft: 0, } }, { x: { x1: 5 }, y: { yt: 10, zt: 2, qa: 0, ft: 0, } }],
result = {};
getParts(data, result);
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
let objectArray = [{
"x": {
"x1": 1
},
"y": {
"yt": 0,
"zt": 4,
"qa": 3,
"ft": 0,
}
},
{
"x": {
"x1": 5
},
"y": {
"yt": 10,
"zt": 2,
"qa": 0,
"ft": 0,
}
}];
function findAverage(array) {
let counter = {},
result = {},
i,
obj,
key,
subKey;
// Iterate through array
for (i = 0; i < array.length; i++) {
obj = array[i];
// Copy each key in array element to counter object
for (key in obj) {
counter[key] = counter[key] || {};
// Increment and keep count of key-values of counter based on values in array element
for (subKey in obj[key]) {
counter[key][subKey] = counter[key][subKey] || {total: 0, numElements: 0};
counter[key][subKey].total += obj[key][subKey];
counter[key][subKey].numElements += 1;
}
}
}
// Go back through counter to find average of all existing subkeys (based on incremented total and the number of elements recorded) and throw it into result object
for (key in counter) {
result[key] = result[key] || {};
for (subKey in counter[key]) {
result[key][subKey] = counter[key][subKey].total / counter[key][subKey].numElements;
}
}
return result;
}
console.log(findAverage(objectArray));
Not designed to be absolutely optimal, and copying objects can be done recursively without knowing in advance their structure, but I wanted to keep the steps as clear as possible.
Edited to allow testing as snippet. Had no idea you could even do that on SO!
var array = [{
"x": {
"x1": 1
},
"y": {
"yt": 0,
"zt": 4,
"qa": 3,
"ft": 0
}
},
{
"x": {
"x1": 5
},
"y": {
"yt": 10,
"zt": 2,
"qa": 0,
"ft": 0
}
}];
function aintob(){
var o = {};
var first = array[0],
second = array[1];
var result = {x:{},y:{}};
var each = function(letter, oa, ob){
var i,
letter = {};
for(i in oa){
letter[i] = (oa[i]+ob[i])/2;
}
return letter;
}
o.x = each("x", first.x, second.x);
o.y = each("y", first.y, second.y);
return o;
}
console.log(aintob());