I have an array of 3 nested arrays, each containing 3 objects. What d3 syntax do I use to find the max value of data1 in all of the data?
Is it something like,
function find_max(all_data, i){
return d3.max(all_data[i].data1)
}
Here's my data structure:
all_data = [
[{data1:2, age:6},
{data1:4, age:5},
{data1:5, age:4}],
[{data1:7, age:2},
{data1:1, age:9},
{data1:0, age:8}],
[{data1:5, age:9},
{data1:6, age:9},
{data1:8, age:6}]
]
Basically, I want it to return 8. Thanks for the help!! I can't quite get it right.
We can use a mix of d3.max and Array.map operations:
d3.max(all_data.map(d => d3.max(d.map(n => n.data1)))) // 8
This finds the max of each nested array using d3.max to find the max and a map operation to transform nested arrays of objects into an array of data1 values ([2, 4, 5] for the first nested array).
[{data1:2, age:6}, {data1:4, age:5}, {data1:5, age:4}].map(n => n.data1) // [2, 4, 5]
d3.max([{data1:2, age:6}, {data1:4, age:5}, {data1:5, age:4}].map(n => n.data1)) // 5
And with each sub-max, we find the global max using d3.max again.
var all_data = [
[{data1:2, age:6},
{data1:4, age:5},
{data1:5, age:4}],
[{data1:7, age:2},
{data1:1, age:9},
{data1:0, age:8}],
[{data1:5, age:9},
{data1:6, age:9},
{data1:8, age:6}]
];
console.log(d3.max(all_data.map(d => d3.max(d.map(n => n.data1)))));
<script src="https://d3js.org/d3.v5.min.js"></script>
If you are comfortable with the notion of flatMap, you could also do as follow:
d3.max(all_data.flatMap(d => d.map(n => n.data1))); // 8
but this requires creating a flatMap function for arrays:
Array.prototype.flatMap = function(lambda) {
return Array.prototype.concat.apply([], this.map(lambda));
};
where the flatMap operation flattens the nested lists:
all_data.flatMap(d => d.map(n => n.data1)) // [2, 4, 5, 7, 1, 0, 5, 6, 8]
Finally, if you'd like to get both the max and the min at once, we can use a mix of Array.flatMap and d3.extent:
var [min, max] = d3.extent(all_data.flatMap(d => d.map(n => n.data1)));
Probably the easiest way is to nest d3.max():
function findMax(data) {
return d3.max(data, arr => // return max of all nested max values
d3.max(arr, d => d.data1) // return max of each nested array
);
}
The outer call to d3.max() uses its accessor function to get access to the maximum value of each nested array. The inner call will determine the maximum value for each nested array. For this purpose it defines an accessor function to return the data1 property.
Have a look at the following working demo:
const all_data = [
[{data1:2, age:6},
{data1:4, age:5},
{data1:5, age:4}],
[{data1:7, age:2},
{data1:1, age:9},
{data1:0, age:8}],
[{data1:5, age:9},
{data1:6, age:9},
{data1:8, age:6}]
];
function findMax(data) {
return d3.max(data, arr =>
d3.max(arr, d => d.data1)
);
}
console.log(findMax(all_data));
<script src="https://d3js.org/d3.v5.js"></script>
Alternatively, you could first use d3.merge() to merge your nested arrays into one and apply d3.max() to that merged array.
function findMax(data) {
return d3.max(d3.merge(data), d => d.data1);
}
Here is the working demo:
const all_data = [
[{data1:2, age:6},
{data1:4, age:5},
{data1:5, age:4}],
[{data1:7, age:2},
{data1:1, age:9},
{data1:0, age:8}],
[{data1:5, age:9},
{data1:6, age:9},
{data1:8, age:6}]
];
function findMax(data) {
return d3.max(d3.merge(all_data), d => d.data1);
}
console.log(findMax(all_data));
<script src="https://d3js.org/d3.v5.js"></script>
You could map the inner data1 values and get the max value and then take the result for the outer array.
var all_data = [[{ data1: 2, age: 6 }, { data1: 4, age: 5 }, { data1: 5, age: 4 } ], [{ data1: 7, age: 2 }, { data1: 1, age: 9 }, { data1: 0, age: 8 }], [{ data1: 5, age: 9 }, { data1: 6, age: 9 }, { data1: 8, age: 6 }]],
maxData1 = Math.max(...all_data.map(a => Math.max(...a.map(({ data1 }) => data1))));
console.log(maxData1);
Related
I have some data like this, an array of objects:
source = [{
day: 1,
deliveries: 16,
hours: 9
}, {
day: 2,
deliveries: 19,
hours: 11
}]
Which I would like to have in this format:
source = (['day', 'deliveries', 'hours'],
['1', '16', '9'],
['2', '19', '11'])
Sort of like a table. I read up a little on mapping arrays and tried this:
const datatable = source.map(d => Array.from(Object.keys(d)))
console.log(datatable)
// [["day", "deliveries", "hours"], ["day", "deliveries", "hours"]]
And this:
const datatable = source.map(d => Array.from(Object.values(d)))
console.log(datatable)
// [[1, 16, 9], [2, 19, 11]]
Each gives me half of what I want.
I tried this:
let datatable = source.map(d => Array.from(Object.keys(d)))
let datatable2 = source.map(d => Array.from(Object.values(d)))
datatable = datatable[1]
let combined = datatable.concat(datatable2);
console.log(combined)
///["day", "deliveries", "hours", [1, 16, 9], [2, 19, 11]]
But even here the column names are not being combined correctly, and this way seems a little messy. How do I have the keys be on top (like column names would be) and the values following them?
Assuming you want source to be an array of arrays (common for table-like structures), get the keys once, then add each row array mapping the object's properties to the key for that index:
const keys = Object.keys(source[0]);
const result = [keys, ...source.map(obj => keys.map(key => obj[key]))];
Live Example:
const source = [{
day: 1,
deliveries: 16,
hours: 9
}, {
day: 2,
deliveries: 19,
hours: 11
}];
const keys = Object.keys(source[0]);
const result = [keys, ...source.map(obj => keys.map(key => obj[key]))];
console.log(result);
.as-console-wrapper {
max-height: 100% !important;
}
Note that this assumes a couple of things:
The source array always has at least one object in it.
The objects in the source array all have the same set of properties.
You want the keys to be in the order in which they appear in the first object in the array. (JavaScript object properties do have a defined order now, but using that order is almost never a good idea, so you might want to do some kind of sort operation on keys.)
You are almost there. Just use [0] to get the first item to get only keys. And then combine the array using ....
let source = [{
day: 1,
deliveries: 16,
hours: 9
}, {
day: 2,
deliveries: 19,
hours: 11
}]
let ansArray = Object.keys(source[0]);
let datatable = source.map(d => Array.from(Object.values(d)))
let combined = [ansArray,...datatable];
console.log(combined);
Array.from(Object.keys(d)) and Array.from(Object.values(d)) will return the wrong data if the order of property is wrong.
const source = [{
day: 1,
deliveries: 16,
hours: 9
}, {
day: 2,
deliveries: 19,
hours: 11
}]
const datatable = source.reduce((acc, item, index) => {
if (index == 0) {
acc.push(Object.keys(item));
}
const newRow = acc[0].reduce((rowAcc, prop) => {
rowAcc.push(item[prop]);
return rowAcc;
}, []);
acc.push(newRow);
return acc;
}, [])
console.log(datatable);
Is there any operation in Javascript just like [x for x in array] in python?
For example, I'm using javascript to reading a json file where there're dozens of (key, value) pairs needed to be handled(or transformed into other format). And I thought working in this way is stupid:
let transformed = []
for (let key in json){
transformed = [ /* doing some transform*/ ]
}
Is there anything like:
let transformed = [
lambda function1(key), lambda function2(value) for key, value in json
]
Thanks in advance.
The rough equivalent of Python's list comprehension is Array.map:
const myArray = [1, 2, 3]
const transformed = myArray.map((item) => item + 1)
// [2, 3, 4]
But your example is not about an array, but about an Object with keys and values. In Python, this would be a dict, and you'd use a dict comprehension along the lines of {function1(key): function2(value) for key, value in my_dict.items()}.
In JavaScript, you can turn such an object into an array with Object.entries, then perform the map, and finally transform it back into an object using Object.fromEntries:
const myObject = { a: 1, b: 2 }
const transformed = Object.fromEntries(Object.entries(myObject)
.map(([key, value]) => [key + 'x', value + 1]))
// { ax: 2, bx: 3 }
Note that fromEntries is fairly new and you might need to add a polyfill for it.
You can use a code likes this. You must use a function that handle operation on current single item.
const words = ['hello', 'bird', 'table', 'football', 'pipe', 'code'];
const capWords = words.forEach(capitalize);
function capitalize(word, index, arr) {
arr[index] = word[0].toUpperCase() + word.substring(1);
}
console.log(words);
// Expected output:
// ["Hello", "Bird", "Table", "Football", "Pipe", "Code"]
First of all, javascript does NOT support Associative Arrays. If you are used to them in Python, PHP, and other languages you need to do a little workaround in JS to achieve the same functionality.
The most common way to simulate an associative array is using an object.
let testObject = {name: "Color", value: "Red"};
And then you push every object into an array so you end up with something like this:
let testArray = [{name: "Color", value: "Red"}, {name: "Color", value: "Blue"}];
Once you have this array consisting of objects, you can use map function to go through every object in the array and do whatever you want with it.
testArray.map((item, index) => {
console.log("The value of "+index+". item is: "item.value);
})
You can use Array.map() function. It work pretty like Array.forEach() function
const numbers = [1, 2, 3, 4, 5]
let newArray = numbers.map((element) => {
return element * 2
})
console.log(newArray) // excepted : [ 2, 4, 6, 8, 10 ]
It can be reduce using
const numbers = [1, 2, 3, 4, 5]
let newArray = numbers.map(element => element * 2)
console.log(newArray) // excepted : [ 2, 4, 6, 8, 10 ]
For more informations, you can this documentation https://developer.mozilla.org/fr/docs/Web/JavaScript/Reference/Global_Objects/Array/map
In C# if I had a list for example of 3 ints [1,2,3], I could trasform that list into another with .Select in following way [1,2,3].Select(e => new { Id = e, Name = $"name:{e}"), which would return new array with 3 objects.
how can I get the same result in js without using for loop?
You can use the map function like this:
var array = [1,2,3]
var result = array.map(e => ({id: e, name: `name:${e}`}))
console.log(result)
It returns the following result:
[ { id: 1, name: 'name:1' },
{ id: 2, name: 'name:2' },
{ id: 3, name: 'name:3' } ]
Here is the map function docs:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map
Yes, it is called map(example with integers, but you can map into objects too):
const array1 = [1, 4, 9, 16];
const map1 = array1.map(x => x * 2);
console.log(map1);
// expected output: Array [2, 8, 18, 32]
I'm a Javascript beginner (more or less).
I've created a new array:
var genres = [
"metal",
"rockroll",
"funk",
"punk",
"country",
];
However, I'd like to put each genre in the array a specific number of times, not just once. I know I can just repeat each line as many times as I need, but I'm sure there's a better way.
It would be great if I could do something like this:
var genres = [
"metal" * 3,
"rockroll" * 5,
"funk" * 1,
"punk" * 0,
"country" * 4,
];
...but of course I've tried that, and it doesn't work.
Can anyone help me out? I wasn't able to find anything by googling.
Thanks!
You can build an array like this with reduce() if you start with some data structure that holds your counts and categories:
let cats = [[3, "metal"], [5, "rockroll"], [1, "funk"], [0, "punk"], [4, "country"] ]
// etc..
let arr = cats.reduce((arr, [n, cat]) => arr.concat(Array(n).fill(cat)), [])
console.log(arr)
let item = [
{
genres: "metal",
count: 3
},
{
genres: "rockroll",
count: 5
},
{
genres: "funk",
count: 1
},
{
genres: "punk",
count: 0
}
];
console.log(item);
item.map(i => {
for(let n = 0; n < i.count; n++){
console.log(i.genres);
}
});
How do you think about using the Object?
There's no built-in way to do this, but you could easily write a function to do it. For instance:
function addMultiples (input) {
const output = []
for (let key in input) {
for (let i = 0; i < input[key]; i++) {
output.push(key)
}
}
return output
}
Then you would pass in your values as an object:
console.log(addMultiples({
"metal": 3,
"rockroll": 5,
"funk": 1,
"punk": 0,
"country": 4
}).join(", "))
// prints "metal, metal, metal, rockroll, rockroll, rockroll, rockroll, rockroll, funk, country, country, country, country"
You can also use Array.from and keep your sub arrays filled. And only spread them when needed:
let cats = [[3, "metal"], [5, "rockroll"], [1, "funk"], [0, "punk"], [4, "country"]]
const filled = Array.from(cats, ([v,k]) => new Array(v).fill(k)) // fill arrays
console.log(filled.reduce((r,c) => [...r, ...c])) // spread for output
When Promise.all completes it returns an array of arrays that contain data. In my case the arrays are just numbers:
[
[ 1, 4, 9, 9 ],
[ 4, 4, 9, 1 ],
[ 6, 6, 9, 1 ]
]
The array can be any size.
Currently I'm doing this:
let nums = []
data.map(function(_nums) {
_nums.map(function(num) {
nums.push(num)
})
})
Is there an alternative way of doing this? Does lodash have any functions that are able to do this?
ES2019 introduced Array.prototype.flat which significantly simplifies this to:
const nums = data.flat();
const data = [
[ 1, 4, 9, 9 ],
[ 4, 4, 9, 1 ],
[ 6, 6, 9, 1 ]
];
const nums = data.flat();
console.log(nums);
Original Answer
Use reduce and concat:
data.reduce(function (arr, row) {
return arr.concat(row);
}, []);
Or alternatively, concat and apply:
Array.prototype.concat.apply([], data);
I would do as follows;
var a = [
[ 1, 4, 9, 9 ],
[ 4, 4, 9, 1 ],
[ 6, 6, 9, 1 ]
],
b = [].concat(...a)
console.log(b)
You actually don't need any sort of library to do it, you can use concat with apply:
Promise.all(arrayOfPromises).then((arrayOfArrays) => {
return [].concat.apply([], arrayOfArrays);
});
If you are using lodash, though, you can use _.flatten(arrayOfArrays) for the same effect.
If using async/await, to expand on #Retsam's answer, you can do it like so
const mergedArray = []
.concat
.apply([], await Promise.all([promise1, promise2, promiseN]));
A real world example I did using the AWS SDK, getting a list of usernames from multiple IAM user groups
const users = await getActiveUsersByGroup(['group1', 'group2'])
async function getActiveUsersByGroup(groups = []) {
getUsersByGroupPromises = groups.map(group => getUsersByGroup(group));
const users = []
.concat
.apply([], await Promise.all(getUsersByGroupPromises)) // Merge (concat) arrays
.map(users => users.UserName); // Construct new array with just the usernames
return users;
}
async function getUsersByGroup(group) {
const params = {
GroupName: group,
MaxItems: 100 // Default
};
const { Users: users } = await iam.getGroup(params).promise();
return users;
}