Calculate quintiles/deciles from an array of numbers - javascript

Given the following array:
[13, 468, 3, 6, 220, 762, 97, 16, 522, 69, 119, 2895, 1255, 49, 19, 261, 9, 140, 55, 20, 6, 22, 6, 17, 115]
I need to calculate the value that is at the 20th, 40th, 60th, and 80th percentile. The steps would be to order the array from low to high, count the total number of values, determine what value is at the 20th percentile, etc. (for example, if there are 10 numbers in order from low to high, the 2nd value would be the 20th percentile).
This is stored in a variable and I know I can sort the numbers like this:
ticks6.sort();
and get the number of values in the array with this:
var newticks=ticks6.length;
I have no idea how to do the next part though where I figure out the percentiles, but looking for a solution in jquery or javascript.

Use like this:
var arr = [13, 468, 3, 6, 220, 762, 97, 16, 522, 69, 119, 2895, 1255, 49, 19, 261, 9, 140, 55, 20, 6, 22, 6, 17, 115];
arr.sort();
var len = arr.length;
var per20 = Math.floor(len*.2) - 1;
console.log(arr[per20]);
//similarly
var per40 = Math.floor(len*.4) - 1;
console.log(arr[per40]);

The Simple Statistics library has a quantile function you can use for this:
ss.quantile([13, 468, 3, 6, 220, 762, 97, 16, 522, 69, 119, 2895, 1255, 49, 19, 261, 9, 140, 55, 20, 6, 22, 6, 17, 115], 0.2)
=> 13

You can easely sort your array :
console.log([13, 468, 3, 6, 220, 762, 97, 16, 522, 69, 119, 2895, 1255, 49, 19, 261, 9, 140, 55, 20, 6, 22, 6, 17, 115].sort(function(a,b){return a-b}))
Get the length of the array : myArray.length.
And the 20th percile parseInt(myArray.length * 0.2) => 2

Something like this:
tricks6.sort();
var length = tricks6.length;
var twentieth = sorted[math.floor((length-1)*.2)] //do for all

Related

Why reduce() is returning NaN when multiplying big array

I'm solving a problem 1822 from leetcode and I'm stuck with reduce() returning NaN.
There is a function signFunc(x) that returns:
1 if x is positive.
-1 if x is negative. 0 if x is equal to 0. You are given an integer array nums. Let product be the product of all values in the array
nums.
Return signFunc(product).
My try of solution:
var arraySign = function(nums) {return Math.sign(nums.reduce((acc, curr) => acc * curr));};
console.log(arraySign([1,5,0,2,-3]));
When I pass simple array like [1,5,0,2,-3] everything is okay, but when I pass monster like
[1,28,-91,-62,-36,-1,-84,-90,-92,61,6,-58,-60,2,51,-15,-18,-81,87,84,100,-84,-13,-87,-33,72,-72,-59,-79,28,-69,-97,-93,17,67,11,-12,19,5,42,-85,71,-77,-82,26,-58,-51,-14,63,-85,-86,66,47,57,-86,-25,-75,59,-17,-71,89,-78,-42,30,39,61,-96,-30,-29,-92,-90,69,20,65,32,92,44,-71,-18,87,-86,23,-96,-21,-49,-96,-98,35,-11,-1,81,-48,68,5,75,57,-30,-7,32,86,-29,-86,-61,45,-31,-93,-26,-9,86,57,-52,75,68,-58,14,27,-94,47,-38,-44,75,-83,21,-83,43,62,74,97,78,43,54,28,64,-19,-89,88,68,18,-96,-83,-25,-71,88,-84,-24,-61,72,-90,-56,29,46,56,51,16,66,-2,65,-95,16,51,42,61,99,89,-93,59,-99,69,26,-61,21,41,40,-4,-49,3,-96,57,65,72,-41,-77,-4,61,71,-88,21,-95,38,64,92,0,-63]
var arraySign = function(nums) {return Math.sign(nums.reduce((acc, curr) => acc * curr));};
console.log(arraySign([1,28,-91,-62,-36,-1,-84,-90,-92,61,6,-58,-60,2,51,-15,-18,-81,87,84,100,-84,-13,-87,-33,72,-72,-59,-79,28,-69,-97,-93,17,67,11,-12,19,5,42,-85,71,-77,-82,26,-58,-51,-14,63,-85,-86,66,47,57,-86,-25,-75,59,-17,-71,89,-78,-42,30,39,61,-96,-30,-29,-92,-90,69,20,65,32,92,44,-71,-18,87,-86,23,-96,-21,-49,-96,-98,35,-11,-1,81,-48,68,5,75,57,-30,-7,32,86,-29,-86,-61,45,-31,-93,-26,-9,86,57,-52,75,68,-58,14,27,-94,47,-38,-44,75,-83,21,-83,43,62,74,97,78,43,54,28,64,-19,-89,88,68,18,-96,-83,-25,-71,88,-84,-24,-61,72,-90,-56,29,46,56,51,16,66,-2,65,-95,16,51,42,61,99,89,-93,59,-99,69,26,-61,21,41,40,-4,-49,3,-96,57,65,72,-41,-77,-4,61,71,-88,21,-95,38,64,92,0,-63]));
I got only "NaN" return. At this moment I skipped this bug by if's:
var arraySign = function(nums) {
let product = nums.reduce((acc, curr) => acc * curr);
if(product>0) return 1;
else if (product<0) return -1;
else return 0;};
But i want to know: why reduce is not working in this problem? Is there any limit for reduce()?
The problem is not with reduce. The problem is that you're multiplying a lot of numbers, which amounts to Infinity (or -Infinity), and then you're also multiplying that by 0. But Infinity * 0 gives NaN.
You can solve this by only multiplying the signs of the numbers:
function arraySign(nums) {
return nums.reduce((acc, curr) => acc * Math.sign(curr), 1);
};
Off Topic: But you can solve this by simply counting the number of negative values and looking for zeroes.
Every 2 negative values, the signs will cancel each other out and the result becomes positive.
an even number of negative values will have a positive result
an odd number of negative values will have a negative result
and the positive values in the list have no influence whatsoever on the sign of the result.
const arraySign = function(nums) {
// if the array contains a `0` the result will be `0`.
// 0 * whatever will always stay 0
if (nums.includes(0)) return 0;
let count = 0;
for (const value of nums) count += value < 0;
return count & 1 ? -1 : 1;
}
const nums = [1, 28, -91, -62, -36, -1, -84, -90, -92, 61, 6, -58, -60, 2, 51, -15, -18, -81, 87, 84, 100, -84, -13, -87, -33, 72, -72, -59, -79, 28, -69, -97, -93, 17, 67, 11, -12, 19, 5, 42, -85, 71, -77, -82, 26, -58, -51, -14, 63, -85, -86, 66, 47, 57, -86, -25, -75, 59, -17, -71, 89, -78, -42, 30, 39, 61, -96, -30, -29, -92, -90, 69, 20, 65, 32, 92, 44, -71, -18, 87, -86, 23, -96, -21, -49, -96, -98, 35, -11, -1, 81, -48, 68, 5, 75, 57, -30, -7, 32, 86, -29, -86, -61, 45, -31, -93, -26, -9, 86, 57, -52, 75, 68, -58, 14, 27, -94, 47, -38, -44, 75, -83, 21, -83, 43, 62, 74, 97, 78, 43, 54, 28, 64, -19, -89, 88, 68, 18, -96, -83, -25, -71, 88, -84, -24, -61, 72, -90, -56, 29, 46, 56, 51, 16, 66, -2, 65, -95, 16, 51, 42, 61, 99, 89, -93, 59, -99, 69, 26, -61, 21, 41, 40, -4, -49, 3, -96, 57, 65, 72, -41, -77, -4, 61, 71, -88, 21, -95, 38, 64, 92, 0, -63];
console.log(arraySign([1,5,2,-3]));
console.log(arraySign(nums));

JavaScript - How do I dynamically assign a new key value pair to an object, using object-literal, and bracket notation, spread syntax in a one-liner?

I want to dynamically specify negative values as seen in this exact question.
Rules for unquoted JavaScript Object Literal Keys?
I want to also accomplish this using some method of dynamic bracket notation, using a string equivalent of a negative remainder (modulus operation).
bucketObj[key] reports undefined, since I have not pre set a key to store a corresponding value. How do I dynamically set a key of an object in either bracket notation, dot notation, or both?
function toDigitBuckets(array, radix) {
let bucket = JSON.parse(JSON.stringify([...Array(radix).fill([])]));
let bucketObj = Object.assign(bucket);
array.forEach(val => { let key = String.toString(val % 10); bucketObj[key].push(val) });
return bucket;
}
let array = [-7, -49, 84, 39, -31, 95, 7, -8, -13, -32, 93, 40, -81, -30, -57, -57, 49, 66, -64, 42, 35, 29, -57, 41, 93, 34, -45, -15, 51, 16, 97, -88, 52, -69, 56, -16, -91, 51, 10, -21, 80, 78, -5, 18, -20, -98, 72, -94, 11, -83, -31, 13, -21, 39, -47, 8, -98, 95, 52, -18, 77, -11, -38, -46, -98, 48, -45, -4, 76, -32, -81, 67, -82, 9, -60, -20, 0, 33, -12, 77, 65, 45, -22, 99, -47, -83, -81, 10, -99, 16, 23, 5, -57, 89, -62, 9, -16, 79, 5, -2];
let radix = 10;
console.log(JSON.stringify(toDigitBuckets(array, radix)));
You can use Array#reduce with an object as the accumulator. Each time a new key is encountered, first set that property value to be an empty array.
function toDigitBuckets(array, radix) {
return array.reduce((acc, curr) =>
((acc[curr % radix] ??= []).push(curr), acc), {});
}
let array = [-7, -49, 84, 39, -31, 95, 7, -8, -13, -32, 93, 40, -81, -30, -57, -57, 49, 66, -64, 42, 35, 29, -57, 41, 93, 34, -45, -15, 51, 16, 97, -88, 52, -69, 56, -16, -91, 51, 10, -21, 80, 78, -5, 18, -20, -98, 72, -94, 11, -83, -31, 13, -21, 39, -47, 8, -98, 95, 52, -18, 77, -11, -38, -46, -98, 48, -45, -4, 76, -32, -81, 67, -82, 9, -60, -20, 0, 33, -12, 77, 65, 45, -22, 99, -47, -83, -81, 10, -99, 16, 23, 5, -57, 89, -62, 9, -16, 79, 5, -2];
let radix = 10;
console.log(toDigitBuckets(array, radix));
.as-console-wrapper{max-height:100%!important;top:0}

forEach() method - looping over an array

I am totally new to coding so my question is probably very basic. I want to loop over the following array and every time the number is divisible by 3 I want to add 100. If not, just print the number. I want to do that with the forEach() method. This is my code but when I want to print it it says "undefined" What am I doing wrong?
var test = [12, 929, 11, 3, 199, 1000, 7, 1, 24, 37, 4,
19, 300, 3775, 299, 36, 209, 148, 169, 299,
6, 109, 20, 58, 139, 59, 3, 1, 139];
test.forEach(function(num){
if(num %3 === 0){
return num+=100;
}else{
return num;
}
console.log(num) ;
})
Get rid of the return statements:
The return statement ends function execution and specifies a value to
be returned to the function caller.
Therefore it will never make it to the console.log line (this is what they call unreachable code since there is no possible path to it):
var test = [12, 929, 11, 3, 199, 1000, 7, 1, 24, 37, 4,
19, 300, 3775, 299, 36, 209, 148, 169, 299,
6, 109, 20, 58, 139, 59, 3, 1, 139
];
test.forEach(function(num) {
if (num % 3 === 0) {
num += 100;
}
console.log(num);
})
I removed the else block because, as pointed out in the comments below, there is no purpose for it.
The approach above is fine if all you want to do is log the result, but if you want to get a new array that has stored all the new values then you should consider using Array.prototype.map like this:
var test = [12, 929, 11, 3, 199, 1000, 7, 1, 24, 37, 4,
19, 300, 3775, 299, 36, 209, 148, 169, 299,
6, 109, 20, 58, 139, 59, 3, 1, 139
];
var updatedValues = test.map(num => num % 3 === 0 ? num + 100 : num);
console.log(updatedValues);
The problem is that the return keyword immediately stops the function, so you don't progress further. And since Array#forEach itself doesn't return anything, the keyword is pretty useless. You can just remove it and you'd get the behaviour you want:
var test = [12, 929, 11, 3, 199, 1000, 7, 1, 24, 37, 4,
19, 300, 3775, 299, 36, 209, 148, 169, 299,
6, 109, 20, 58, 139, 59, 3, 1, 139];
test.forEach(function(num){
if(num %3 === 0){
num+=100;
}
console.log(num) ;
})
If you instead want to create a new array from the first one using the rules you've described, then you can simply substitute .forEach for the Array#map method:
var test = [12, 929, 11, 3, 199, 1000, 7, 1, 24, 37, 4,
19, 300, 3775, 299, 36, 209, 148, 169, 299,
6, 109, 20, 58, 139, 59, 3, 1, 139];
var result = test.map(function(num){
if(num %3 === 0){
return num+=100;
}else{
return num;
}
})
console.log(result);
You should use map instead of forEach here since map will execute the provided function to each array item and return a new array.
The map() method creates a new array with the results of calling a provided function on every element in the calling array.
Source
Just changing your current code, it can be like this
var test = [12, 929, 11, 3, 199, 1000, 7, 1, 24, 37, 4,
19, 300, 3775, 299, 36, 209, 148, 169, 299,
6, 109, 20, 58, 139, 59, 3, 1, 139];
var result = test.map(function(num) {
if (num %3 === 0) {
return num + 100;
} else {
return num;
}
})
Or, you can also improve it further by separating things
const add100IfDividableBy3 = function (num) {
return (num % 3 === 0) ? num + 100 : num;
}
const test = [12, 929, 11, 3, 199, 1000, 7, 1, 24, 37, 4, 19, 300, 3775, 299, 36, 209, 148, 169, 299, 6, 109, 20, 58, 139, 59, 3, 1, 139];
const result = test.map(add100IfDividableBy3)
The function add100IfDividableBy3 uses what is called as a Ternary Operator

I am stuck on a quiz in Udacity for JavaScript on Multi-dimensional arrays.

The quiz is about a multidimensional array and wants us to use a nested for loop to cycle through each element and replace the values that are divisible by 2 with the strings 'even' and 'odd' for even and odd numbers respectively. I cannot print out the array with the numbers divisible by 2 on to the console with the added string.
I have tried using .slice() and .splice() also but that did not get me the desired results either. Below is my latest attempt.
Programming Quiz - Multi-dimensional Arrays:
Question: Use a nested for loop to take the numbers array below and replace all of the values that are divisible by 2 (even numbers) with the string "even" and all other numbers with the string "odd".
var numbers = [
[243, 12, 23, 12, 45, 45, 78, 66, 223, 3],
[34, 2, 1, 553, 23, 4, 66, 23, 4, 55],
[67, 56, 45, 553, 44, 55, 5, 428, 452, 3],
[12, 31, 55, 445, 79, 44, 674, 224, 4, 21],
[4, 2, 3, 52, 13, 51, 44, 1, 67, 5],
[5, 65, 4, 5, 5, 6, 5, 43, 23, 4424],
[74, 532, 6, 7, 35, 17, 89, 43, 43, 66],
[53, 6, 89, 10, 23, 52, 111, 44, 109, 80],
[67, 6, 53, 537, 2, 168, 16, 2, 1, 8],
[76, 7, 9, 6, 3, 73, 77, 100, 56, 100]
];
My code:
//create a nested for loop to cycle through each row and column
for(let row = 0; row < numbers.length; row++){
for(let col = 0; col < numbers.length; col++){
//if the even numbers in each row and column are divisible by 2, replace those
//numbers with the word even
if(numbers % 2 === 0){
numbers[row] += 'even';
}
}
}
console.log(numbers);
You're real close! It comes down to how you're referencing the index in the 2-dimensional array. Iterating over it in a nested for loop requires first that we iterate through the rows, then the columns. In your example, you were actually iterating over the columns twice. In order to fix this, you would simply iterate over the row index of the numbers array in the nested for loop:
for(let row = 0; row < numbers.length; row++){
for(let col = 0; col < numbers[row].length; col++){
Then finally you will need to set the target index numbers[row][col] to even. In your example you used the addition assignment operator +=, which performs what is string concatenation. Instead of simply changing the index value to 'even', the += would actually add the word 'even' to the end of the number. So the index output would actually read something like 156even. Just drop the plus sign in order to reassign the index to even:
numbers[row][col] = 'even';
var numbers = [
[243, 12, 23, 12, 45, 45, 78, 66, 223, 3],
[34, 2, 1, 553, 23, 4, 66, 23, 4, 55],
[67, 56, 45, 553, 44, 55, 5, 428, 452, 3],
[12, 31, 55, 445, 79, 44, 674, 224, 4, 21],
[4, 2, 3, 52, 13, 51, 44, 1, 67, 5],
[5, 65, 4, 5, 5, 6, 5, 43, 23, 4424],
[74, 532, 6, 7, 35, 17, 89, 43, 43, 66],
[53, 6, 89, 10, 23, 52, 111, 44, 109, 80],
[67, 6, 53, 537, 2, 168, 16, 2, 1, 8],
[76, 7, 9, 6, 3, 73, 77, 100, 56, 100]
];
for(let row = 0; row < numbers.length; row++){
for(let col = 0; col < numbers[row].length; col++){ //iterate over the n-th index of numbers[]
if(numbers[row][col] % 2 === 0){ //numbers[row][col] points to the nested index
numbers[row][col] = 'even'; //set index to 'even'
}
}
}
console.log(numbers);
This video is a nice explanation of how iterating over 2d arrays works: https://www.youtube.com/watch?v=qdT1P2qmsmU
The video is using Java, but the idea is exactly the same.
Hope this helps! Multi-dimensional arrays are tough to wrap your brain around!

Convert buffer to array

I am setting memcached with
$memcached->set("item" , ["1" => "hello"]);
anything work in PHP ,
In Node.js with memcached plugin , I get a buffer instead of array in result
<Buffer 61 3a 25 61 34 3a>
I can not convert such buffer to array
In Node.js :
memcached.get("item" , function(err, data) {
console.log(data);
}
Do you have any way ?
arr = [...buffer]
ES6 introduced a lot of other features, besides buffers.
You can even easily append like this:
arr.push(...buffer)
The ... operator expands enumerables such as arrays and buffers when used in array. It also expands them into separate function arguments.
Yes, it's also faster:
... : x100000: 835.850ms
Slice call from prototype : x100000: 2118.513ms
var array,
buffer = new Buffer([1, 4, 4, 5, 6, 7, 5, 3, 5, 67, 7, 4, 3, 5, 76, 234, 24, 235, 24, 4, 234, 234, 234, 325, 32, 6246, 8, 89, 689, 7687, 56, 54, 643, 32, 213, 2134, 235, 346, 45756, 857, 987, 0790, 89, 57, 5, 32, 423, 54, 6, 765, 65, 745, 4, 34, 543, 43, 3, 3, 3, 34, 3, 63, 63, 35, 7, 537, 35, 75, 754, 7, 23, 234, 43, 6, 247, 35, 54, 745, 767, 5, 3, 2, 2, 6, 7, 32, 3, 56, 346, 4, 32, 32, 3, 4, 45, 5, 34, 45, 43, 43]),
iter = 100000;
array = buffer;
console.time("... : x" + iter);
for (var i = iter; i--;) array = [...buffer]
console.timeEnd("... : x" + iter);
console.time("Apply/call/etc : x" + iter);
for (var i = iter; i--;) array = Array.prototype.slice.call(buffer, 0)
console.timeEnd("Apply/call/etc : x" + iter);
There is another way to convert to array of integers
Using toJSON()
Buffer.from('Text of example').toJSON()
{ type: 'Buffer',data: [ 84, 101, 120, 116, 32, 111, 102, 32, 101, 120, 97, 109, 112, 108, 101 ] }
// simple get data
Buffer.from('Text of example').toJSON().data
[ 84, 101, 120, 116, 32, 111, 102, 32, 101, 120, 97, 109, 112, 108, 101 ]
Example of benchmark
// I took this from #user4584267's answer
const buffer = new Buffer([1, 4, 4, 5, 6, 7, 5, 3, 5, 67, 7, 4, 3, 5, 76, 234, 24, 235, 24, 4, 234, 234, 234, 325, 32, 6246, 8, 89, 689, 7687, 56, 54, 643, 32, 213, 2134, 235, 346, 45756, 857, 987, 0790, 89, 57, 5, 32, 423, 54, 6, 765, 65, 745, 4, 34, 543, 43, 3, 3, 3, 34, 3, 63, 63, 35, 7, 537, 35, 75, 754, 7, 23, 234, 43, 6, 247, 35, 54, 745, 767, 5, 3, 2, 2, 6, 7, 32, 3, 56, 346, 4, 32, 32, 3, 4, 45, 5, 34, 45, 43, 43]);
let array = null;
const iterations = 100000;
console.time("...buffer");
for (let i = iterations; i=i-1;) array = [...buffer]
console.timeEnd("...buffer");
console.time("array.prototype.slice.call");
for (let i = iterations; i=i-1;) array = Array.prototype.slice.call(buffer, 0)
console.timeEnd("array.prototype.slice.call");
console.time("toJSON().data");
for (let i = iterations; i=i-1;) array = buffer.toJSON().data
console.timeEnd("toJSON().data");
OUTPUT
...buffer: 559.932ms
array.prototype.slice.call: 1176.535ms
toJSON().data: 30.571ms
or if you want more profesional and custom function in Buffer use this:
Buffer.prototype.toArrayInteger = function(){
if (this.length > 0) {
const data = new Array(this.length);
for (let i = 0; i < this.length; i=i+1)
data[i] = this[i];
return data;
}
return [];
}
Example of benchmark:
const buffer = new Buffer([1, 4, 4, 5, 6, 7, 5, 3, 5, 67, 7, 4, 3, 5, 76, 234, 24, 235, 24, 4, 234, 234, 234, 325, 32, 6246, 8, 89, 689, 7687, 56, 54, 643, 32, 213, 2134, 235, 346, 45756, 857, 987, 0790, 89, 57, 5, 32, 423, 54, 6, 765, 65, 745, 4, 34, 543, 43, 3, 3, 3, 34, 3, 63, 63, 35, 7, 537, 35, 75, 754, 7, 23, 234, 43, 6, 247, 35, 54, 745, 767, 5, 3, 2, 2, 6, 7, 32, 3, 56, 346, 4, 32, 32, 3, 4, 45, 5, 34, 45, 43, 43]);
let array = null;
const iterations = 100000;
console.time("toArrayInteger");
for (let i = iterations; i=i-1;) buffer.toArrayInteger();
console.timeEnd("toArrayInteger");
Ouput:
toArrayInteger: 28.714ms
Note: In the last example I copied a function from Buffer.toJSON and custom it a lite
Here you go:
var buffer = new Buffer([1,2,3])
var arr = Array.prototype.slice.call(buffer, 0)
console.log(arr)
I haven't used memcached so I am not sure just what this buffer represents or what you want to have instead. Sorry. Here is a function to split a buffer up into an array of bytes. More at node.js Buffer docs, hope it helps!
var hex = new Buffer("613a2561343a", "hex");
var l = hex.length; // in bytes
var output = [];
for(var i = 0; i < l; i++){
var char = hex.toString('hex',i,i+1); // i is byte index of hex
output.push(char);
};
console.log(output);
// output: [ '61', '3a', '25', '61', '34', '3a' ]
You can also use Array.from:
memcached.get("item" , function(err, data) {
console.log(Array.from(data));
}
I have a solution, although I am currently trying to find a better one:
function bufToArray(buffer) {
let array = new Array();
for (data of buffer.values()) array.push(data);
return array;
}
EDIT : I found a simpler way:
var buffer = Buffer.from('NodeJS rocks!')
var array = new Function(`return [${Array.prototype.slice.call(buffer, 0)}]`)
But, like someone already said, [...buffer] is faster (and more code efficient).
You can also use new Uint8Array(buffer [, byteOffset [, length]]);
In interent , there was no information about that , but I have found the convert way
In nodejs , I have to use :
var arrayobject = phpjs.unserialize(data.toString());
but , it is very stupid way for getting array , it seem that php serilzie the data when setting memcache .

Categories