If I have a CSV file that looks like this:
Year,Value1,Value2,Value3
2000,500,20,30
2001,40,30,20
2002,90,12,80
2003,70,55,22
...
I can read this in with D3 JS using the d3.csv("./file.csv").then(function (data)) method and I'll get data that looks like this:
[
{ Value1: "500", Value2: "20", Value3: "30", Year: "2000"},
{ Value1: "40", Value2: "30", Value3: "20", Year: "2001"},
{ Value1: "90", Value2: "12", Value3: "80", Year: "2002"},
{ Value1: "70", Value2: "55", Value3: "22", Year: "2003"}
]
This is great. It formats the data perfectly for what I need. Unfortunately for me, the incoming data I'll be working with is actually an array of arrays that will look like this:
[
["Year","Value1","Value2","Value3"],
[2000,500,20,30],
[2001,40,30,20],
[2002,90,12,80],
[2003,70,55,22]
]
Is there a built in method in D3 that will do to this array of arrays what the d3.csv() method does to CSV? As in, is there a method that will take in the array of arrays and turn it into an array of objects where each column header is associated with it's value in the given row?
So far the best solution I've come up with is to just turn the array of arrays into CSV and then parse it with D3 like this (I'm putting double quotes around each value in case of commas in values):
let csv = "";
for (const array of arrays) {
csv += '"' + array.join('","') + '"\r\n';
}
const data = d3.csvParse(csv);
This just feels a bit clunky to me, so I'm wondering if there's a quicker way to do this.
You can do this with pure JS, mapping each row to an object that you can build with reduce.
var data = [
["Year", "Value1", "Value2", "Value3"],
[2000, 500, 20, 30],
[2001, 40, 30, 20],
[2002, 90, 12, 80],
[2003, 70, 55, 22]
];
var result = data.slice(1)
.map(row => row.reduce((acc, curr, i) => {
acc[data[0][i]] = curr;
return acc;
}, {}));
console.log(result);
Related
This question already has answers here:
Create an object from an array of keys and an array of values
(9 answers)
Create object from two arrays
(4 answers)
Closed 2 years ago.
Having two arrays:
let values = ["52", "71", "3", "45", "20", "12", "634", "21"];
let names = ["apple", "orange", "strawberry", "banana", "coconut", "pineapple", "watermelon", "plum"];
How can I create an object like:
{
"apple": 52,
"orange": 71,
"strawberry": 3,
"banana": 45,
"coconut": 20,
"pineapple": 12,
"watermelon": 634,
"plum": 21
}
I tried using Object.assign but this only overrides the values.
Object.assign<any, any>(names, values);
Object.defineProperties doesn't work as well or - more likely - I don't know how to use them.
EDIT
I tried the
let temp = {};
names.forEach((item, index) => {
console.log('item: ', item);
console.log('index: ', index);
console.log('temp[item]: ', temp[item]);
console.log('values[index]: ', values[index]);
temp[item] = values[index];
console.log(names);
});
but this is what I got
Create a new result-object. Add to this object foreach element of names a nnew object with name and corresponding value.
Edited: Because it seems tht you have in your values-array all elements as string and in your result-object the values are integers I use parseInt for convertion.
Note: Using a variable name is not so good because you get an TypeError if you want to use anything like this name.forEach, name.map. It seems it's a reserved word or something like this.
let values = ["52", "71", "3", "45", "20", "12", "634", "21"];
let names = ["apple", "orange", "strawberry", "banana", "coconut", "pineapple", "watermelon", "plum"];
let temp = {};
names.forEach((elem, index) => { temp[elem]=parseInt(values[index]) });
names.forEach((item, index) => {
console.log('item: ', item);
console.log('index: ', index);
console.log('temp[item]: ', temp[item]);
console.log('values[index]: ', values[index]);
temp[item] = values[index];
console.log(names);
});
I have two arrays of objects:
[
0: {key1: value1, key2: value2, key3: value3},
1: {key1: value1, key2: value2, key3: value3}
]
[
0: {stop_id: 173, file_id: "1", key_type: null, key_value: "0020", seg_beg: 32},
1: {stop_id: 176, file_id: "1", key_type: null, key_value: "0201", seg_beg: 10},
2: {stop_id: 176, file_id: "1", key_type: null, key_value: "0201", seg_beg: 10}
]
I need to check to see if the values of any of the keys in the first object, match any of the values of the key_value...keys, in the second object, and then set a variable further up to the stop_id value in the matched record. Like this:
if(object1.value === object2.key_value){
match = object2[iterator].stop_id;
}
To simplify this, I have attempted to just grab the values of the first object:
//pd.segs is object 1
let pdSegValues = [];
for(let i=0;i<pd.segs.length;i++){
pdSegValues.push(Object.values(pd.segs[i]));
}
But that gets me an array of arrays again, and basically puts me back in the same situation. I'm suffering from a fried brain, and admittedly have a weakness for loops. Can anyone show me a decent way to accomplish what I need here?
You can do this by collecting the values you want to test and then using some.
let arr1 = [
{"a1": "value1", "b1": "value2"},
{"a2": "0020", "b2": "value22"},
{"a3": "value111", "b3": "0201"}
];
let arr2 = [
{stop_id: 173, file_id: "1", key_type: null, key_value: "0020", seg_beg: 32},
{stop_id: 176, file_id: "1", key_type: null, key_value: "0201", seg_beg: 10},
{stop_id: 176, file_id: "1", key_type: null, key_value: "0201", seg_beg: 10}
];
// accumulate unique arr1 values to an array
let arr1Values = Array.from(arr1.reduce((acc, curr) => {
Object.values(curr).forEach(v => acc.add(v));
return acc;
}, new Set()));
// accumulate all unique arr2 "key_value"
let arr2KeyValues = arr2.reduce((acc, curr) => {
acc.add(curr.key_value);
return acc;
}, new Set());
console.log(arr1Values);
console.log(Array.from(arr2KeyValues));
// Test if any of the values in objects in the first array are
// equal to any of the key_values in the second array
console.log(arr1Values.some(k => arr2KeyValues.has(k)));
It looks like you're going to have to compare every object in one array to every object's keys in another array. An initial brute force approach has 3 nested for loops:
// Loop through the objects in the first array
for (const objectA of arrayA) {
// Loop through that object's keys
for (const key in objectA) {
// Loop through the objects in the second array
for (const objectB of arrayB) {
if (objectA[key] === objectB.key_value) {
// do all the stuff
}
}
}
}
Here's what I ended up doing, just to leave a record :)
let stopRules = pd.stopRules;
let pdSegs = pd.segs;
let routeStopsTest = [];
//Returns a flat array of all unique values in first object
//Thanks #slider!
let pdSegValues = Array.from(pdSegs.reduce((acc, curr) => {
Object.values(curr).forEach(v => acc.add(v));
return acc;
}, new Set()));
//Pushes all objects from stopRules array to a holding array
//When they match individual segments in the pdSegs array
pdSegValues.forEach( seg => {
let nullTest = stopRules.filter(o => o.key_value === seg);
if(nullTest.length !== 0){
routeStopsTest.push(nullTest);
}else{}
});
Then all I have to do is flatten the resulting array of objects, and I have the results I need, which I can then loop through for the original purpose.
Thank you, everyone, for the insightful input. I've learned a fair bit here :)
From ES2015 with computed properties and Array.reduce/Array.map/Object.assign you can do:
[{name: 'foo', age: 43}, {name: 'bar', age: 55}].map(
o => ({[o.name]: o.age})).reduce((a, b) => Object.assign(a,b), {})
…and get:
{ foo: 43, bar: 55 }
How do I get this from JMESPath?
Attempt:
$echo '[{"name": "foo", "age": 43}, {"name": "bar", "age": 55}]' | jp [].{name:age}
[
{
"name": 43
},
{
"name": 55
}
]
Problem
How to construct a Jmespath query that returns objects with arbitrary key-value pairs
The keys need to be dynamic, based on the output of a jmespath filter expression
Workaround
As of this writing (2019-03-22), dynamic keys are not available in standard Jmespath
However, it is possible to return a list of lists instead of a list of objects, and simply post-process that list of lists outside of jmespath
Example
[*].[#.name,#.age]
Returns
[['foo', 43], ['bar', 55]]
Which can then be post-processed outside of Jmespath, if that is an option for you.
See also
github issue about this exact use-case
To get this result precisely:
{ "foo": 43, "bar": 55 }
You should use this query:
#.{foo: #[0].age, bar: #[1].age}
But as you can see I don't retrieve the keys foo and bar dynamically because I can't do it in JMESPath.
I get a JSON strings through JSONP call. I just know that how the general structure of JSON is going to be but I do not know what will be the values and keys. The general structure will be like this
[
{"key_name": "value"},
{"key_name": "value"},
{"key_name": "value"}
]
I do not know what will be inside curly brackes. How can I reach these values and change them to something like this
[
{name: "key_name", y: value},
{name: "key_name", y: value},
{name: "key_name", y: value}
]
where value is a number
example fiddle:
Use Array.prototype.map() on the array of objects. Fetch the array of keys of an object using Object.keys()
var x = [{
"key_name1": "25"
}, {
"key_name2": "452"
}, {
"key_name3": "32"
}];
var new_x = x.map(function(el) {
return {
"name": Object.keys(el)[0],
"y": +el[Object.keys(el)[0]]
};
});
console.log(new_x);
I need to select two fields out of three fields from Json data using Linq.js
Required output should be
[{ "A": -27, C: "country 1" } , { "A": 28 , C: "country 2"} ]
using "linq.js" from following path: [ https://raw.github.com/gist/1175460/fb7404d46cab20e31601740ab8b35d99a584f941/linq.js ]
Sample data
var Data = [{ "A": -27, "B": -39, C: "country 1" }, { "A": 28, "B": 0 , C: "country 2"}]
var filter = " x => x['A'], x['C'] ";
var findItem = Enumerable.From(Data)
.Select(filter)
.ToArray();
console.log(findItem);
code at JsFiddle : http://jsfiddle.net/gLXNw/9/
Your "lambda" function must return a valid java object.
Your query should be more like this:
var query = Enumerable.From(data)
.Select("x => { A: x['A'], X: x['C'] }") // object initializer
.ToArray();
You can use function in result selector instead of lambda (if lambda expression was used not for political reasons :))
var findItem = Enumerable.From(Data)
.Select(function(x){
return {
'A': x['A'],
'X': x['C']
};
}).ToArray();