print histogram in javascript? - javascript

I have a query that checks the size in kb of my mongo collection documents, which looks like this:
db.myCollection.find().forEach(function(obj)
{
var size = Object.bsonsize(obj)
print('document id: ' + obj._id + ' size: ' + size/1024)
});
and it prints:
document id: 57b6e0561a7b8900011bafhr size: 463.248046875
but I want to print an histogram that looks like:
bigger than 100kb -> 1,000,000 docs
bigget than 200kb -> 500,000 docs
bigger than 300kb -> 300,000 docs
...
max doc 750kb
how can I do this in javascript?

You can try something simple, like this:
// an array of 100 random numbers 0-100
var arr = [];
for(var i=0;i<100;i++)
arr.push(Math.random()*100)
// reducing the array to "histogram"
// does not create empty bins
arr.reduce(function(acc,cur){
var k = Math.floor(cur/10)*10; // creates bins of 0-9, 10-19, 20-29,..., 90-99
if (!(k in acc)) acc[k]=0; // creates a bin if neccessary
acc[k]++; // increments the bin
return acc;
},[]);
Output (keys denote bins, values are element counts):
0: 10
10: 12
20: 4
30: 8
40: 8
50: 10
60: 12
70: 12
80: 10
90: 14

Related

How to distribute one array of elements over another but have the element count gradually go down?

I'm creating mock data for my app with fakerJS.
I have created one array of 10 000 user IDs. And 1 array of 100 000 content IDs.
I want to distribute these content IDs over the user ID array where the first one will get the most content IDs and the last user will get the least (0).
Eg.
const userIds = ['a', 'b', 'c', ...] // 10_000 long
const contentIds = ['c1', 'c2', 'c3', ...] // 100_000 long
const result = distribute(userIds, contentIds)
result // { a: ['c1', 'c2', 'c3', ...], b: [...], z: [] }
The distribution should look something like this theoretically:
However, the 40 here for highest number is way too low, so imagine this being way higher for the first user ID and with 10_000 users, many of the last users could have 0 content IDs with this distribution basically.
I've been coding for 6+ years, but I think I need to start learning Mathematics to figure this one out, would appreciate any help on how to even start 😅
Maybe a logarithm decay and truncate (you can play with value_data.push formula until you find what you want)
Start and End
0: 90
1: 83
2: 79
3: 76
4: 74
5: 72
...
9995: 0
9996: 0
9997: 0
9998: 0
9999: 0
<script>
var time_data = [];
var value_data = [];
max = 10000;
//logarithmic decay array and truncate
for (let i=1;i<=max;++i) {
time_data.push(i);
value_data.push( Math.floor(100 - ( (9.71672 * (1 + Math.log(i)) ) )) );
}
//initializer
guarda = 0;
valueGuarda = 0;
for (let index = 0; index < time_data.length; index++) {
guarda = time_data[index] + guarda;
valueGuarda = value_data[index] + valueGuarda;
}
//arrays
console.log(time_data)
console.log(value_data)
//calculating the summation
let total = value_data.reduce((a, b) => a + b, 0); //100000
console.log("total: " + total);
</script>

App Script getValue() Returning Empty Strings

I'm having an issue with my script that I created. I wanted to be able to archive metrics for work on a weekly basis. Everything works as expected, except when I try to pull values from my overview tab.
The cells that I am trying to grab values from are the results of various calculations that give me a good idea of my progress; I at first thought it may have something to do with my use of ARRAYFORMULA.
Here is an example of one of the cells:
=ARRAYFORMULA({
"Total Number of Attempts";
IFERROR(
COUNTA(
Metrics!$F$2:$F
),
0
)
})
In this particular array formula, the formula is typed into cell E21, the "Total Number of Attempts" appears in E21, and I would be pulling the value from E22.
My thought was that since I haven't put any data in the cell myself, the script was treating it like a blank cell and returning an empty string. However, I tested what happens when I do put values in the cell and I get the same empty string returned.
I don't see anything logically wrong with my code, so I must be missing something with the way that Google Sheets/App Script operates. Below, you will find my code for the archiveData() function:
/*
This function will be set up with a trigger
It will run every week, depositing the current values into their correct columns in the
Archive tab.
*/
function archiveData() {
// Grab the sheet names
var archive = SpreadsheetApp.getActive().getSheetByName('Archive');
var data = SpreadsheetApp.getActive().getSheetByName('Overview');
// Get the week number
var d = Utilities.formatDate(new Date(), "GMT", "w");
// Initialize row/column number for sheets to loop through
row = 2;
column = 1;
// Starting at A2, if the cell is filled, advance to the next cell in column
// If not, it will break out of loop and continue
while(archive.getRange(row, column).getValue() != "") {
row++;
}
// Place the week number in Column A
archive.getRange(row, column).setValue(d);
// Add a variable to store a row, column pair
var metric = [];
// Loop through the remaining columns
while(column <= 18) {
var addData = false;
// If the column is already populated, move to the next column
if(archive.getRange(row, column).getValue() != "") {
column++;
} else {
addData = true;
// Use a switch case to select the correct row, column pair for the correct metric on the
// Overview tab
switch(column) {
case 2:
// Total Avg Number of Tracks Missed on First Attempt
metric = [3, 14]; // C14
break;
case 3:
// Total Avg Number of Attempts Per Task
metric = [5, 14]; // E14
break;
case 4:
// Total Avg Number of Tasks Per Week
metric = [7, 14]; // G14
break;
case 5:
// Avg Number of Tracks Missed on First Attempt in Last 5 Tasks
metric = [3, 17]; // C17
break;
case 6:
// Avg Number of Attempts Per Task in Last 5 Tasks
metric = [5, 17]; // E17
break;
case 7:
// Avg Number of Tasks Per Week in Last Two Weeks
metric = [7, 17]; // G17
break;
case 8:
// Total Number of Tracks
metric = [3, 22]; // C22
break;
case 9:
// Total Number of Attempts
metric = [5, 22]; // E22
break;
case 10:
// Total Avg Tracks Per Week
metric = [7, 22]; // G22
break;
case 11:
// Total Number of Tracks in last 5 Attempts
metric = [3, 25]; // C25
break;
case 12:
// Total Number of Attempts in last 5 Tasks
metric = [5, 25]; // E25
break;
case 13:
// Avg Number of Tracks Per Week in Last Two Weeks
metric = [7, 25]; // G25
break;
case 14:
// Total Number of Tracks This Week
metric = [7, 28]; // G28
break;
case 15:
// Longest Task
metric = [5, 31]; // E31
break;
case 16:
// Shortest Task
metric = [5, 34]; // E34
break;
case 17:
// Total Avg Task Time
metric = [7, 31]; // G31
break;
case 18:
// Avg Task Time in Last 5 Attempts
metric = [7, 34]; // G34
break;
// this shouldn't run
default:
"ERROR";
break;
}
}
if(addData) {
console.log(metric[0], metric[1]); // This correctly shows the row, column pair
var metricData = data.getRange(metric[0], metric[1]).getValue();
console.log("metricData: ", metricData); // This shows metricData is an empty string
archive.getRange(row, column).setValue(metricData);
column++;
}
}
}

Divide number into many unequal parts JavaScript

I want to split a number between 20 and 50 into unequal parts.
For example:
30 = 1x20 & 1x10
45 = 2x20 1x5
or 38 = 1x20 1x10 1x5 1x2 1x1
document.getElementById("jscolor").style.color = "red";
var tokenResult = prompt(`Please enter a number between 10 and 50: `);
var divideBy = 5;
tokenResult = parseInt(tokenResult);
document.write(tokenResult + ` = `);
for (var i = 0; i < divideBy; i++) {
document.write(`${tokenResult / divideBy} `);
}
Which outputs something like:
25 = 5 5 5 5 5
I haven't managed to split it into unequal parts that aren't random.
Baically ou need an array of denominations, like
[20, 10, 5, 2, 1]
Then you need to take your value and divide it through the largest value. Take the count, an integer value and store it along with the denomination.
Substract the product of count and denomination value from the input value.
If your new value is not zero take the second large value from the denominations array and perfor the last steps again.
Finally get all counts and denominations into a readable string and make an output.

What is the answer for this Javascript while statement?

In javascript I came across this code from a tutorial website and the answer that was given was 900 but I have 109 for the answer. Please explain how do you get the answer and what are the steps taken.
var amount = 0;
var i = 1;
while (I<10) {
amount = amount + 100;
I++;
}
alert("The value is:" + amount);
it is indeed 900. btw, your I should be lowercase i in the while loop.
so amount=0 at the start and i=1.
then you enter the while loop if i < 10, which it is cause i=1 at this point.
then the inside of the loop gets executed: amount becomes 100 because 0+100 = 100
then i gets incremented, so i is now 2 and the loop happens again and again til i becomes 10 in which it exits the loop since 10 is not less than 10.
you'll find that this loops "insides" executes 9 times, (adding 100 to the value of amount each time) giving the final total of amount = 900
var amount = 0;
var i = 1;
while (i<10) {
amount = amount + 100;
i++;
}
alert("The value is:" + amount);
You can analyze this by walking through it line by line and listing out the values at each line.
(I'm assuming s/I/i/ - JavaScript is case-sensitive. If it wasn't just a typo or copy/paste error, you will likely get an error.)
Line 1: amount = 0
Line 2: i = 1
Line 3: i<10, so go to line 4.
Line 4: amount = 100, i = 1
Line 5: amount = 100, i = 2
Line 6: i<10, so go to line 4
Line 4: amount = 200, i = 2
Line 5: amount = 200, i = 3
etc., which is how you end up at amount = 900.

How to read an ArrayBuffer with binary data in "4 byte single"/floating point/IEEE 754 encoded data?

I need to loop over a binary file via an arrayBufferand retrieve sets of 1024 floating points. I'm doing this:
// chunk_size = 1024
// chunk_len = 48
// response_buffer = ArrayBuffer
// response_buffer.byteLength = 49152
for (i = chunk_len; i > 0; i -= 1) {
switch (i) {
case (chunk_len):
// create view from last chunk of 1024 out of 49152 total
float_buffer = new Float32Array(response_buffer, ((i - 1) * chunk_size));
// add_data(net_len, float_buffer);
break;
case 0:
break;
default:
float_buffer = new Float32Array(response_buffer, ((i - 1) * chunk_size)), chunk_size);
//add_data(net_len, float_buffer);
break;
}
}
My problem is if I call this on the first run for the end of my buffer:
// i - 1 = 47 * chunk_size
new Float32Array(response_buffer, ((i - 1) * chunk_size));
the same statement fails on the next run where I call:
new Float32Array(response_buffer, ((i - 1) * chunk_size), 1024);
Although I can read here, that
I can do this:
Float32Array Float32Array(
ArrayBuffer buffer,
optional unsigned long byteOffset,
optional unsigned long length
);
Question:
Why is my loop failing after declaring the first Float32Array view on my response_offer ArrayBuffer?
I think you have an extra ")" in the first line of your "default" case.
float_buffer = new Float32Array(response_buffer, ((i - 1) * chunk_size)), chunk_size);
Should be:
float_buffer = new Float32Array(response_buffer, ((i - 1) * chunk_size), chunk_size);
So. Finally understand... maybe this helps the next person wondering:
First off - I was all wrong in trying to read my data, which is 4 byte single format.
If I have an arrayBuffer with byteLength = 49182 this means there are that many entries in my array.
Since my array is 4 byte single format, I found out with some SO-help and searching that this is readable with getFloat32 AND that 4 entries comprise one "real" value
My data contains 3 measurements a 4000 data points stored in units of 1024 column by column.
So if I have 12000 data-points and 49182/4 = 12288 datapoints, I will have 288 empty data points at the end of my data structure.
So my binary data should be stored like this:
0 - 1024 a
1025 - 2048 a
2049 - 3072 a
3072 - 4000 [a
4001 - 4096 b]
4097 - 5120 b
5121 - 6144 b
6145 - 7168 b
7169 - 8000 [b
8001 - 8192 c]
8193 - 9216 c
9217 - 10240 c
10240 - 11264 c
11264 - 12000 [c
12000 - 12288 0]
My final snippet will contain 288 empty results, because 3x4000 datapoints in 1024 chunks will return some empty results
To read, I found a nice snippet here (dynamic high range rendering), which helped me to this:
// ...
raw_data = ...
data = new DataView(raw_data);
...
tmp_data = new Float32Array(byte_len / Float32Array.BYTES_PER_ELEMENT);
len = tmp_data.length;
// Incoming data is raw floating point values with little-endian byte ordering.
for (i = 0; i < len; i += 1) {
tmp_data[i] = data.getFloat32(i * Float32Array.BYTES_PER_ELEMENT, true);
}
Now I have a single array with which I can work and build my processing structure.

Categories

Resources