I have some data, which is the time in seconds (from people completing a workout). I want to graph these times in HighCharts, but I feel like I'm going about this all wrong. Right now I'm having to fill in the spaces between values with 0's. Also, note that some people finished in the exact same times
//Time in seconds, already ordered
var rawData = [183, 189, 195, 237, 256, 298, 306, 314, 328, 330, 330, 330, 338, 364, 370, 411, 411, 458, 474, 513, 513, 566, 572, 574, 600];
//Get the smallest & largest values.
//This is simple since it's already ordered
var min = rawData[0];
var max = rawData[rawData.length - 1];
//Now fill in the missing places in the data.
//Count how many items have the exact same value
var graphData = [];
for (var i = min; i <= max; i++) {
graphData.push(_.filter(rawData,function(m){
return m === i;
}).length);
}
I know this can't be the best way to do what I want, and I know it has some bugs with it. Can anyone suggest a better way of doing this?
Demo: http://codepen.io/chrismbarr/pen/epGGYX?editors=001
You don't need to do that. You only need to create a 2D array with the x and y values, eg.
var graphData = [];
for (var i in rawData) {
graphData.push([rawData[i], _.filter(rawData,function(m){
return m === rawData[i];
}).length]);
}
which creates an array like
[
[183, 1],
[189, 1],
[195, 1],
[237, 1],
[256, 1],
[298, 1],
// so on
[330, 3],
[330, 3],
[330, 3],
// ...
]
Update
another option is
var graphData = [];
for (var i = min; i <= max; i++) {
var ocurrences = _.filter(rawData, function(m){
return m === i;
}).length;
if (ocurrences > 0) {
graphData.push([i,ocurrences]);
}
}
which creates
[
[183, 1],
[189, 1],
[195, 1],
[237, 1],
[256, 1],
[298, 1],
// so on
[330, 3],
// ...
]
Both options work, you don't have to worry about the repeated items in the first resulting array since Highcharts draws the bars exactly in the same position, so you won't notice the difference.
Demo http://codepen.io/anon/pen/RWLjed?editors=001
Related
I'm doing some exercises on JavaScript and I came into a question that asks to rotate arrays item to the left with a given n rotation steps. The exercises are tested with Jasmine. Tried several method but none are meeting the precondition:
it("Arrays: Rotation Gauche", function () {
// DESCRIPTION:
// A left rotation operation on an array shifts each element
// from the array to the left. For example, if left rotations are
// done on the array [1,2,3,4,6], the array would become [3,4,5,1,2]
//
// Given an array of integers a, do n left rotations on
// the array. The function returns the updated array.
function rotateLeft(a, n) {
// TODO: implement the function as described in DESCRIPTION
let len = 0,j=0
var b =[]
len = a.length
for (let i = n; i < len; i++){
b[j] = a[i]
j++
}
for (let i = 0; i < n; i++){
b[j] = a[i]
j++
}
return b;
}
// Jasmin unit tests
let input = [1, 2, 3, 4, 6];
let expected = [3, 4, 5, 1, 2];
expect(rotateLeft(input, 4)).toBe(expected);
input = [41, 73,89,7,10,1,59,58,84,77,77,97,58,1,86,58,26,10,86,51];
expected = [7,97, 58, 1, 86, 58, 26, 10, 86, 51, 41, 73, 89, 7, 10, 1, 59, 58, 84, 77]
expect(rotateLeft(input, 10)).toBe(expected);
input = [98,67,35,1,74,79,7,26,54,63,24,17,32,81];
expected = [26, 54, 63, 24, 17, 32, 81, 98, 67, 35 ,1 ,74, 79, 7]
expect(rotateLeft(input, 7)).toBe(expected);
});
My last attempt is below the TODO comment.
And obviously the tests aren't passing. I tried several approaches without success. It's just an exercise, so I would like some guidance.
Thanks
I'm starting to learn about deep-learning and found synaptic.js.
I would like to create a prediction system where I have a input of numbers and would like the AI to understand the pattern.
My training data would be a array of 2 numbers, and the output I want to validate is [x, y, z] where x and z are kind of booleans for even/odd, and y is the sum of both numbers in the imput.
So:
var trainingSet = [{
'input': [20, 34],
'output': [1, 54, 0]
}, {
'input': [22, 33],
'output': [1, 55, 1]
},{
'input': [24, 35],
'output': [1, 59, 1]
},{
'input': [23, 36],
'output': [0, 59, 0]
}];
and I would like the AI to know the answer if I input [20, 31].
How would I set up such logic?
I started a jsFiddle based on a YouTube talk but don't understand what the code does actually...
Made a loop to generate trainig data in this jsFiddle that basically is:
// training data generator:
var trainingSet = [];
for (var i = 0; i < 500; i++) {
var obj = {};
obj.input = [
Math.random() * 10,
Math.random() * 10
].map(Math.round);
obj.output = [
Number(obj.input[0] % 2 == 0),
obj.input[0] + obj.input[1],
Number(obj.input[1] % 2 == 1)
]
trainingSet.push(obj);
}
document.body.innerHTML = JSON.stringify(trainingSet);
Unless the generator you build is simply to explain the problem to us, there's no way the problem can be solved. More formally, no function exists such that you can recover the input from the output. The generator produces random numbers and what is preserved is whether they were odd / even and the sum. There exists an infinite set of numbers that fulfills these criteria. From your example: 54 = 20 + 34 = 18 + 36 = 16 + 38 ... If there was a process driving this, it can be done. But it's random. Your neural network can never learn a pattern because there is no pattern.
How do you determine the bucket to which a number belongs to? For ex, lets say we have buckets 0 - 20, 21 - 50, 51 - 80, 81 - 100 or the equivalent grades as 'Poor', 'Average', 'Good', 'Great'. Is there an efficient way using jquery/lodash/d3/underscore to find out that '45' belongs to the '21 - 50' bucket or is 'Average'?
Edit: Is this the best way to do it? In terms of speed, minimal code.
Here's what I have with a lot of help;
// Set up your data
var range = [[0, 20], [21, 50], [51, 80], [81, 100]]
var number = 45
range.find(function(val) { return val[1] >= number })
// Returns [21, 50]
range.findIndex(function(val) { return val[1] >= number })
// Returns 1
This should work...
var range = [[0, 20], [21, 50], [51, 80], [81, 100]]
var number = 45
var bucket = range.filter(function(a) {
if (number >= a[0] && number <= a[1]) return a
})
console.log(bucket[0])
You can use an array of objects with properties set to from "Poor" to "Great" corresponding to the range of numbers set as value of the property, Array.prototype.filter()
var range = [{
Poor: [0, 20]
}, {
Average: [21, 50]
}, {
Good: [51, 80]
}, {
Great: [81, 100]
}];
var number = 45;
var res = range.filter(function(el) {
var key = el[Object.keys(el)];
return number > key[0] && number < key[1]
});
console.log(Object.keys(res[0])[0])
The D3 way using scales:
var scale = d3.scaleQuantize()
.domain([0,100])
.range(["very bad","bad","average","good","very good"]);
console.log(scale(34));
console.log(scale(55));
console.log(scale(91));
<script src="https://d3js.org/d3.v4.min.js"></script>
The nice thing of D3 is that the scale automatically divides the domain based on the number of values of the range. For instance, the snippet above has 5 values ("very bad","bad","average","good","very good"), and so 34 is "bad". In the snippet below, using only 3 values, 34 is "average":
var scale = d3.scaleQuantize()
.domain([0,100])
.range(["bad","average","good"]);
console.log(scale(34));
console.log(scale(55));
console.log(scale(91));
<script src="https://d3js.org/d3.v4.min.js"></script>
var ranges = [
{
name: 'Poor',
range: [0, 20]
},
{
name: 'Average',
range: [21, 50]
},
{
name: 'Good',
range: [51, 80]
},
{
name: 'Great',
range: [81, 100]
},
]
var number = 45;
var range = _.find(ranges, function (r) {
return _.inRange(number, r.range[0], r.range[1] + 1);
}).name;
function largestOfFour(arr) {
var max = 0;
var newArr = [];
for (var i = 0; i < arr.length; i++) {
for (var j = i; j < arr.length; j++) {
max = Math.max(max, arr[i][j]);
}
newArr.push(max);
}
return newArr;
}
Here is my code. It works for me but I want to know is there any other sort way to do this?
Try this:
function largestOfFour(arr) {
return arr.map(function(item){
return Math.max.apply(null, item);
});
}
You may use the spread operator as:
var data = [
[1, 2, 3, 4],
[10, 20, 200, 31],
[21, 3, 444, 133],
[0, 0, 90, 1]
];
const max = Math.max(...data.map(inner => Math.max(...inner)));
console.log(max);
You can try something like this:
Idea, Math.max takes n arguments and gives you the max value. Using .apply you can pass parameters as array. Combining both will give you max value in an array.
Apply
var data = [
[1, 2, 3, 4],
[10, 20, 200, 31],
[21, 3, 444, 133],
[0, 0, 90, 1]
];
var max_arr = data.map(function(a) {
return Math.max.apply(this, a);
});
console.log(max_arr)
Sort + slice + pop
var data = [
[1, 2, 3, 4],
[10, 20, 200, 31],
[21, 3, 444, 133],
[0, 0, 90, 1]
];
var max_arr = data.map(function(a) {
return a.sort().slice(-1).pop()
});
console.log(max_arr)
Using a complex array (for the use case of tabular data displayed in columns and rows) lets say I have some values:
var values = [
[234, 386, 21, 38],
[-23, 58, 106, 0],
[45, -48, 506, 23],
[109, 168, 42, 111]
];
What would be the best way to return a matching array that would rank the values against their column in the correct (maintained) order? The ranked order would be highest to lowest in this case.
For example, an end result array of:
[
[1, 1, 4, 2],
[4, 3, 2, 4],
[3, 4, 1, 3],
[2, 2, 3, 1]
];
Note how the result is sorted vertically by column.
I would want to use this with a large data set, so any guidance/tips for quickest performance is my aim here.
--
For context: My first attempt was to map the original array with the index values, but I was unsure where to go from there:
var singleColumn = [234, -23, 45, 109];
for (var i = 0; i < singleColumn.length; i++) {
singleColumn[i] = [singleColumn[i], i];
}
Essentially the trick will be retaining original indices after the sort. I've iterated them into a data structure first, sorted it, and then rebuilt the 2-dimensional array structure from the result.
I haven't done any checking to ensure that the input is all well-formed, the assumption is all rows are the same width as the first row.
An optimization that could probably be done would be transforming the raw values into the data-structure during the sort, which would eliminate a pass of the array. I don't see an easy way to do that without losing some of the conciseness and readability, and it would be a pretty small gain.
var values = [
[234, 386, 21, 38],
[-23, 58, 106, 0],
[45, -48, 506, 23],
[109, 168, 42, 111]
];
function buildRanking(arr) {
var result = [];
for(var col = 0; col < arr[0].length; col++) {
//everything inside this for loop is per column
//first use map function to turn the column into an array of objects
//each holding the value and the current index. [{value: 234, index: 1}, etc..]
var sortableStructure = values.map(function(val, i) {
return { value : val[col], index : i };
});
//Sort function to sort my sortableStructure in place on the values
sortableStructure.sort(function(a, b) {
return b.value - a.value;
});
//now iterate over the sortable strucutre
for(var i = 0; i < sortableStructure.length; i++) {
//this ugly bit just makes sure arrays are initialized for each row as needed
if(typeof result[sortableStructure[i].index] === 'undefined')
result[sortableStructure[i].index] = [];
//for the current item in the sortableStructure, get the index
//access the result element corresponding to that index
//(the original position of this sorted value) and push in
//the current index (sort order) + 1 (to switch from zero-based to one-based)
result[sortableStructure[i].index].push(i + 1);
}
}
return result;
}
//To provide visible output.
document.write(JSON.stringify(buildRanking(values)).split('],[').join('],<br/>['));
First pass at this and highly unoptimized but here's a loose implementation where I do it step by step.
function sort(rows) {
var columns = [];
/* Invert rows and columns */
for (var i = 0, row; i < rows.length; i++) {
row = rows[i];
for (var j = 0, col; j < row.length; j++) {
col = rows[i][j];
columns[j] = columns[j] || [];
columns[j][i] = col;
}
}
/* Sort by descending order, returning index */
var sortedColumns = columns.slice(0).map(function(column, i) {
return column.slice(0).sort(function(a, b) {
return b - a;
}).map(function(value, j, sortedColumn) {
return sortedColumn.indexOf(column[j]) + 1;
});
});
/* Invert rows and columns back again */
var sortedRows = [];
for (var i = 0, row; i < sortedColumns.length; i++) {
row = sortedColumns[i];
for (var j = 0, col; j < row.length; j++) {
col = sortedColumns[i][j];
sortedRows[j] = sortedRows[j] || [];
sortedRows[j][i] = col;
}
}
return sortedRows;
}
var values = [
[234, 386, 21, 38],
[-23, 58, 106, 0],
[45, -48, 506, 23],
[109, 168, 42, 111]
];
var expected = [
[1, 1, 4, 2],
[4, 3, 2, 4],
[3, 4, 1, 3],
[2, 2, 3, 1]
];
var sorted = sort(values);
console.log(sorted.toString() === expected.toString()); // true
JSFiddle demo: https://jsfiddle.net/7ek6pz63/2/
Assuming the columns habe to be sorted descending and the result is based on one, then this should work.
var values = [
[234, 386, 21, 38],
[-23, 58, 106, 0],
[45, -48, 506, 23],
[109, 168, 42, 111]
];
function getX(array) {
var length = array[0].length,
result = Array.apply(null, { length: array.length }).map(function () { return []; }),
temp, i;
for (i = 0; i < length; i++) {
temp = [];
array.forEach(function (a, j) {
temp.push({ v: a[i], i: j });
});
temp.sort(function (a, b) {
return b.v - a.v;
}).forEach(function (a, j) {
result[a.i][i] = j + 1;
});
}
return result;
}
document.write('<pre>' + JSON.stringify(getX(values), 0, 4) + '</pre>');