Iterate over a large 2D array with nested loop in JavaScript - javascript

I am trying to iterate over a large 2D array which is over 3000 rows and 54 columns. Each index contains either a string or integer value. When I try to use a nested for loop I am unable to test it since it just takes to long to complete. How can I get around this issue?
I have this code from an earlier post that does something similar:
function getOrder() {
const srcSheetName = "result";
const dstSheetName = "Order Changes";
const ss = SpreadsheetApp.getActiveSpreadsheet();
// 1. Retrieve source values.
const srcSheet = ss.getSheetByName(srcSheetName);
const [[,,,,,,,, ...header], ...srcValues] = srcSheet.getRange("F1:BQ" + srcSheet.getLastRow()).getValues();
// 2. Create an object using the source values.
const srcObj = srcValues.reduce((o, [a,,,,,,,, ...v]) => {
const temp = v.reduce((s, r, i) => {
if (r.toString() != "") s += `${header[i]} (${r}) `;
return s;
}, "");
return Object.assign(o, {[a]: temp || ""});
}, {});
// 3. Retrieve the header column of destination values.
const dstSheet = ss.getSheetByName(dstSheetName);
const dstRange = dstSheet.getRange(3, 1, dstSheet.getLastRow() - 1);
const dstValues = dstRange.getValues();
// 4. Create the output values using the header column and the object.
const putValues = dstValues.map(([a]) => [srcObj[a] || ""]);
console.log(srcObj)
// 5. Put the values.
dstRange.offset(0, 2).setValues(putValues);
}
The above code matches names on two different sheets and returns the values and headers of each column if a match is found and does so very quickly with the same number of entries. I assume it is so quick because of .reduce to remove unnecessary information in the 2d array.
How can I achieve a similar speed? I would like to search the 2d array for non-zero entries of a row in the last 12 columns. If any of the columns contain a value I would like to return index 0 of that row and continue until the array has been completely cycled through.
I have tried to adjust the above code but I don't understand it entirely and can't manipulate it how I'd like. Here is what I have written:
function getCustomer(){
const srcSheetName = "result";
const dstSheetName = "Allergy";
const ss = SpreadsheetApp.getActiveSpreadsheet();
const srcSheet = ss.getSheetByName(srcSheetName);
const allergyRange = srcSheet.getRange('F1:BQ' + srcSheet.getLastRow()).getValues();
const dstSheet = ss.getSheetByName(dstSheetName);
Logger.log(allergyRange);
for (let i = 0; i < allergyRange.length; i++){
for (let k = 0; k < allergyRange[i].length; k++){
Logger.log("hi");
}
}
}
I would like to nest an if statement in the code I've written but am unaware of a way to refer to a range of indices in a row of a 2d Array and at this point I think this would take too much time to be practical. Any tips would be greatly appreciated.

Assuming allergyRange is formatted like [row, ...] where each row is an array with each of its indices referring to a column:
allergyRange.map(row => row.slice(row.length-12)).forEach((row, i) => {
if(!row.every(val => val == 0)) console.log(allergyRange[i][0])
});
This maps a new array of arrays that contain just the last 12 columns, checks if every value in that row is equal to 0, and if not logs the 0th index of that row.

Related

How to compare several rows of values between them on google app script

I have a google sheet with the following data
google sheet "formatfruit"
Each user has a fruit and a vegetable associated, I want to know the percentage of similarity between each user in the google sheet "formatfruit"
Today I can compare the first user kevin with all the others and return his percentage of similarity in another google sheet called "matchofruit".
I associated the value "1" when a user has a fruit or a vegetable in common with kevin and the value "0" if the user has no fruit or vegetable in common.
The result that appears in the google sheet matchofruit is here
google sheet matchofruit
The code I used is below
function myFunction() {
var formafruit = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("fruit");
var matchofruit = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("matchofruit");
var n = formafruit.getLastRow();
var user1 = formafruit.getRange(2,1).getValues();// name user 1 : kévin
var user2 = formafruit.getRange(3,1).getValues();// name user 2 : mikael
for (var i = 2;i<4;i++) { // i<4 because we have 3 column in formafruit
for (var z = 2;z<n+1;z++) {
matchofruit.getRange(z,1).setValue(user1); // Return the name of the users in the first column
if(formafruit.getRange(2,i).getValue() === formafruit.getRange(z,i).getValue()){ // Compare the fruits and vegetables associated to kévin with the fruits and vegetables associated to each user
matchofruit.getRange(z,i).setValue(1); // Returns 1 if kevin shares at least one fruit or vegetable in common with a user
}
else {
matchofruit.getRange(z,i).setValue(0);
}
}
}
// Calculate the % of common values
for (var p = 0;p<n-1;p++){}
for (var s = 0;s<n-1;s++) {
var scoreforall = matchofruit.getRange(2,2,p,11).getValues()[s]// get the array of all the matches
let sum = 0;
for (let e = 0; e < scoreforall.length; e++) {
sum += scoreforall[e]; // add each array together
}
var sumTotal= Math.round(sum*(100/2)); // convert in percentage each sum
matchofruit.getRange(s+2,4).setValue(sumTotal); // send match values in column 4
}
// Return the result in a sentence
for (var a = 2;a<n+1;a++) {
var usern = formafruit.getRange(a,1).getValues(); //get all the users' emails in the formafruit
var valeurmatch = matchofruit.getRange (a,4).getValues(); // get value % of matches
matchofruit.getRange(a,5).setValue(user1+" "+"have"+" "+valeurmatch+"%"+" "+"of values in common with"+" "+usern);//Return the % of common value between Kevin and the other users
}
}
I would like to be able to do the same for mikael, gauthier, vanessa and mireille knowing that I only put 5 users to simplify the problem but that in truth there can be more than 100 users and that each user has more than 11 associated values(here we have only 2 different type of values, fruits and vegetables). It's been several weeks that I'm looking for a solution to my problem and I haven't found anything to solve it. Do you have an idea?
Thanks!
I believe your goal is as follows.
You want to achieve the following situations. (The following images are from OP's question.)
From
To
In your situation, for example, when 5 users are used, you want to create 25 rows.
When I saw your script, the methods of setValues and getValues are used in the loop. I think that this becomes the high process cost. Ref So, I would like to propose the following modification.
Modified script:
function myFunction2() {
const ss = SpreadsheetApp.getActiveSpreadsheet();
const [src, dst] = ["fruit", "matchofruit"].map(s => ss.getSheetByName(s));
const [, ...values] = src.getDataRange().getValues();
const res = values.flatMap(([a1, ...v1]) =>
values.map(([a2, ...v2]) => {
const temp = v1.map((e, i) => e == v2[i] ? 1 : 0);
const sum = (temp.filter(f => f == 1).length / temp.length) * 100;
const matchResult = `${a1} have ${sum}% of values in common with ${a2}`;
return [a1, ...temp, sum, matchResult];
})
);
dst.getRange(2, 1, res.length, res[0].length).setValues(res);
}
In this modification, the values are retrieved from "fruit" sheet. And, an array for putting to "matchofruit" sheet is created. And then, the created array is put into "matchofruit" sheet.
Note:
In this sample script, the header row of "matchofruit" has already been put. If you want to put the header row to "matchofruit" sheet, please add it to my proposed script.
References:
map()
filter()

Ridiculously slow Apps-Script Loop

I've just switched from excel to Google sheets and I've had to go through a bit of a learning curve with moving on with "Macros" or scripts as they're now called.
Anyway, a short while later I've written a loop to go through everything in column B and if it's less than 50, delete the row.
It works and I'm happy but it's so slow. I have about 16,000 rows and I'll probably end with more. I let it run for about 4 minutes and it didn't even get rid of 1,000 rows. I refuse to believe that a popular programming language is that slow I can still read stuff as it's being deleted 20 rows up.
function grabData(){
let sheet = SpreadsheetApp.getActive().getSheetByName("Keywords");
var rangeData = sheet.getDataRange();
var lastColumn = rangeData.getLastColumn();
var lastRow = rangeData.getLastRow();
let range = sheet.getRange("B2:B16000");
let values=range.getValues();
for (var i = 0, len = values.length; i<len; i++){
if(values[i] <= 50 ){
sheet.deleteRow(i);
i--
len--
};
};
}
I keep seeing somewhere that something's not being reset, but I have no idea what that means.
Is it because the array length starts off at 16,000 and when I delete a row I'm not accounting for it properly?
Since I never use formulas I would do it this way:
function grabData() {
let ss = SpreadsheetApp.getActive();
let sh = ss.getSheetByName("Keywords");
let rg = s.getRange(2, 2, sh.getLastRow() - 1, sh.getLastColumn());
let values = rg.getValues();
let oA = [];
values.forEach((r, i) => {
if (r[0] > 50) {
oA.push(r);
}
});
rg.clearContent();
sh.getRange(2,1,oA.length,oA[0].length).setValues(oA);
}
It's much faster but it will probably mess up your formulas. Which is one of the reasons I never use formulas. Deleting lines is quite slow. Pretty much anything you do with the UI is slow.
Welcome to App Script and the community! App Script is actually very fast if follow the best practice of App Script.
Here is an example for you that will complete what you need in one second (*modify the variable value in config to fit your own application):
function myFunction() {
// config
const filterValue = 50
const targetSheetName = "Sheet1"
const targetColumn = "A"
const startRowNum = "2"
// get data from target sheet
const ss = SpreadsheetApp.getActiveSpreadsheet()
const sheet = ss.getSheetByName(targetSheetName)
const endRowNum = sheet.getLastRow()
const targetRange =`${targetColumn + startRowNum }:${targetColumn + endRowNum}`
const data = sheet.getRange(targetRange).getValues()
// filter data based on filterValue and set filtered result into new ary
const ary = data.filter(row=>row[0]>=filterValue)
//get max row number in the sheet
const maxRowNum = sheet.getMaxRows()
// break if nothing is filtered out
if(ary.length===0){
// remove all row and break
let deleteStartFromRowNum = parseInt(startRowNum,10) - 1
let deleteRowsCount = maxRowNum - deleteStartFromRowNum
sheet.deleteRows(deleteStartFromRowNum, deleteRowsCount)
return
}
// break if all is filtered out
if(ary.length===data.length){
// remove all trailing empty rows
if(endRowNum<maxRowNum){
let deletStartFromRowNum = endRowNum+1
let deleteRowsCount = maxRowNum-endRowNum
sheet.deleteRows(deletStartFromRowNum,deleteRowsCount)
}
return
}
// get lowerbound (the last row of filtered data in ary)
const lowerBound = parseInt(startRowNum,10) + ary.length - 1
// set ary into sheet range according to lowerBound value
sheet.getRange(`${targetColumn + startRowNum}:${targetColumn + lowerBound.toString()}`).setValues(ary)
// delete rest of the rows that are below lower bound
let deleteStartFromRowNum = lowerBound + 1
let deleteRowsCount = maxRowNum - lowerBound
sheet.deleteRows(deleteStartFromRowNum, deleteRowsCount)
return
}
Issue:
In Apps Script, you want to minimize calls to other service, including requests to Spreadsheets (see Minimize calls to other services). Calling other services in a loop will slow down your script considerably.
Because of this, it's much preferrable to filter out the undesired rows from values, remove all existing data in the range via Range.clearContent(), and then use setValues(values) to write the filtered values back to the spreadsheet (see Use batch operations).
Code snippet:
function grabData(){
let sheet = SpreadsheetApp.getActive().getSheetByName("Keywords");
const range = sheet.getRange("B2:B16000");
const values = range.getValues().filter(val => val[0] > 50);
range.clearContent();
sheet.getRange(2,2,values.length).setValues(values);
}
Reference:
Best Practices

Random Selection in a Column

I've modified a code to select a data randomly from A Column cells. The problem I'm facing is, I'm only able to get the data from A1. and rest of the data are not showing. Where did I go wrong?
function getData () {
var SS = SpreadsheetApp.getActiveSheet()
var Avals = SS.getRange("A1:A").getValues();
var numberOfValues = Avals.filter(String).length;
var data = SS.getRange(1,1,numberOfValues).getValues();
for(var i = 0; i < data.length; i++)
{
var j = Math.floor(Math.random()*(data[i].length)); //method of randomization
var element = data[i][j];
return element;
logger.log(element);
}
}
Explanation:
getValues() returns a 2D array. In your case you have a single column, therefore data has the format of: [[a1],[a2],[a3],..]]. data[i] will give you a single element of this array. For example data[0] is [a1] and as you can understand [a1].length is equal to 1 regardles of the chosen index. In other words, data[i].length is 1 for every i and therefore you are always getting the first element.
It is also worth mentioning that you have a return statement inside the for loop and therefore i gets only the first value 0 since the function is terminated when reaches the return statement. You don't need a for loop if you want to get a single random element from the column.
Since data[i].length is equal to 1 this expression Math.random()*(data[i].length) returns a number between 0 and 1 but less than 1. Therefore Math.floor(Math.random()*(data[i].length)) always returns 0 and as a result data[0][0] is equal to the value of the first cell A1.
Please notice that logger.log(element) is wrong. It should be Logger.log(element); but you are not getting any error since return is before that line and the function never reaches that line.
Finally, I used flat() to convert the 2D array to 1D and therefore data.length returns the correct length of the array but also you can now index it with one variable.
Solution:
function getData () {
const SS = SpreadsheetApp.getActive();
const sh = SS.getActiveSheet();
const Avals = sh.getRange("A1:A").getValues();
const numberOfValues = Avals.filter(String).length;
const data = sh.getRange(1,1,numberOfValues).getValues().flat();
const j = Math.floor(Math.random()*(data.length)); //method of randomization
const element = data[j];
Logger.log(element);
return element;
}

Pasting multiple rows of data into single cell using JavaScript

So I have combinations of names to tasks in a table where several different task are associated with the same name. But I need to put the task into one cell next to the associated name. Using JavaScript. Heres what I got;
function Unique(){
var ss = SpreadsheetApp.openById("ID");
var dataRaw = ss.getSheetByName("Sheet1");
var destination = ss.getSheetByName("Sheet2");
var names2 = dataRaw.getRange(2,10,dataRaw.getLastRow(),1).getValues();
var names1 = names2.flat(1);
var names = names1;
//var names = ["name1","name1","name2", "name3", "name3"];
var uniqueNames = []; //empty array
var count = 0;
var found = false;
for (i = 0; i < names.length; i++){
for(y =0; y < uniqueNames.length; y++){
if(names[i] == uniqueNames[y]){
found = true;
}
}
count++;
if(count == 1 && found == false){
uniqueNames.push(names[i]);
}
count = 0;
found = false;
}
/* can I use this??? maybe it's not needed
var uniqueNames2 = uniqueNames.map(function(obj) {
return Object.keys(obj).sort().map(function(key) {
return obj[key];
});
});
*/
var dest = destination.getRange(1,2,uniqueNames.length,uniqueNames[0].length);
dest.setValue(uniqueNames); //maybe this is not needed
console.log(uniqueNames[0].length);
}
My approach is to;
take in names and output the unique names so there is no doubles
once i have unique names use some type of for() loop or map() function to find tasks and pair with names? maybe im wrong?
and then setValues() to the range that I need.
The problems that I'm running into are that My Unique() function needs a regular array not array of arrays, which i fix using
array.flat(1)
but then to paste the values javaScript needs the array or arrays to be just an array which I COULD fix with
Object.keys(obj).sort().map(function(key)
in the commented out section? to turn an array of arrays back into an array... but then my "width" is not consistent for my array, columns, and I get the error that my range is not the same number of columns as my data. I feel that this is fairly simple and I am grossly over complicating things. Any help would be great thank you. My google sheet below https://docs.google.com/spreadsheets/d/1rbz52kkzhVAGX21MUVoexzPUvWxjk-RCw-5PrRLoBBc/edit?usp=sharing
I believe your goal as follows.
You want to achieve the following conversion.
From
Task Names
Task 1 name one
Task 2 name one
Task 3 name one
Task 4 name one
Task 5 name one
Task 1 name two
Task 2 name two
Task 3 name two
Task 1 name three
Task 2 name three
Task 3 name three
To
task names
Task 1
Task 2
Task 3
Task 4
Task 5 Name one
Task 1
Task 2
Task 3 name two
Task 1
Task 2
Task 3 name three
For this, how about this answer?
Modification points:
In your script, for example, about var names2 = dataRaw.getRange(2,10,dataRaw.getLastRow(),1).getValues();, I thought that you might misunderstand the row and column for getRange. And, in this case, only one row Names of column "B" on "Sheet1" is retrieved. The row of Task is not retrieved in your script. And also, from dest.setValue(uniqueNames);, you might misuderstood setValue and setValues.
When above points are reflected to your script, it becomes as follows.
Modified script:
In this modification, at name2, the values from the cells "B2:B12" are retrieved, and the unique values are retrieved using your script. Then, the values from the cells "A2:B12" are retrieved, and the values for putting to Spreadsheet are created using the created unique values. Then, the created values are put to the Spreadsheet.
Modified script:
function Unique_org2(){
var ss = SpreadsheetApp.openById("ID");
var dataRaw = ss.getSheetByName("Sheet1");
var destination = ss.getSheetByName("Sheet2");
var names2 = dataRaw.getRange(2,2,dataRaw.getLastRow()-1,1).getValues(); // <--- Modified
var names1 = names2.flat(1);
var names = names1;
var uniqueNames = [];
var count = 0;
var found = false;
for (i = 0; i < names.length; i++){
for(y =0; y < uniqueNames.length; y++){
if(names[i] == uniqueNames[y]){
found = true;
}
}
count++;
if(count == 1 && found == false){
uniqueNames.push(names[i]);
}
count = 0;
found = false;
}
// --- I added below script.
var values = dataRaw.getRange(2, 1, dataRaw.getLastRow() - 1, 2).getValues(); // Added
var uniqueNames = uniqueNames.reduce((ar, e) => {
var temp = "";
values.forEach(([a, b]) => {
if (e == b) temp += a + "\n";
});
ar.push([temp.trim(), e]);
return ar;
}, []);
// ---
var dest = destination.getRange(2,1,uniqueNames.length,uniqueNames[0].length); // <--- Modified
dest.setValues(uniqueNames); // <--- Modified
}
Other pattern:
In this pattern, in order to achieve your goal, I would like to propose the other sample script of following flow. This flow might be able to reduce the process cost from above modified script.
Retrieve values from the cells "A2:B12" of "Sheet1".
Create an object from the retrieved values.
Convert the object to an array for putting to Spreadsheet.
Put the values to Spreadsheet to the destination sheet.
Sample script:
function Unique(){
var ss = SpreadsheetApp.openById("ID");
var dataRaw = ss.getSheetByName("Sheet1");
var destination = ss.getSheetByName("Sheet2");
// 1. Retrieve values from the cells "A2:B12" of "Sheet1".
const values = dataRaw.getRange(2, 1, dataRaw.getLastRow() - 1, 2).getValues();
// 2. Create an object from the retrieved values.
const obj = values.reduce((o, [a, b]) => Object.assign(o, {[b]: (o[b] ? o[b] + a : a) + "\n"}), {});
// 3. Convert the object to an array for putting to Spreadsheet.
const res = Object.entries(obj).map(([k, v]) => [v.trim(), k]);
// 4. Put the values to Spreadsheet to the destination sheet.
destination.getRange(2, 1, res.length, res[0].length).setValues(res);
}
References:
getRange(row, column, numRows, numColumns)
setValue(value)
setValues(values)

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]]);
}

Categories

Resources