Related
I have an object with following example data model
const partition = {
values: [
{
dimensionValue: 'A',
numbers: [0, 33],
partition: {
values: [
{
dimensionValue: '1',
numbers: [0, 3375],
partition: {
values: [
{
dimensionValue: 'a',
numbers: [0, 0],
partition: null
},
{
dimensionValue: 'b',
numbers: [0, 8],
partition: null
}
]
}
},
{
dimensionValue: '2',
numbers: [6028, 0],
partition: {
values: [
{
dimensionValue: 'a',
numbers: [0, 6028],
partition: null
}
]
}
}
]
}
},
{
dimensionValue: 'B',
numbers: [0, 31721.57],
partition: {
values: [
{
dimensionValue: '1',
numbers: [0, 0],
partition: {
values: [
{
dimensionValue: 'a',
numbers: [0, 31721.57],
partition: null
}
]
}
}
]
}
}
]
}
I need to transform it into one-dimensional array that will store relation between nested nodes in the dimension property, and numbers from the specific node layer in the values property. Essentially, output should look like this
[
{
"dimensions": ["A"],
"values": [0, 33]
},
{
"dimensions": ["A", "1"],
"values": [0, 3375]
},
{
"dimensions": ["A", "1", "a"],
"values": [0, 0]
},
{
"dimensions": ["A", "1", "b"],
"values": [0, 8]
},
{
"dimensions": ["A", "2"],
"values": [6028, 0]
},
{
"dimensions": ["A", "2", "a"],
"values": [0, 6028]
},
{
"dimensions": ["B"],
"values": [0, 31721.57]
},
{
"dimensions": ["B", "1"],
"values": [0, 0]
},
{
"dimensions": ["B", "1", "a"],
"values": [0, 31721.57]
}
]
My semi-working solution is here.
I'm sure there is some sexy recursive function to use here but I'm struggling to write it.
const partition = {
values: [
{
dimensionValue: 'A',
numbers: [0, 33],
partition: {
values: [
{
dimensionValue: '1',
numbers: [0, 3375],
partition: {
values: [
{
dimensionValue: 'a',
numbers: [0, 0],
partition: null
},
{
dimensionValue: 'b',
numbers: [0, 8],
partition: null
}
]
}
},
{
dimensionValue: '2',
numbers: [6028, 0],
partition: {
values: [
{
dimensionValue: 'a',
numbers: [0, 6028],
partition: null
}
]
}
}
]
}
},
{
dimensionValue: 'B',
numbers: [0, 31721.57],
partition: {
values: [
{
dimensionValue: '1',
numbers: [0, 0],
partition: {
values: [
{
dimensionValue: 'a',
numbers: [0, 31721.57],
partition: null
}
]
}
}
]
}
}
]
}
const extractDimensionValues = (
partitionValues
) => {
return (
partitionValues.flatMap(({ dimensionValue, numbers, partition }) => {
const mainValues = {
dimensions: [dimensionValue],
values: [...numbers],
}
const nestedValues = partition.values.flatMap((value) => {
return ({
dimensions: [dimensionValue, value.dimensionValue],
values: [...value.numbers]
})
})
return !partition.values ? [mainValues] : [mainValues, ...nestedValues]
})
)
}
const data = [...extractDimensionValues(partition.values)]
console.log('data :', data)
I updated the code so it flattens the partitionValues array and map over it to extract the relevant dimension values and corresponding numbers. The extracted data is stored in a new array data which is a one-dimensional array.
Updated code:
const partition = {
values: [
{
dimensionValue: 'A',
numbers: [0, 33],
partition: {
values: [
{
dimensionValue: '1',
numbers: [0, 3375],
partition: {
values: [
{
dimensionValue: 'a',
numbers: [0, 0],
partition: null
},
{
dimensionValue: 'b',
numbers: [0, 8],
partition: null
}
]
}
},
{
dimensionValue: '2',
numbers: [6028, 0],
partition: {
values: [
{
dimensionValue: 'a',
numbers: [0, 6028],
partition: null
}
]
}
}
]
}
},
{
dimensionValue: 'B',
numbers: [0, 31721.57],
partition: {
values: [
{
dimensionValue: '1',
numbers: [0, 0],
partition: {
values: [
{
dimensionValue: 'a',
numbers: [0, 31721.57],
partition: null
}
]
}
}
]
}
}
]
};
const extractDimensionValues = (partitionValues, currentDimensions = []) => {
return (
partitionValues.flatMap(({ dimensionValue, numbers, partition }) => {
const dimensions = [...currentDimensions, dimensionValue];
const values = { dimensions, values: [...numbers] };
if (!partition || !partition.values) {
return [values];
}
return [
values,
...extractDimensionValues(partition.values, dimensions)
];
})
);
};
const data = [...extractDimensionValues(partition.values)];
console.log('data:', data);
You could take a recursive approach by using the nested result for mapping with the actual dimensionValue.
const
getFlat = o => o?.values?.flatMap(({ dimensionValue, numbers: values, partition }) => [
{ dimensions: [dimensionValue], values },
...getFlat(partition)
.map(({ dimensions, values }) => ({ dimensions: [dimensionValue, ...dimensions], values }))
]) || [],
partition = { values: [{ dimensionValue: 'A', numbers: [0, 33], partition: { values: [{ dimensionValue: '1', numbers: [0, 3375], partition: { values: [{ dimensionValue: 'a', numbers: [0, 0], partition: null }, { dimensionValue: 'b', numbers: [0, 8], partition: null }] } }, { dimensionValue: '2', numbers: [6028, 0], partition: { values: [{ dimensionValue: 'a', numbers: [0, 6028], partition: null }] } }] } }, { dimensionValue: 'B', numbers: [0, 31721.57], partition: { values: [{ dimensionValue: '1', numbers: [0, 0], partition: { values: [{ dimensionValue: 'a', numbers: [0, 31721.57], partition: null }] } } ] } }] },
flat = getFlat(partition);
console.log(flat);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Another flattening, recursive approach could be based on a single reduce task which does recursively create the new flattened partition value from the currently processed item and keeps track of the correct dimensions path/array by always passing its recent state as part of an accumulating object which also holds the temporary and the final result-array.
function recursivelyCreateAndCollectFlattenedPartitionValue(
// - the destructured initial value and the accumulated value.
{ result = [], dimensions = [] },
// - the destructured currently processed array item.
{ dimensionValue, numbers: values, partition = null },
) {
result
// - push ...
.push({
// ... always the newly created flatened item ...
dimensions: dimensions.concat(dimensionValue),
values,
}, ...(
// ... and, only if necessary, the `result` array
// of the next recursion cycle while "walking the tree".
partition?.values.reduce(
recursivelyCreateAndCollectFlattenedPartitionValue, {
dimensions: dimensions.concat(dimensionValue),
result: [],
},
).result ?? []
));
return { result, dimensions: [...dimensions] };
}
const partition = {
values: [{
dimensionValue: 'A',
numbers: [0, 33],
partition: {
values: [{
dimensionValue: '1',
numbers: [0, 3375],
partition: {
values: [{
dimensionValue: 'a',
numbers: [0, 0],
partition: null,
}, {
dimensionValue: 'b',
numbers: [0, 8],
partition: null,
}],
},
}, {
dimensionValue: '2',
numbers: [6028, 0],
partition: {
values: [{
dimensionValue: 'a',
numbers: [0, 6028],
partition: null,
}],
},
}],
},
}, {
dimensionValue: 'B',
numbers: [0, 31721.57],
partition: {
values: [{
dimensionValue: '1',
numbers: [0, 0],
partition: {
values: [{
dimensionValue: 'a',
numbers: [0, 31721.57],
partition: null,
}],
},
}],
},
}],
};
const { result: listOfFlattenedPartitionValues } = partition
.values
.reduce(recursivelyCreateAndCollectFlattenedPartitionValue, { result: [] });
console.log({ listOfFlattenedPartitionValues });
.as-console-wrapper { min-height: 100%!important; top: 0; }
This is similar to the solution from Filip Huhta, but with no local variables, and in fact, no statements at all, only expressions:
const flatten = ({values}, path = []) => values .flatMap (
({dimensionValue, numbers, partition}) => [
{dimensions: [...path, dimensionValue], values: numbers},
...(partition ? flatten (partition, path .concat (dimensionValue) ): [])
]
)
const partition = {values: [{dimensionValue: "A", numbers: [0, 33], partition: {values: [{dimensionValue: "1", numbers: [0, 3375], partition: {values: [{dimensionValue: "a", numbers: [0, 0], partition: null}, {dimensionValue: "b", numbers: [0, 8], partition: null}]}}, {dimensionValue: "2", numbers: [6028, 0], partition: {values: [{dimensionValue: "a", numbers: [0, 6028], partition: null}]}}]}}, {dimensionValue: "B", numbers: [0, 31721.57], partition: {values: [{dimensionValue: "1", numbers: [0, 0], partition: {values: [{dimensionValue: "a", numbers: [0, 31721.57], partition: null}]}}]}}]}
console .log (flatten (partition))
.as-console-wrapper {max-height: 100% !important; top: 0}
I find this a very clean way to code.
So I have a function that when passed the parameters id (location of element), marker (updated value requested), array (nested array) it should run through a loop to match the id with the correct nested location.
It should then take the nested location and find those elements on the nested array to update it with the requested value. Though when I attempt to get it to update the value and test its working, all I am receiving in the terminal is the location of the element and not an updated array.
Am I doing something wrong with updating the nested array? This is the code
function BoardManipulation(id, marker, array) {
let match;
for (let i = 0; i < translation.length; i++) {
if(JSON.stringify(translation[i].id) === JSON.stringify(id)) {
match = translation[i].value;
return match
}
}
let newArr = array[match[0]][match[1]] = marker;
console.log(newArr)
}
let board = [["X", "O", "X"], ["X", "O", "_"], ["_", "X", "_"]];
const game = BoardManipulation(7, 'O', board);
console.log(game)
This is the translation piece that the id is checked against.
let translation = [
{ id: 0, value: [0, 0] },
{ id: 1, value: [0, 1] },
{ id: 2, value: [0, 2] },
{ id: 3, value: [1, 0] },
{ id: 4, value: [1, 1] },
{ id: 5, value: [1, 2] },
{ id: 6, value: [2, 0] },
{ id: 7, value: [2, 1] },
{ id: 8, value: [2, 2] },
];
I have to create an array of arrays based on some object attributes.
So my object looks like this:
const data = {
projectId: 5,
userIds: [2, 3, 1, 5],
dateIds: [99, 100, 101, 102, 103],
task: 'task',
duration: 8,
description: 'description'
}
Based on the userIds and dateIds I have to create an array of arrays with every attribute like this:
[[projectId, userId, dateId, task, duration, description]] <- this is what every number means
For every userId and dateId i have to create a new array.
And based on my example should be like this:
[[5, 2, 99, 'task', 8, 'description'],
[5, 3, 99 , 'task', 8, 'description'],
[5, 1, 99, 'task', 8, 'description'],
[5, 5, 99, 'task', 8, 'description'],
[5, 2, 100, 'task', 8, 'description'],
[5, 3, 100, 'task', 8, 'description']
... etc]]
Hope i explained my issue well. Thank you for your time!
My function:
const data = { projectId: 5, userIds: [2, 3, 1, 5], date: [99, 100, 101, 102], task: 'task', duration: 'duration', description: 'description' }
const parentArray = []
data.date.map(object =>
data.userIds.map(anotherObject => {
// console.log(anotherObject, object)
parentArray.push([data.projectId, object, anotherObject, data.task, data.duration, data.description])
}
))
console.log(parentArray)
const data = {
projectId: 5,
userIds: [2, 3, 1, 5],
dateIds: [99, 100, 101, 102, 103],
task: 'task',
duration: 8,
description: 'description'
}
const result = data.userIds.map(uid => {
return data.dateIds.map(did => [data.projectId, uid, did, data.task, data.duration, data.description])
}).flat();
console.log(result);
Not exactly what you asked for but using your example you can create an array of objects which might add clarity by naming the properties (if some other user needs something like this). Note how I pass in the data and reference it with this and loop through the dateId's. Key is I never have to reference the original array, perhaps making this more maintainable internally;
const data = {
projectId: 5,
userIds: [2, 3, 1, 5],
dateIds: [99, 100, 101, 102, 103],
task: 'task',
duration: 8,
description: 'description'
};
let x = [];
data.userIds.forEach(function(userid, index) {
this.dateIds.map((dateid, idx) => {
x.push({
project: this.projectId,
user: userid,
dateid: dateid,
tsk: this.task,
dur: this.duration,
desc: this.description
});
});
}, data);
x.forEach(function(el, index, array) {
console.log(el);
});
I am having these kind of array structure.
[{ "primary_product": "Blueberry",
"list_of_products": ["Raspberry","Strawberry","Blackberry"]}]
I want to destructure the pattern and make it like this below
[{"id": 1,"value":"Blueberry"},{"id": 2,"value":"Raspberry"},{"id": 3,"value":"Strawberry"}, …]
Primary product will be the first product and then make the array of strings into key/value pair. How to do this using es6?
All you need is basic functions like forEach and push. I would recommend learning these.
let arr1 = [{ "primary_product": "Blueberry", "list_of_products": ["Raspberry","Strawberry","Blackberry"]}]
arr2 = [{ id: 1, value: arr1[0].primary_product }]
arr1[0].list_of_products.forEach((element) => {
arr2.push({ id: arr2.length + 1, value: element })
})
Here's a one-liner using map on the list_of_products:
const arr = ['Raspberry','Strawberry','Blackberry'];
return arr.map((val, i) => {return {id: i+1, value: val}});
This is the result:
[
{ id: 1, value: 'Raspberry' },
{ id: 2, value: 'Strawberry' },
{ id: 3, value: 'Blackberry' }
]
Note that the callback to map includes (currentValue, index, arr).
To make things slightly easier for the eyes I've simplified the structure:
const p = [ { a: 100, b: [101, 102, 103]}
, { a: 200, b: [201, 202, 203]}];
You can flatten all the numbers into a single list i.e. [100, 101, 102, 103, 200, 201, 202, 203] with:
p.flatMap(({a, b}) => [a, ...b]);
To get closer to what you're after, let's first create an id function that will return the next number:
const id = (n => () => ++n)(0);
id(); //=> 1
id(); //=> 2
id(); //=> 3
// …
Then let's create a function obj that takes an x and wraps it into an object:
const obj => x => ({id: id(), value: x});
obj(100); //=> {id: 1, value: 100);
obj(200); //=> {id: 2, value: 200);
// …
Then you can do:
p.flatMap(({a, b}) => [obj(a), ...b.map(obj)]);
//=> [ {id: 1, value: 100}
//=> , {id: 2, value: 101}
//=> , {id: 3, value: 102}
//=> , {id: 4, value: 103}
//=> , {id: 5, value: 200}
//=> , {id: 6, value: 201}
//=> , {id: 7, value: 202}
//=> , {id: 8, value: 203}]
I have an array of objects that I want to reduce into a single object. The sample array always has the same keys in each of its objects as seen below:
sample = [
{australia: 0, belgium: 0, brazil: 0, canada: 1, china: 1, ...},
{australia: 0, belgium: 0, brazil: 3, canada: 2, china: 2, ...},
{australia: 2, belgium: 1, brazil: 4, canada: 2, china: 5, ...}
]
I am looking to obtain a single object where the keys are the same as in the objects, and the values are a concatenation of each value in the initial array.
Something like this:
desiredResult: {australia:[0,0,2],belgium:[0,0,1],brazil:[0,3,4],canada:[1,2,2],china:[1,2,5],...}
So far I have been trying the following reduce method on the array, but I am missing the part where I concatenate all the values:
let desiredResult = sample.reduce((a,b) =>({...a, desiredResult: b}),{})
// Which results in:
// desiredResult: {australia: 2, belgium: 1, brazil: 4, canada: 2, china: 5}
¿Could you help me figure out the best way to reach this solution?
You could get the entries and create new properties as array and push the value to it.
var sample = [{ australia: 0, belgium: 0, brazil: 0, canada: 1, china: 1 }, { australia: 0, belgium: 0, brazil: 3, canada: 2, china: 2 }, { australia: 2, belgium: 1, brazil: 4, canada: 2, china: 5 }],
result = sample.reduce((r, o) => {
Object.entries(o).forEach(([k, v]) => (r[k] = r[k] || []).push(v));
return r;
}, {});
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Since each of the lement in the array is again a object , you need to iterate them
let sample = [{
'australia': 0,
'belgium': 0,
'brazil': 0,
'canada': 1,
'china': 1
},
{
'australia': 0,
'belgium': 0,
'brazil': 3,
'canada': 2,
'china': 2
},
{
'australia': 2,
'belgium': 1,
'brazil': 4,
'canada': 2,
'china': 5
}
];
let newData = sample.reduce((acc, curr) => {
for (let keys in curr) {
if (!acc[keys]) {
acc[keys] = []
}
acc[keys].push(curr[keys])
}
return acc;
}, {});
console.log(newData)
You can try reduce by taking entries of element in key, value form and then pushing them using for..of in accumulator accordingly:
var sample = [{ australia: 0, belgium: 0, brazil: 0, canada: 1, china: 1 }, { australia: 0, belgium: 0, brazil: 3, canada: 2, china: 2 }, { australia: 2, belgium: 1, brazil: 4, canada: 2, china: 5 }]
const result= sample.reduce((acc, elem)=>{
countries= Object.entries(elem);
for(const [country, count] of countries){
acc[country]= acc[country] || [];
acc[country].push(count);
}
return acc;
},{});
console.log(result);