Editing Values in Typed Arrays - javascript

Using JavaScript I would like to offset the elements in a typed array so that if the original array had values of 0 to 99, the new array would start at 10 and go to 99 leaving 10 empty elements for new data.
So if the original array can be viewed as a 10 x 10 grid, I would like to move all data up one row and then enter new data in the bottom row.
I know this can be done using a loop but this method would be too slow for my project which has a much larger array (990 x 1920).
I've tried ArrayBuffers and got nowhere.
The problem with the following test method (using subarray) is that although data1 size is specified as 100 it appears to reduce down to the subarray size when applied. I can then find no way to add further data at the end.
function initialize() {
data = new Uint32Array(100);
data1 = new Uint32Array(100);
for (var i = 0; i < data.length; i++) {
data[i] = i;
}
data1 = data.subarray(10);
console.log(data1);
}
Is there any way other than a loop to offset data in a typed array and add data at the end.
OK, I found a solution at Typed Arrays in Gecko 2: Float32Array concatenation and expansion using Set().

In JavaScript, a typed array is a fixed-length data structure which is based on ArrayBuffer i.e. a pre-allocated piece of memory anyway. Because of that, typed arrays do not have variable-length methods like push, pop etc.
So in order to offset a typed array you only have two options.
Preallocate a lot of memory in advance and shift the 'typed array', which is a actually a view over a memory block
var SIZE=100;
var SHIFT=10;
var buffer = new ArrayBuffer(100000); // preallocate a lot of memory
var data = new Uint32Array(buffer, 0, SIZE);
for (var i = 0; i < SIZE; i++) {
data[i] = i;
}
var data1 = new Uint32Array(buffer, Uint32Array.BYTES_PER_ELEMENT*SHIFT, SIZE)
data1[90]=100; //set the 101st (91st) element
console.log('data1', data1);//10,11,...98,99,100,0,0,0,0,0,0,0,0,0
Copy the slice of the old data into a new memory area.
var SIZE=100;
var SHIFT=10;
var data = new Uint32Array(SIZE);
for (var i = 0; i < SIZE; i++) {
data[i] = i;
}
var data1 = new Uint32Array(SIZE)
data1.set(data.subarray(SHIFT));
data1[90]=100; //set the 101st (91st) element
console.log('data1', data1); //10,11,...98,99,100,0,0,0,0,0,0,0,0,0
This is a classic space-time tradeoff.
The first option takes more memory but less cpu cycles, the second option is the other way round.

Related

Push strings to an array multiple times based on length of another array of arrays javascript

I am new to JS and I have a program (written in the Common Workflow Language) that takes in two arrays, one of files one of strings. The arrays are initially the same length:
var headers = ["Header1", "Header2", "Header3"];
var files = [file1, file2, file3];
Each header corresponds to a particular file so Header1 -> file1, Header2 -> file2, Header3 -> file3. I have a step in my workflow that splits the files by a certain number of lines into an array of split files, so now I have an array of arrays of files like so:
var files = [[01.file1, 02.file1, 03.file1], [01.file2, 02.file2],
[01.file3, 02.file3, 03.file3, 04.file3, 05.file3]];
Since the files are split by a certain number of lines, I have no way of knowing beforehand how many times the file is going to be split (I am processing a lot of files at a time).
Basically, what I am trying to do now, is duplicate each header equal to the length of each subarray, so Header1 should be duplicated 3 times, Header2 should be duplicated twice, and Header3 should be duplicated 5 times.
I have seen a few posts on how to duplicate a single string into an array of known length that use the var arrayNew = new Array(int).fill(x) method, but this seems to statically assign a length to an array and fill it with a single value.
I am trying to duplicate the headers strings by the length of the files array of arrays. Here is what I have so far:
var dupStrings = [];
for (var i = 0; i < files.length; i++) {
var arrLen = files[i].length;
dupStrings.push(headers[i].repeat(arrLen));
}
But this is currently giving me:
var headers = ["Header1Header1Header1", "Header2Header2",
"Header3Header3Header3Header3Header3"]
I now understand why that is happening, but I don't know how to fix it. I would like it to be:
var headers = [["Header1", "Header1", "Header1"], ["Header2", "Header2"],
["Header3", "Header3", "Header3", "Header3", "Header3"]]
Your current issue occurs, because headers[i].repeat(arrLen) returns string, whereas you need an array, you may do dupStrings.push(Array(arrLen).fill(headers[i])) instead.
However, there's the other way around:
const headers = ["Header1", "Header2", "Header3"],
files = [[01.file1, 02.file1, 03.file1], [01.file2, 02.file2], [01.file3, 02.file3, 03.file3, 04.file3, 05.file3]],
result = headers.map((h,i) => Array.from({length: files[i].length}, () => h))
console.log(result)
Try map and fill:
var headers = ["Header1", "Header2", "Header3"];
var files = [["01.file1", "02.file1", "03.file1"], ["01.file2", "02.file2"],
["01.file3", "02.file3", "03.file3", "04.file3", "05.file3"]];
var dupStrings = headers.map(function(element, index) {
return Array(files[index].length).fill(element);
});
console.log(dupStrings)
Your for-loop is not correct, you have to iterate on files[i] in order to create an array because repeat is creating a string. The answer without using map of fill (it may be difficult for you, a newbie to understand how map and fill work) is :
for (let i = 0; i < files.length; i++) {
for (let j = 0; j < files[i].length; j++) {
dupStrings.push(headers[i]);
}
headers[i] = dupStrings;
dupStrings = [];
}

dynamic array elements through loop

I am trying to create an array of images in javascript for my website when I declare array size it is working but when I am trying to take it as a dynamic array it is not showing images. can anyone tell me what's wrong with this code?
var theImages = new Array()
for (i = 0; i < theImages.length; i++)
{
theImages[i] = i+".jpg"
}
The initial size of theImages is 0.
You need to use
for (i = 0; i < 5; i++)
{
theImages[i] = i+".jpg";
}
replace 5 by the number of images you have.
This is happening because you are looping an empty array, the length/size of the array is 0 because you have just created a new array and are looping it without any elements in it yet.
If you wish to add all images to an array, you will have to know the total number of images you have/ count of images, and then run the loop to add the images in the array, which you were able to do successfully you said.
var theImages = new Array();
for (i = 0; i < 6; i++)
{
theImages[i] = i+".jpg";
}
If you are getting the image names for SQL, it is a different query you want to use, let me know if that is what you are looking for.

Breaking up large JSON object

I have a lot of files that I need to upload to my database, I am doing this through the browser and the server is having sizing issues with the data that is being sent to it and it rejects it. The server is not under my control in this context so I need to break up this object(s) into smaller objects before sending them to the server to get inserted into the database (rethinkdb if it matters). There is no order they need to be inserted in I just need to break up the file into smaller pieces.
I know I need a loop, but I do not understand how I can loop through 100 objects, save them as another object send them to the server, then start from 101 and so on....
Looping through all objects I get but this I cannot figure out or find examples for.
The code below is working for its purpose however it only goes to 250 then stops, it doesn't go past that.....
var lineData = jsonData.theData;
var newData = [];
var newLine;
//Shows on the browser console how many objects there are in the data
console.log(jsonData.theData.length);
//Goes through the Data and grabs the first 1000 lines
for(var i = 0; i< 250; i++){
newLine = lineData[i]
newData.push(newLine);
console.log(lineData[i]);
}
All you need to do is loop through your objects and for every 100th object, push out your new array and start over. So something like:
var lineData = jsonData.theData;
var newData = [];
for (var i=0; i < lineData.length; i++) {
newLine = lineData[i];
newData.push(newLine);
if (i && !(i % 100)) {
// upload newData
newData = [];
}
}
// check if there's any data left
if (newData.length) {
// upload the remaining data
}

Reorganizing multidimensional arrays based on multiple value characteristics in JavaScript?

I'm having trouble organizing this data the way I would like it to. On my pages, a few things happen that I know work...
Some PHP spits out a multidimensional associative array. The top level of this array is an array of regions. Each region is an array of timezones.
Some more PHP creates a second multidimensional associative array. The top level of this array is an array of regions. Each region is an array of UTC offsets.
Both arrays are generated in the same order from the same data. This means that $offsets["region"][0] will have be based on the same timezone as $timezones["region"][0].
Both arrays are encoded into JSON and passed to my JavaScript.
I have the following JavaScript code...
var tempCurrentTimezoneArray = timezoneArray[ $("select[name='region_selector']").val() ];
var tempCurrentOffsetArray = timezoneOffsetArray[ $("select[name='region_selector']").val() ];
var groupedTimezones = {};
var groupedOffsets = {};
for (counter = 0; counter < tempCurrentOffsetArray.length; counter++) {
significantOffset = tempCurrentOffsetArray[counter].substr(tempCurrentOffsetArray[counter].length - 2);
if (!(significantOffset in groupedTimezones)) {
groupedTimezones[significantOffset] = [];
groupedOffsets[significantOffset] = [];
}
groupedTimezones[significantOffset].push(tempCurrentTimezoneArray[counter]);
groupedOffsets[significantOffset].push(tempCurrentOffsetArray[counter]);
}
var offsetArray = [];
for (var property in groupedTimezones) {
if (!groupedTimezones.hasOwnProperty(property)) {
continue;
}
groupedTimezones[property].sort();
groupedOffsets[property].sort();
offsetArray.push(parseInt(property));
}
offsetArray.sort();
var currentTimezoneArray = [];
var currentOffsetArray = [];
for (counter = 0; counter < offsetArray.length; counter++) {
currentTimezoneArray = currentTimezoneArray.concat(groupedTimezones[offsetArray[counter]]);
currentOffsetArray = currentOffsetArray.concat(groupedOffsets[offsetArray[counter]]);
}
In the top two lines I remove all of the timezone data not pertaining to the region selected on the page. This means that I am left with 2 single-dimensional arrays. Any given index of either array relates directly to the other array. I.E....
tempCurrentOffsetArray[0] is the UTC offset of the timezone found at tempCurrentTimezoneArray[0].
The rest of this code is intended to complete the following tasks...
Group timezones and offsets by their UTC offset.
Organize each offset group in alphabetical order.
Create two arrays where values are organized first by UTC offset and second by alphabetical order.
The problem I'm having is that on some regions I receive almost perfect listings,and on others I receive some listings with a seemingly random number of undefined values, and I'm not sure why. Can anyone identify the syntactical or logical errors in my code?
JSON of tempCurrentTimezoneArray input data here
JSON of tempCurrentOffsetArray input data here
You think still too complicated. It is a mess to keep these two Arrays in sync, better use one Array with objects.
var region_selector = $("select[name='region_selector']").val();
var tempCurrentTimezoneArray = timezoneArray[ region_selector ];
var tempCurrentOffsetArray = timezoneOffsetArray[ region_selector ];
//consolidate the Arrays
var data = []; //create a new Array `data`
for(var i = tempCurrentOffsetArray.length; i--; ){
//write into Array `data` at index `i` an object, containing these properties:
//`timezone`, `offset` and `offsetValue`, and their respective values
data[i] = {
timezone: tempCurrentTimezoneArray[i],
offset: tempCurrentOffsetArray[i],
//the + at the beginning converts the value behind that into a Number, like parseFloat() would do
offsetValue: +tempCurrentOffsetArray[i].match(/^GMT([+-]\d+(?:\.\d+)?)$/)[1]
}
}
//sorter-function for data to sort the values by offsetValue ASC first, then by timezone ASC
function sortedByOffset(a, b){
return a.offsetValue - b.offsetValue || a.timezone.localeCompare(b.timezone);
}
//you should do this as late as possible, usually after the filtering
data.sort(sortedByOffset);
If you insist on the two output-Arrays
var currentTimezoneArray = data.map(d => d.timezone);
var currentOffsetArray = data.map(d => d.offset);
otherwise this is imo more flexible
//utilities to fetch a property off the object
var getTimezone = d => d.timezone;
//aka function getTimezone(d){ return d.timezone }
var getOffset = d => d.offset;
//aka function getOffset(d){ return d.offset }
//example usages:
data.filter(d => d.offset === "GMT-5").map( getTimezone );
data.filter(d => d.offsetValue >= -2 && d.offsetValue <= -5 ).map( getOffset );
taking the first example; thinking in terms of a SQL-statement this would be
SELECT timezone FROM data WHERE offset = "GMT-5"
get me the timezone-values for each entry where the offset is GMT-5
you start with an Array containsing all values data then you get the subset you are interested in (in this case every entry, with the offset "GMT-5") by filtering.
Now you have an Array containing all values you are intersted in, but still the whole objects; like a SELECT * FROM ...
the map() function calls the function getTimezone() on every entry in this subset and returns another Array containing only the timezone-values.
The second example defines a range for the filter (every entry from GMT-2 to and including GMT-5 and every GMT in between) and returns for these entries the offset-protperty.
I discovered the issue with my code. There were actually three issues the first being on line 6. After looking over the data one more time I realized that some of the values had offsets that were floating point integers or had more than two significant digits. The new line 6 is...
significantOffset = tempCurrentOffsetArray[counter].replace(/[^\d.-]/g, '');
The second issue with my code also had to do with parsing floating integers. On line 21 we need to use parseFloat instead of parseInt. The new line 21 is...
offsetArray.push(parseFloat(property));
The third issue lies on line 23. sort() needs to be told how to sort the integers. This is the new line 23...
offsetArray.sort(function(a, b){return a-b});
The final code looks like this...
var tempCurrentTimezoneArray = timezoneArray[ $("select[name='region_selector']").val() ];
var tempCurrentOffsetArray = timezoneOffsetArray[ $("select[name='region_selector']").val() ];
var groupedTimezones = {};
var groupedOffsets = {};
for (counter = 0; counter < tempCurrentOffsetArray.length; counter++) {
significantOffset = tempCurrentOffsetArray[counter].replace(/[^\d.-]/g, '');
if (!(significantOffset in groupedTimezones)) {
groupedTimezones[significantOffset] = [];
groupedOffsets[significantOffset] = [];
}
groupedTimezones[significantOffset].push(tempCurrentTimezoneArray[counter]);
groupedOffsets[significantOffset].push(tempCurrentOffsetArray[counter]);
}
var offsetArray = [];
for (var property in groupedTimezones) {
if (!groupedTimezones.hasOwnProperty(property)) {
continue;
}
groupedTimezones[property].sort();
groupedOffsets[property].sort();
offsetArray.push(parseFloat(property));
}
offsetArray.sort(function(a, b){return a-b});
var currentTimezoneArray = [];
var currentOffsetArray = [];
for (counter = 0; counter < offsetArray.length; counter++) {
currentTimezoneArray = currentTimezoneArray.concat(groupedTimezones[offsetArray[counter]]);
currentOffsetArray = currentOffsetArray.concat(groupedOffsets[offsetArray[counter]]);
}

Javascript multiple array push() differences

I have problem with pushing data. I want to prepare data (time,temperature,humidity) for plotting (Dygraphs). But when I´m filling variable data with this one code (see below) I don´t get graph.
for (var i = 0; i < time.length; i++){
var t = new Date (time[i]);
data.push(t);
for(var n = 0; n < 2; n++){
data.push([data_graph[n][i]]);
}
}
But when I leave one for-cycle and manually write nums of arrays (see below), It works and I get graph.
for (var i = 0; i < time.length; i++){
var t = new Date (time[i]);
data.push([t,data_graph[0][i],data_graph[1][i]]);
}
I got idea to use temporary variable, but also with no success.
for (var i = 0; i < time.length; i++){
var data_temporary = [];
var t = new Date (time[i]);
for(var n = 0; n < 2; n++){
data_temporary.push([data_graph[n][i]]);
}
data.push([t,data_temporary]);
}
So my question is...where could be a problem?
Thanks in advance for answers.
Yes, your three code snippets generate three different data structures:
[t, [datagraph…], [datagraph…], t, [datagraph…], [datagraph…], …]
[[t, datagraph…, datagraph…], [t, datagraph…, datagraph…], …]
[[t, [[datagraph…], [datagraph…]]], [t, [[datagraph…], [datagraph…]]], …]
Too often you pushed one-element-arrays, btw.
So if you want struc#2 generated by a loop, use
for (var i=0; i<time.length; i++) {
var t = new Date (time[i]);
var temp = [t]; // or temp=[]; temp.push(t);
for (var j=0; j<data_graph.length; j++) // or j<2 if that's certain
temp.push(data_graph[j][i]);
data.push(temp);
}
Each call to push() creates a new element in your data array. So, in your first example, you are passing 3 objects on each iteration of the outer for loop, and in the third example you are passing an object that consists of time and an array of two values. But the dygraph script apparently expects objects consisting of three elements, so your second example works.
The second (working) version creates a two dimension array with time.length elements in the first dimension each containing three elements [t, x, y], as required.
In the first version you are creating a one-dimensional array [t0, [x0], [y0], t1, [x1], [y1], ...].
Your third version doesn't work because whilst you correctly create time.length elements in the first dimension, the elements themselves are [t, [[x], [y]]], and not [t, x, y].

Categories

Resources