javascript, convert an array of objects to an array of arrays vertically - javascript

I have a CSV file that I have successfully read in with d3.csv. The result is a JSON file where each line consists of an array element and each array element is an object with key/value pairs matching the column headers.
I need this in a "vertical" format, as an array of arrays, where each inner array consists of the value for each object.
Here is an example to run in Node:
> a = new Array();
[]
> a.push({"b":2, "c": 4, "d":6, "e": 8});
1
> a.push({"b":3, "c": 6, "d":9, "e": 12});
2
> a.push({"b":4, "c": 8, "d":12, "e": 16});
3
> a.push({"b":5, "c": 10, "d":15, "e": 20});
4
> a
[
{ b: 2, c: 4, d: 6, e: 8 },
{ b: 3, c: 6, d: 9, e: 12 },
{ b: 4, c: 8, d: 12, e: 16 },
{ b: 5, c: 10, d: 15, e: 20 }
]
> x = [[2,3,4,5],[4,6,8,10],[6,9,12,15],[8,12,16,20]]
[ [ 2, 3, 4, 5 ], [ 4, 6, 8, 10 ], [ 6, 9, 12, 15 ], [ 8, 12, 16, 20 ] ]
> x
[
[ 2, 3, 4, 5 ],
[ 4, 6, 8, 10 ],
[ 6, 9, 12, 15 ],
[ 8, 12, 16, 20 ]
]
>
Here, [a] represents the array of object I have while [x] represents the array of arrays I would like to have.
My data file is very wide and has many columns. I have tried several toy solutions, and I can iterate through the array, select each element, then iterate through each element and select each key, grab the value, and push it to a new array. However, this is nasty and very easy to break. Surely there is a better way.
If I had a list of lists, I could flip the rows and columns. Unfortunately, I have a list of object, read in with D3.csv().
My primary language was (note, was) Perl, and a Perl-ish solution is natural to me. My current application runs client side in a browser, and I need a client side solution in JavaScript.

You can achieve this in a number of ways, but since it appears that all objects in your source array have the same properties, the most direct may be a nested map() call. The outer map() is called on the Object.keys() of the first element of the array, and the inner map() uses each iterated key on every object in the source array.
const a = [{ b: 2, c: 4, d: 6, e: 8 }, { b: 3, c: 6, d: 9, e: 12 }, { b: 4, c: 8, d: 12, e: 16 }, { b: 5, c: 10, d: 15, e: 20 }];
const result = Object.keys(a[0]).map(key => a.map(o => o[key]));
console.log(result);
If the objects had varying properties, you could use a reduce() call to accumulate all the values of like properties.
const a = [{ b: 2, c: 4, d: 6, e: 8 }, { b: 3, c: 6, d: 9, e: 12 }, { b: 4, c: 8, d: 12, e: 16 }, { b: 5, c: 10, d: 15, e: 20 }];
const result = Object.values(
a.reduce((acc, obj) => {
Object.keys(obj).forEach(key =>
(acc[key] ??= []).push(obj[key]));
return acc;
}, {}));
console.log(result);

I like #pilchard's d3 agnostic answer; but if you're interested in a d3 driven answer you can use d3.transpose on an array of arrays with a pre-processing step of removing the keys of the objects with Object.values:
const a = [
{ b: 2, c: 4, d: 6, e: 8 },
{ b: 3, c: 6, d: 9, e: 12 },
{ b: 4, c: 8, d: 12, e: 16 },
{ b: 5, c: 10, d: 15, e: 20 }
]
const x = d3.transpose(a.map(o => Object.values(o)));
console.log(x);
.as-console-wrapper { max-height: 100% !important; top: 0; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/6.5.0/d3.min.js"></script>

Related

How to reassign values in a js object based on the values present in an object within the same object?

I have an array of objects in the following form-
let result = [
{
a: 1,
b: 2,
c: 3,
newValues: {
a: 10,
b: 20,
c: 30
}
},
{
d: 4,
e: 5,
f: 6,
newValues: {
d: 40,
e: 50,
f: 60
}
}
]
And want to convert it to following format -
let result = [
{
a: 10,
b: 20,
c: 30,
},
{
d: 40,
e: 50,
f: 60
}
]
But have been unable to do so.
Any help for converting the older array to the new one will be very much appreciated.
A simple map will do it
let result = [
{
a: 1,
b: 2,
c: 3,
newValues: {
a: 10,
b: 20,
c: 30
}
},
{
d: 4,
e: 5,
f: 6,
newValues: {
d: 40,
e: 50,
f: 60
}
}
]
let data = result.map( r => r.newValues)
console.log(data)
The problem by mapping only the r.newValues is you can potentially lost data that never changed and are not in newValues.
const result = [
{
a: 1,
b: 2,
c: 3,
newValues: {
a: 10,
b: 20,
c: 30
}
},
{
d: 4,
e: 5,
f: 6,
newValues: {
d: 40,
e: 50
}
}
];
const updates = result.map(element => {
const {newValues, rest} = element;
delete element.newValues;
return {...element, ...newValues};
});
console.log(updates);
It will work even if a value of newValues was not present into newValues.
The following answer is roughly equivalent to the one by JStw, with two key differences:
It uses Underscore instead of spread syntax;
It does not modify the elements of result.
This means that code is easier to reason about and potentially safer. Also, you don't need polyfills for the spread syntax.
const result = [
{
a: 1,
b: 2,
c: 3,
newValues: {
a: 10,
b: 20,
c: 30
}
},
{
d: 4,
e: 5,
f: 6,
newValues: {
d: 40,
e: 50
}
}
];
const updates = _.map(result, element =>
_.chain(element)
.omit('newValues')
.extend(element.newValues)
.value()
);
console.log(updates);
<script src="https://cdn.jsdelivr.net/npm/underscore#1.13.6/underscore-umd-min.js"></script>

How can I get all the object inside an object which is present inside an array and add the result into another array

I am struggling with an issue that is bugging me a lot. I am not good with JSON data manipulation.
So the issue is I have an Array of multiple Object which contain some data, Now inside these objects, I have another array of objects which I want
the JSON looks something like this-
const data = [{
a: 2,
b: 3,
c: 4,
d: [{
e: 5,
f: 4,
g: 6,
}, {
h: 5,
i: 4,
j: 6,
}]
}, {
a: 11,
b: 31,
c: 42,
d: [{
e: 54,
f: 46,
g: 62,
}, {
h: 55,
i: 42,
j: 64,
}]
}]
Now What I want is an Array which holds the following data
const d = [{
e: 5,
f: 4,
g: 6,
}, {
h: 5,
i: 4,
j: 6,
}, {
e: 54,
f: 46,
g: 62,
}, {
h: 55,
i: 42,
j: 64,
}]
I tried mapping over the data but I always end up with an array that look
const data = [
[{
e: 5,
f: 4,
g: 6,
}, {
h: 5,
i: 4,
j: 6,
}],
[{
e: 54,
f: 46,
g: 62,
}, {
h: 55,
i: 42,
j: 64,
}]
]
Not sure what am i doing wrong. need some help
You can loop over the data and then loop over the data.d again to get all of the required data. For each of the data, you push it into another array that you will later use.
const data = [{a:2,b:3,c:4,d:[{e:5,f:4,g:6,},{h:5,i:4,j:6,}]},{a:11,b:31,c:42,d:[{e:54,f:46,g:62,},{h:55,i:42,j:64,}]}]
let result = [];
data.forEach(d => d.d.forEach(dd => result.push(dd)));
console.log(result);

Delete property and its values in all the object

I'm a beginner in javaScript, I have this object MyGraph:
const MyGraph = {
a: { b: 5, c: 2 },
b: { a: 5, c: 7, d: 8 },
c: { a: 2, b: 7, d: 4, e: 8 },
};
I want to delete property "a" and its values in other properties as well to get this result:
const MyGraph = {
b: { c: 7, d: 8 },
c: { b: 7, d: 4, e: 8 },
};
I tried like this:
for(let XXX of Object.keys(MyGraph)){
console.log(XXX.a);
delete XXX.a;
}
the result of execution:
undefined
undefined
undefined
any help!
You could use a recursive algorithm :
function del_entries(key, obj) {
if (obj.hasOwnProperty(key)) {
delete obj[key];
}
// Or with Object.hasOwn, not fully supported by old browsers but more up to date
/*
if (Object.hasOwn(obj, key)) {
delete obj[key]
}
*/
Object.values(obj).forEach(o=> del_entries(key, o))
}
const MyGraph = {
a: { b: 5, c: 2 },
b: { a: 5, c: 7, d: 8 },
c: { a: 2, b: 7, d: 4, e: 8 },
};
del_entries("a", MyGraph);
console.log(MyGraph)
In your code XXX is the key. You need to do graph[XXX] to access the actual object. So instead of XXX.a you should do graph[XXX].a. But this only accounts for objects in graph that have an the key a. You also need to account for key a in graph. Please see the code below. Its a rudimentary example.
If you have one level of nesting then you can use then you can use the code below.
const mygraph = {
a: { b: 5, c: 2 },
b: { a: 5, c: 7, d: 8 },
c: { a: 2, b: 7, d: 4, e: 8 },
};
console.log(mygraph);
function deletePropAndValuesOf(key, graph) {
for (const k of Object.keys(graph)) {
if (k === key) {
delete graph[key];
} else {
if (key in graph[k]) {
delete graph[k][key]
}
}
}
}
deletePropAndValuesOf("a", graph);
console.log(mygraph);
You can copy the code to a .js file and run it using node. e.g.
Ive used object destructuring to remove the first array with an a, but could not figure out how to do all the a's's but the code below might help?
const MyGraph = {
a: { b: 5, c: 2 },
b: { a: 5, c: 7, d: 8 },
c: { a: 2, b: 7, d: 4, e: 8 }};
const {a, ...newMyGraph} = MyGraph;
// output
console.log(newMyGraph)
returns
b: {
a: 5,
c: 7,
d: 8
},
c: {
a: 2,
b: 7,
d: 4,
e: 8
}
}

map array of objects based on set of properties

Suppose I have an object:
let array = [
{a: 1, b: 5, c: 9},
{a: 2, b: 6, c: 10},
{a: 3, b: 7, c: 11},
{a: 4, b: 8, c: 12}
];
then I have a dictionary:
const columns = [
{ key: 'a', value: 'a' },
{ key: 'b', value: 'b' },
]
I want to filter out properties that are not defined in columns.
I have tried
array.map((x) => ({"a": x.a, "b": x.b}))
Is there a way to use the data defined in columns instead of manually typing all the properties?
Desired output:
[
{
"a": 1,
"b": 5
},
{
"a": 2,
"b": 6
},
{
"a": 3,
"b": 7
},
{
"a": 4,
"b": 8
}
]
You could map entries and get the new objects.
let
array = [{ a: 1, b: 5, c: 9 }, { a: 2, b: 6, c: 10 }, { a: 3, b: 7, c: 11 }, { a: 4, b: 8, c: 12 }],
columns = [{ key: 'a', value: 'a' }, { key: 'b', value: 'b' }],
keys = columns.map(({ key }) => key),
result = array.map(o => Object.fromEntries(keys.map(k => [k, o[k]])));
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
You could use this.
This uses just an array to hold the desired columns because I don't get why you would use a dictionary with key and value being the same.
let array = [
{ a: 1, b: 5, c: 9 },
{ a: 2, b: 6, c: 10 },
{ a: 3, b: 7, c: 11 },
{ a: 4, b: 8, c: 12 },
];
const desiredColumns = ["a", "b"];
const transformed = array.map(item => {
const obj = {};
desiredColumns.forEach(col => {
if(col in item){
obj[col] = item[col];
}
})
return obj;
})
console.log(array);
console.log(transformed)
Another, slightly less direct way using map() and reduce():
Create an array with all the keys we'll keep
Reduce the array to get the desired result
Add current key + value if key keep array
const array = [{a: 1, b: 5, c: 9}, {a: 2, b: 6, c: 10}, {a: 3, b: 7, c: 11}, {a: 4, b: 8, c: 12} ];
const columns = [{ key: 'a', value: 'a' }, { key: 'b', value: 'b' }, ];
const toKeep = columns.map(({ key }) => key).flat();
const result = array.map(a =>
Object.keys(a)
.reduce((prev, cur) => (toKeep.includes(cur)) ? { ...prev, [cur]: a[cur] } : prev, {})
);
console.log(result);
Result:
[
{
"a": 1,
"b": 5
},
{
"a": 2,
"b": 6
},
{
"a": 3,
"b": 7
},
{
"a": 4,
"b": 8
}
]

How to reshaping Data in Javascript from array to object without losing some of the data

I am trying to add the key to each so that I can be able to easy make a multi scatter plot in d3. . I am not sure how to do it.
EDIT: TO CLARIFY what I meant.
Data:
var dataOriginal = {
Apples: [{"A":4,"B":null,"C":null,"D":2}, {"A":5,"B":null,"C":3,"D":2}],
Oranges: [{"A":3,"B":1,"C":4,"D":4.3}],
Jackfruit: [{"A":5,"B":4,"C":4,"D":3}],
Avocado: [{"A":null,"B":33,"C":2,"D":9.66}],
Pomegranate: [{"A":5,"B":3.5,"C":null,"D":6}]
}
Function:
const data = Object.keys(dataOriginal).map((key) => {
const temp = {...dataOriginal[key]};
temp.key = key;
return temp;
});
Results:
0:
0: {A: 4, B: null, C: null, D: 2}
1: {A: 5, B: null, C: 3, D: 2}
key: "Apples"
__proto__: Object
1:
0: {A: 3, B: 1, C: 4, D: 4.3}
key: "Oranges"
__proto__: Object
2:
0: {A: 5, B: 4, C: 4, D: 3}
key: "Jackfruit"
__proto__: Object
3:
0: {A: null, B: 33, C: 2, D: 9.66}
key: "Avocado"
__proto__: Object
4: {0: {…}, key: "Pomegranate"}
Desired results
: {A: 4, B: null, C: null, D: 2, key: "Apples"}
1: {A: 3, B: 1, C: 4, D: 4.3, key: "Oranges"}
2: {A: 5, B: 4, C: 4, D: 3, key: "Jackfruit"}
3: {A: null, B: 33, C: 2, D: 9.66, key: "Avocado"}
4: {A: 5, B: 3.5, C: null, D: 6, key: "Pomegranate"}
5: {A:5,B:null,C:3,D:2, key: "Apples"}
You need to reduce the object to get a single object with added values.
const
addByKey = array => array.reduce((a, b) => {
Object.entries(b).forEach(([k, v]) => a[k] = (a[k] || 0) + v);
return a;
}, {}),
dataOriginal = { Apples: [{ A: 4, B: null, C: null, D: 2 }, { A: 5, B: null, C: 3, D: 2 }], Oranges: [{ A: 3, B: 1, C: 4, D: 4.3 }], Jackfruit: [{ A: 5, B: 4, C: 4, D: 3 }], Avocado: [{ A: null, B: 33, C: 2, D: 9.66 }], Pomegranate: [{ A: 5, B: 3.5, C: null, D: 6 }] }
data = Object.keys(dataOriginal).map((key) => ({ ...addByKey(dataOriginal[key]), key }));
console.log(data);
.as-console-wrapper { max-height: 100% !important; top: 0; }
For getting single object with same keys, you could map the objects, add the key and get a flat array.
const
dataOriginal = { Apples: [{ A: 4, B: null, C: null, D: 2 }, { A: 5, B: null, C: 3, D: 2 }], Oranges: [{ A: 3, B: 1, C: 4, D: 4.3 }], Jackfruit: [{ A: 5, B: 4, C: 4, D: 3 }], Avocado: [{ A: null, B: 33, C: 2, D: 9.66 }], Pomegranate: [{ A: 5, B: 3.5, C: null, D: 6 }] }
data = Object
.keys(dataOriginal)
.flatMap(key => dataOriginal[key].map(o => ({ ...o, key })));
console.log(data);
.as-console-wrapper { max-height: 100% !important; top: 0; }
The reason why {"A":5,"B":null,"C":3,"D":2} is missed is because, index 0 is hardcoded in the code.
const temp = {...dataOriginal[key][0]};
Alternate solution:
var dataOriginal = {
Apples: [{"A":4,"B":null,"C":null,"D":2}, {"A":5,"B":null,"C":3,"D":2}],
Oranges: [{"A":3,"B":1,"C":4,"D":4.3}],
Jackfruit: [{"A":5,"B":4,"C":4,"D":3}],
Avocado: [{"A":null,"B":33,"C":2,"D":9.66}],
Pomegranate: [{"A":5,"B":3.5,"C":null,"D":6}]
}
const myData =[]
Object.keys(dataOriginal).map((key) => {
for (let i = 0; i < dataOriginal[key].length; i++) {
myData.push({...dataOriginal[key][i], key})
}
})
console.log(myData)

Categories

Resources