I have an object which has objects inside in it at the following form:
Object {
"item1": { "subitem1": 5, "subitem2": 10 },
"item2": { "subitem1": 3, "subitem2": 12, "subitem3": 1 },
"item3": { "subitem1": 8, "subitem2": 1, "subitem3": 3 }
}
I want to convert it to an array with the following form:
[0] Object { key: "item1", "subitem1": 5, "subitem2": 10 }
[1] Object { key: "item2", "subitem1": 3, "subitem2": 12, "subitem3": 1 }
[2] Object { key: "item3", "subitem1": 8, "subitem2": 1, "subitem3": 3 }
Any ideas? Thanks in advance
You could get the entries of the object and assign the key.
var object = { item1: { subitem1: 5, subitem2: 10 }, item2: { subitem1: 3, subitem2: 12, subitem3: 1 }, item3: { subitem1: 8, subitem2: 1, subitem3: 3 } },
result = Object.entries(object).map(([key, o]) => Object.assign({ key }, o));
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
You can use Object.keys() and Array.prototype.map():
const obj = { "item1": { "subitem1": 5, "subitem2": 10 }, "item2": { "subitem1": 3, "subitem2": 12, "subitem3": 1 }, "item3": { "subitem1": 8, "subitem2": 1, "subitem3": 3 }},
res = Object.keys(obj).map(key => ({key, ...obj[key]}));
console.log(res);
Do note, however, the order of the keys retrieved from Object.keys is not guaranteed to be the same order as listed in your object
You can try this mate
let obj = { "item1": { "subitem1": 5, "subitem2": 10 }, "item2": { "subitem1": 3, "subitem2": 12, "subitem3": 1 }, "item3": { "subitem1": 8, "subitem2": 1, "subitem3": 3 } };
let op =[];
for(let key in obj){
op.push({
key : key,
...obj[key]
})
}
console.log(op);
Related
I have an array in this format:
let array = [
{ text: "Green marbles", number: 10, n: 1 },
{ text: "Pink marbles", number: 5, n: 1 },
{ text: "Yellow marbles", number: 2, n: 1 },
{ text: "Green marbles", number: 10, n: 2 },
{ text: "Pink marbles", number: 5, n: 2 },
{ text: "Yellow marbles", number: 2, n: 2 }
]
The desired result would be:
let formatArray = [
{ n: 1, "Green marbles": 10, "Pink marbles": 5, "Yellow marbles": 2 },
{ n: 2, "Green marbles": 10, "Pink marbles": 5, "Yellow marbles": 2 }
];
The number is not constant (just for this example it is)I tried doing this:
let formatArray = [];
array.forEach(el=> {
Object.keys(el).forEach(eel=> {
formatArray.push(/*…???*/)
})
})
Stuck here, but I think that this would be the idea
Try to use the reduce method to return a new array with the values you want.
let array = [
{ text: "Green marbles", number: 10, n: 1 },
{ text: "Pink marbles", number: 5, n: 1 },
{ text: "Yellow marbles", number: 2, n: 1 },
{ text: "Green marbles", number: 10, n: 2 },
{ text: "Pink marbles", number: 5, n: 2 },
{ text: "Yellow marbles", number: 2, n: 2 }
]
const formatArray = array.reduce((accum, iter) => {
const {n, text, number} = iter
if (accum[n-1] === undefined) accum[n-1] = {}
accum[n-1].n = n
accum[n-1][text] = number
return accum
}, [])
console.log(formatArray)
I am using the [] to set the key to be one of the iterator's values. I am also letting the n value set which object the iterator needs to be added to.
1) You can easily achieve the result efficiently using Map as:
array.reduce((map, curr) => map.set(curr.n, { ...(map.get(curr.n) ?? {}), [curr.text]: curr.number }), new Map())
let array = [
{ text: "Green marbles", number: 10, n: 1 },
{ text: "Pink marbles", number: 5, n: 1 },
{ text: "Yellow marbles", number: 2, n: 1 },
{ text: "Green marbles", number: 10, n: 2 },
{ text: "Pink marbles", number: 5, n: 2 },
{ text: "Yellow marbles", number: 2, n: 2 },
];
let collection = array.reduce((map, curr) => map.set(curr.n, { ...(map.get(curr.n) ?? {}), [curr.text]: curr.number }), new Map());
const formatArray = [...collection.values()];
console.log(formatArray);
2) One-liner solution
let formatArray = [ ...array.reduce((map, curr) => map.set(curr.n, { ...(map.get(curr.n) ?? {}), [curr.text]: curr.number }), new Map()).values()];
let array = [
{ text: "Green marbles", number: 10, n: 1 },
{ text: "Pink marbles", number: 5, n: 1 },
{ text: "Yellow marbles", number: 2, n: 1 },
{ text: "Green marbles", number: 10, n: 2 },
{ text: "Pink marbles", number: 5, n: 2 },
{ text: "Yellow marbles", number: 2, n: 2 },
];
let formatArray = [ ...array.reduce((map, curr) => map.set(curr.n, { ...(map.get(curr.n) ?? {}), [curr.text]: curr.number }), new Map()).values()];
console.log(formatArray);
This can be handled as a 'group by' on n accumulating the various marble colors into each grouped object.
let array = [{ text: "Green marbles", number: 6, n: 1 }, { text: "Pink marbles", number: 3, n: 1 }, { text: "Yellow marbles", number: 2, n: 1 }, { text: "Green marbles", number: 12, n: 2 }, { text: "Pink marbles", number: 7, n: 2 }, { text: "Yellow marbles", number: 1, n: 2 }];
const temp = {};
for (const { n, number, text } of array) {
if (temp[n] === undefined) temp[n] = { n, "Green marbles": 0, "Pink marbles": 0, "Yellow marbles": 0 };
temp[n][text] += number;
}
const result = Object.values(temp);
console.log(result);
If you're not sure of the 'marble colors' properties ahead of time you can make it more dynamic
let array = [{ text: "Green marbles", number: 6, n: 1 }, { text: "Pink marbles", number: 3, n: 1 }, { text: "Yellow marbles", number: 2, n: 1 }, { text: "Green marbles", number: 12, n: 2 }, { text: "Pink marbles", number: 7, n: 2 }, { text: "Yellow marbles", number: 1, n: 2 }];
const temp = {};
for (const { n, number, text } of array) {
if (temp[n] === undefined) temp[n] = { n };
temp[n][text] = (temp[n][text] ?? 0) + number;
}
const result = Object.values(temp);
console.log(result);
or as a reduce() call
let array = [{ text: "Green marbles", number: 6, n: 1 }, { text: "Pink marbles", number: 3, n: 1 }, { text: "Yellow marbles", number: 2, n: 1 }, { text: "Green marbles", number: 12, n: 2 }, { text: "Pink marbles", number: 7, n: 2 }, { text: "Yellow marbles", number: 1, n: 2 }];
const result = Object.values(
array.reduce((a, { n, number, text }) =>
(a[n] = { ...(a[n] ??= { n }), [text]: (a[n][text] ?? 0) + number }, a), {}));
console.log(result);
But it seems that your array might actually be ordered with every x rows describing a new n.
If this is the case you can use a simple for loop and check if the index is evenly divisible by x.
let array = [{ text: "Green marbles", number: 6, n: 1 }, { text: "Pink marbles", number: 3, n: 1 }, { text: "Yellow marbles", number: 2, n: 1 }, { text: "Green marbles", number: 12, n: 2 }, { text: "Pink marbles", number: 7, n: 2 }, { text: "Yellow marbles", number: 1, n: 2 }];
let
result = [],
color_count = 3,
prev;
for (let i = 0; i < array.length; i++) {
const { n, number, text } = array[i];
if (i % color_count === 0) {
prev = { n };
result.push(prev);
}
prev[text] = number;
}
console.log(result);
Or, if they are indeed in order, but you don't know how many per n you can track the current object, and if the n doesn't match on any iteration push a new obect to the result.
let array = [{ text: "Green marbles", number: 6, n: 1 }, { text: "Pink marbles", number: 3, n: 1 }, { text: "Yellow marbles", number: 2, n: 1 }, { text: "Green marbles", number: 12, n: 2 }, { text: "Pink marbles", number: 7, n: 2 }, { text: "Yellow marbles", number: 1, n: 2 }];
let result = [], prev;
for (const { n, number, text } of array) {
if (!prev || prev.n !== n) {
prev = { n };
result.push(prev);
}
prev[text] = number;
}
console.log(result);
I am trying to use below Script to Get the Average of Disconnect Devices .The results are output in group for each Test Customer .
var dataObject = [{
"Customer_Nbr": "13",
"Customer_Name": "Test1",
"Connected_Devices": 7,
"Disconnected_Devices": 1,
"Total_Devices": 8
},
{
"Customer_Nbr": "13",
"Customer_Name": "Test1",
"Connected_Devices": 6,
"Disconnected_Devices": 2,
"Total_Devices": 8
},
{
"Customer_Nbr": "12",
"Customer_Name": "Test3",
"Connected_Devices": 8,
"Disconnected_Devices": 2,
"Total_Devices": 10
}
];
groups = dataObject.reduce(function(r, o) {
var k = o.Customer_Nbr + o.Customer_Name;
if (r[k]) {
if (o.Disconnected_Devices)
(r[k].Disconnected_Devices += o.Disconnected_Devices) && ++r[k].Average;
} else {
r[k] = o;
r[k].Average = 1; // taking 'Average' attribute as an items counter(on the first phase)
}
return r;
}, {});
// getting "average of Points"
var result = Object.keys(groups).map(function(k) {
groups[k].Average = Math.round(groups[k].Disconnected_Devices / groups[k].Average);
return groups[k];
});
console.log(result)
Now I also want grouped output to have a percentage calculation which would be result/Total_Devices * 100 .
Output Should be Something like Assuming Total_Devices Count is constant in Input data -
[
{
Customer_Nbr: '13',
Customer_Name: 'Test1',
Connected_Devices: 7,
Disconnected_Devices: 3,
Total_Devices: 8,
Average: 2
Percent: 25
},
{
Customer_Nbr: '12',
Customer_Name: 'Test3',
Connected_Devices: 8,
Disconnected_Devices: 2,
Total_Devices: 10,
Average: 2
Percent: 20
}
]
Something like this maybe?
var dataObject = [
{
Customer_Nbr: "13",
Customer_Name: "Test1",
Connected_Devices: 7,
Disconnected_Devices: 1,
Total_Devices: 8,
},
{
Customer_Nbr: "13",
Customer_Name: "Test1",
Connected_Devices: 6,
Disconnected_Devices: 2,
Total_Devices: 8,
},
{
Customer_Nbr: "12",
Customer_Name: "Test3",
Connected_Devices: 8,
Disconnected_Devices: 2,
Total_Devices: 10,
},
];
groups = dataObject.reduce(function (r, o) {
var k = o.Customer_Nbr + o.Customer_Name;
if (r[k]) {
if (o.Disconnected_Devices)
(r[k].Disconnected_Devices += o.Disconnected_Devices) && ++r[k].Average;
} else {
r[k] = o;
r[k].Average = 1; // taking 'Average' attribute as an items counter(on the first phase)
}
return r;
}, {});
// getting "average of Points"
var result = Object.keys(groups).map(function (k) {
groups[k].Average = Math.round(
groups[k].Disconnected_Devices / groups[k].Average
);
groups[k].percentage = (groups[k].Average/groups[k].Total_Devices) * 100;
return groups[k];
});
console.log(result);
My starting data set is an array of objects containing metrics, each containing an ID. I need to convert this data set into an array of aggregates, by ID. For example:
const startingArray = [
{ id: 1, metricA: 5, metricB: 8, metricC: 1 }
{ id: 2, metricA: 4, metricB: 0, metricC: 7 }
{ id: 1, metricA: 9, metricB: 8, metricC: 2 }
{ id: 3, metricA: 1, metricB: 8, metricC: 2 }
{ id: 3, metricA: 6, metricB: 6, metricC: 1 }
{ id: 2, metricA: 3, metricB: 1, metricC: 9 }
{ id: 1, metricA: 3, metricB: 9, metricC: 8 }
]
const aggregates = {};
startingArray.forEach((item) => {
if (!aggregates[item.id]) {
aggregates[item.id] = {
id: item.id,
metricA: item.metricA,
metricB: item.metricB,
metricC: item.metricC
}
} else {
aggregates[item.id].metricA += item.metricA,
aggregates[item.id].metricB += item.metricB,
aggregates[item.id].metricC += item.metricC
}
});
// convert to flat array using lodash toArray() method
const endingArray = toArray(aggregates);
// results:
// [
// { id: 1, metricA: 17, metricB: 25, metricC: 11 }
// { id: 2, metricA: 5, metricB: 1, metricC: 16 }
// { id: 3, metricA: 5, metricB: 8, metricC: 3 }
// ]
The arrays can be massive, what is the most efficient way of processing this data set?
You could destructure id from the object and collect the rest for getting all entries and create a new object and sum all rest properties.
const
data = [{ id: 1, metricA: 5, metricB: 8, metricC: 1 }, { id: 2, metricA: 4, metricB: 0, metricC: 7 }, { id: 1, metricA: 9, metricB: 8, metricC: 2 }, { id: 3, metricA: 1, metricB: 8, metricC: 2 }, { id: 3, metricA: 6, metricB: 6, metricC: 1 }, { id: 2, metricA: 3, metricB: 1, metricC: 9 }, { id: 1, metricA: 3, metricB: 9, metricC: 8 }],
result = Object.values(data.reduce((r, { id, ...o }) => {
Object.entries(o).forEach(([k, v]) => {
r[id] ??= { id };
r[id][k] = (r[id][k] || 0) + v;
});
return r;
}, {}));
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
I want to run multiple backtests on certain stock data. I want to do this by generating an array of strategy options that I will pass to a backtest function.
In the object below I can define values as arrays so that multiple combinations of strategies will be formed.
The amount of combinations of [0,1] and [2,3] is 4, that's why my output array will consist of 4 strategy objects.
To illustrate, this is my (simplified) input:
const backtestSettings = {
stopLoss: [5],
bands: [
{
timeframe: 1,
openMinVolatility: [0,1],
},
{
timeframe: 5,
openMinVolatility: [2,3],
},
{
timeframe: 15,
openMinVolatility: [0],
},
{
timeframe: 30,
openMinVolatility: [0],
}
]
};
And I am trying to get this as my output:
[
{
stopLoss: 5,
bands: [
{
timeframe: 1,
openMinVolatility: 0
},
{
timeframe: 5,
openMinVolatility: 2
},
{
timeframe: 15,
openMinVolatility: 0
},
{
timeframe: 30,
openMinVolatility: 0
}
]
},
{
stopLoss: 5,
bands: [
{
timeframe: 1,
openMinVolatility: 1
},
{
timeframe: 5,
openMinVolatility: 2
},
{
timeframe: 15,
openMinVolatility: 0
},
{
timeframe: 30,
openMinVolatility: 0
}
]
},
{
stopLoss: 5,
bands: [
{
timeframe: 1,
openMinVolatility: 0
},
{
timeframe: 5,
openMinVolatility: 3
},
{
timeframe: 15,
openMinVolatility: 0
},
{
timeframe: 30,
openMinVolatility: 0
}
]
},
{
stopLoss: 5,
bands: [
{
timeframe: 1,
openMinVolatility: 1
},
{
timeframe: 5,
openMinVolatility: 3
},
{
timeframe: 15,
openMinVolatility: 0
},
{
timeframe: 30,
openMinVolatility: 0
}
]
}
]
Question: How do I convert my input to the desired output? (I've spent days trying a lot of different things)
Bonus: I have something working without the bands (the fact that it is nested makes things complicated for me) by chaining some forEach functions, but in reality the amount of options is substantial, which makes my code really long and unreadable. So I'm hoping that there is a solution that can also accept an arbitrary amount of options instead of chaining forEach functions.
Since you're looking for a hint rather than a full solution, one (non-recursive) helper function might give you a start:
const crossproduct = (xss) =>
xss .reduce (
(ps, xs) => ps .reduce ((r, p) => [... r, ... (xs .map ((x) => [... p, x]))], []),
[[]]
)
const as = [1, 2], bs = ['a', 'b', 'c'], cs = ['x'], ds = ['y', 'z']
console .log (crossproduct ([as, bs, cs, ds]))
This takes the generalized Cartesian product of an array of arrays. That seems an essential step in your process.
The data structure that I am trying to achieve would look as so :
I would like the list_id to become a key in a object, and hold all the id's of the items that have the matching list id.
var lists = { (list_id)1 : [1, 2, 3]
(list_id)2 : [4, 5, 6]
(list_id)3 : [7, 8, 9]
(list_id)4 : [10, 11, 12] };
this object is created from a json data structure that looks like this:
let json = [{ id: 1, list_id: 1 }, { id: 2, list_id: 1 },
{id: 3, list_id: 1 }, {id: 4, list_id: 2 },
{id: 5, list_id: 2 }, {id: 6, list_id: 2 },
{id: 7, list_id: 3 }, {id: 8, list_id: 3 },
{id: 9, list_id: 3 }, {id: 10, list_id: 4 },
{id: 11, list_id: 4 }, {id: 12, list_id: 4 }]
I can make an object that holds all the list_id's as keys but am getting stumped on pushing the actions_id into the value pair array with the matching list id.
let listAll = {};
json.forEach(function(lista, index, listb) {
listAll[lista.list_id] = [];
if ( listAll[lista.list_id] === lista.list_id){
listAll[lista.list_id].push(lista.id)
} else {
listAll[lista.list_id] = [lista.id];
}
});
My goal is to have and object that contains a key for every list_id currently avaliable from the actions.
Then add every action that contains the matching list_id into a value pair array.
the current output of this code is
{ '1': [ 3 ], '2': [ 6 ], '3': [ 9 ], '4': [ 12 ] }
which does not contain all numbers, each array should contain 3 numbers.
An alternative is using the function reduce to group the objects by a specific key = ['list_id', list_id].join('').
let json = [{ id: 1, list_id: 1 }, { id: 2, list_id: 1 }, {id: 3, list_id: 1 }, {id: 4, list_id: 2 }, {id: 5, list_id: 2 }, {id: 6, list_id: 2 }, {id: 7, list_id: 3 }, {id: 8, list_id: 3 }, {id: 9, list_id: 3 }, {id: 10, list_id: 4 }, {id: 11, list_id: 4 }, {id: 12, list_id: 4 }],
result = json.reduce((a, {id, list_id}) => {
let key = ['list_id', list_id].join(''); // For example: this is creating ['list_id', 1] to list_id1
(a[key] || (a[key] = [])).push(id);
return a;
}, Object.create(null)/*This is only to create an object without prototype -> {}*/);
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Why don't you try hasOwnProperty instead?
var listAll = {};
json.forEach(function(list, index) {
if (listAll.hasOwnProperty(list.list_id)) {
listAll[list.list_id].push(list.id);
}else {
listAll[list.list_id] = [list.id];
}
});
console.log(listAll);