Array of column Letters to Array of Column Numbers not working - google-apps-script

This is more or less my first attempt at writing a Javascript function and I want to convert an array of column numbers to an array of column letters
If I run testFunction I get undefined
function testFunction() {
var ui = SpreadsheetApp.getUi();
aryCLTCN(["A","C","D"])
ui.alert(aryCLTCN[3]);
}
function aryCLTCN(array) {
var columnLet = array
var output = [];
for (var i = 0, length = columnLet.length; i < length; i++) {
output[i] = [];
output[i] = CLTCN(columnLet[(i)]);
}
}
function CLTCN(letter)
{
var column = 0, length = letter.length;
for (var i = 0; i < length; i++)
{
column += (letter.charCodeAt(i) - 64) * Math.pow(26, length - i - 1);
}
return column;
}

There are several problems with your code.
Within function testFunction() you call aryCLTCN(["A","C","D"]) but don't assign the result to a variable, then with aryCLTCN[3] you are trying to access a property "3" of the function itself. Which isn't a syntax error because functions can have properties, but the function has no such property so you get undefined. You need something like this:
var result = aryCLTCN(["A","C","D"]);
ui.alert(result[3]);
Except note that JavaScript arrays are zero-based, which means that [3] tries to access the fourth element, but your array only has three elements.
Within function aryCLTCN(array) you create an output array but don't return it. You need to add return output;.
Also with these two lines:
output[i] = [];
output[i] = CLTCN(columnLet[(i)]);
...the first line assigns output[i] to a new empty array, but the second line overwrites that with the return value from CLTCN(columnLet[(i)]);. You can remove output[i] = [];.
Putting all that together:
function testFunction() {
// var ui = SpreadsheetApp.getUi(); // commented out for demo in browser
var result = aryCLTCN(["A","C","D"])
// using alert() instead of ui.alert() for demo here in browser
alert(result[3]); // undefined because there's no 4th element
alert(result[2]); // shows third element
}
function aryCLTCN(array) {
var columnLet = array
var output = [];
for (var i = 0, length = columnLet.length; i < length; i++) {
output[i] = CLTCN(columnLet[(i)]);
}
return output;
}
function CLTCN(letter)
{
var column = 0, length = letter.length;
for (var i = 0; i < length; i++)
{
column += (letter.charCodeAt(i) - 64) * Math.pow(26, length - i - 1);
}
return column;
}
testFunction();
(Note that for the purposes of having a runnable code snippet in my answer I'm using alert() instead of ui.alert(), but in your real code you would stick with ui.alert().)

You get an undefined error because you are calling the trying to access an index on a function. aryCLTCN function needs to have a return the output array and you need to assign it to a variable in your testFunction to be able to access its elements.
Although there was nothing logically or effectively wrong with your functions, I have provided another working solution below.
function testFunction() {
var ui = SpreadsheetApp.getUi();
var colArr = ["A", "B", "Z", "AA", "AZ", "ZA", "AAA"];
var nColArr = colArr.map(function(col) {
var colNum = 0;
col.split('').forEach(function(l, i) { colNum += (l.charCodeAt() - 64) * Math.pow(26, col.length - 1 - i) });
return colNum;
});
ui.alert(nColArr); //Shows all elements inside the nColArr array.
ui.alert(nColArr[3]); //Shows the 4th element inside the nColArr array.
}
Try it out:
var colArr = ["A", "B", "Z", "AA", "AZ", "ZA", "AAA"];
var nColArr = colArr.map(function(col) {
var colNum = 0;
col.split('').forEach(function(l, i) {
colNum += (l.charCodeAt() - 64) * Math.pow(26, col.length - 1 - i)
});
return colNum;
});
console.log(nColArr);

Related

How to merge arrays by index AS3

Seeking a way to merge arrays by index like so:
var a1:Array = ["a", "b", "c"];
var a2:Array = ["1", "2", "3"];
var a3:Array = result: ["a", 1, "b", 2, "c", 3]
I've tried concat, push, splice... not getting close. Thanks.
function arrayMerge(arr1:Array, arr2:Array):Array {
var o:Array = new Array();
for (var i:int=0; i<Math.max(arr1.length, arr2.length); i++) {
if (i<arr1.length) o.push(arr1[i]);
if (i<arr2.length) o.push(arr2[i]);
}
return o;
}
Thanks Payam for answer and non-judgement. Here's how I applied your work:
var arr1:Array = ["question1", "question2", "question3"];
var arr2:Array = ["answer1", "answer2", "answer3"];
var o:Array = new Array();
for (var i:int=0; i<Math.max(arr1.length, arr2.length); i++) {
if (i<arr1.length) o.push(arr1[i]);
if (i<arr2.length) o.push(arr2[i]);
}
trace(o); //(question1,answer1,question2,answer2,question3,question3)
#AndyH :
payamsbr is right, but you may work with Vectors or Arrays
Perhaps tl; dr; but this is the principle.
If You want to understand something try those possibilities.
If you don't, just copy and paste some shorter code ;)
var v1:Vector.<String> = new <String>["a", "b", "c"];
var v2:Vector.<uint> = new <uint>[1, 2, 3]; // why do you use String here and not uint?
// if you want to convert a uint to a String, use myUint.toString();
function convertVectorToArray(v1:Vector.<String>,v2:Vector.<uint>):Array{
var mergedArray:Array = new Array();
if (v1.length != v2.length){
throw(new Error(" ***ERROR : the two Vectors or Arrays have not the same lenfgth!"));
}else{
for(var i:uint = 0; i <v1.length ; i++){
mergedArray.push(v1[i]);
mergedArray.push(v2[i]);
}
}
return(mergedArray);
}
function mergeVectors(v1:Vector.<String>,v2:Vector.<uint>):Vector.<Object>{
var mergedVector:Vector.<Object> = new Vector.<Object>();
if (v1.length != v2.length){
throw(new Error(" ***ERROR : the two Vectors or Arrays have not the same length!"));
}
for(var i:uint = 0; i <v1.length ; i++){
mergedVector.push(v1[i] as String);
mergedVector.push(v2[i] as uint);
}
return(mergedVector);
}
var mergedArray:Array = (convertVectorToArray(v1,v2));
var mergedVector:Vector.<Object> = (mergeVectors(v1,v2));
function listArray(arr:Array):String{
var str: String="";
if ((v1.length*2) != (v1.length + v2.length)){
throw(new Error(" ***ERROR : the two Vectors or Arrays have not the same length!"));
}else{
for (var i:uint = 0; i < arr.length ; i++){
str+="typeof(arr[" + i + "]) = " + (typeof(arr[i]) as String).toUpperCase() + ", value = " + arr[i] + "\n";
}
}
return str;
}
function listVector(vect:Vector.<Object>):String{
var str: String = "";
if ((v1.length*2) != (v1.length + v2.length)){
throw(new Error(" ***ERROR : the two Vectors or Arrays have not the same length!"));
}else{
for (var i:uint = 0; i < vect.length ; i++){
str+="typeof(vect[" + i + "]) = " + (typeof(vect[i]) as String).toUpperCase() + ", value = " + vect[i] + "\n";
}
}
return str;
}
trace(listArray(mergedArray));
trace(listVector(mergedVector));
You may add a sort() method if You need it (you didn't told about it)
And Always throw an Error if the 2 Arrays or Vectors don't have the same length!
Throwing an Error is the best way to understand if something goes wrong...
This will avoid You a lot of time if You need to debug Your code!!!
As You can see the output is the same, but if the Vector Class is used correctly, this is more efficient than an Array.
Output :
Since there's a Vector Class, I don't understand a lot of people who chose Arrays instead...
Of course Vector. is a nonsense, but I posted it anyway so You can figure You out the Vector Class.
Output is the same :
typeof(arr[0]) = STRING, value = a
typeof(arr[1]) = NUMBER, value = 1
typeof(arr[2]) = STRING, value = b
typeof(arr[3]) = NUMBER, value = 2
typeof(arr[4]) = STRING, value = c
typeof(arr[5]) = NUMBER, value = 3
typeof(vect[0]) = STRING, value = a
typeof(vect[1]) = NUMBER, value = 1
typeof(vect[2]) = STRING, value = b
typeof(vect[3]) = NUMBER, value = 2
typeof(vect[4]) = STRING, value = c
typeof(vect[5]) = NUMBER, value = 3
I forgot this easiest way if you really want an Array...
Quick done!
var ar1:Array = [1,2,3];
var ar2:Array = ["a","b","c"];
function merge(...arrays):Array {
var result:Array = [];
for(var i:int=0;i<arrays.length;i++){
result = result.concat(arrays[i]);
}
return result;
}
trace(merge(ar1, ar2));
// outputs : 1,2,3,a,b,c
Another possibility :
function populateObject(v1:Vector.<String>, v2:Vector.<uint>):Object{
var obj = new Object();
if ((v1.length*2) != (v1.length + v2.length)){
throw(new Error(" ***ERROR : the two Vectors or Arrays have not the same length!"));
}else{
for (var i:uint = 0; i < v1.length; i++){
obj[v2[i]] = v1[i];
}
}
return obj;
}
var o:Object = populateObject(v1,v2);
function listObject(someObj:Object):void{
var myObj:Object = someObj;
for (var i:String in someObj){
trace(someObj[i] + ": " + i);
}
}
listObject(o);
output =
a: 1
b: 2
c: 3
I think that You have a lot of possibilities to use here even it's my longer answer ;)
If You try those possibilities and understand them, this will certainty help You to think to find the best way to deal with Your issue.
But You may also copy and paste some shorter code.
I just wanted to show You that there's more than one answer.
If you understand this, You will be able to go further with coding.
Have fun ;)
Sincerely.
Nicolas
Best regards.
Nicolas.

Simplest way to prevent math.random form selecting the same number twice (AS3)

I have a random number variable defined as below
var rannum:Number = Math.floor(Math.random()*50+1);
Then I have a trigger that calls for a new random number everytime a button is clicked
ranbtn.addEventListener(MouseEvent.CLICK, reran);
function reran (event:MouseEvent):void
{
rannum = Math.floor(Math.random()*50+1);
}
I would like to prevent the same random number from being selected until all the numbers have been selected and then possibly start over?
I found a few threads like this one but none of them were specifically what I needed
You need to create an array of the possible values and each time you retrieve a random index from the array to use one of the values, you remove it from the array.Here you have an easy example with javascript.
var uniqueRandoms = [];
var numRandoms = 50;
function makeUniqueRandom() {
// refill the array if needed
if (!uniqueRandoms.length) {
for (var i = 0; i < numRandoms; i++) {
uniqueRandoms.push(i);
}
}
var index = Math.floor(Math.random() * uniqueRandoms.length);
var val = uniqueRandoms[index];
// now remove that value from the array
uniqueRandoms.splice(index, 1);
return val;
}
I've found another option, You can declare an array of Integers:[1,2,3,4...50] and sort them randomly.
var sorted:Array = [];
for(var i:int = 0; i < 50; i++){
sorted.push(i);
}
//I'm making a copy of sorted in unsorted
var unsorted:Array = sorted.slice();
//Randomly sort
while(sorted.join() == unsorted.join()){
unsorted.sort(function (a:int, b:int):int { return Math.random() > .5 ? -1 : 1; });
}
If you get a selected num, you can add one until it is not selected.
Create a list of integers from 1 to 50.
Pick a random integer from the list and remove it.
When there are no more integers left (after 50 picks), repeat step 1.
Code:
function createRangeOfIntegers(from:int, to:int):Vector.<int> {
if (from >= to) throw new ArgumentError("Invalid arguments");
var integers:Vector.<int> = new <int>[];
for (var i:int = from; i <= to; i++) {
integers.push(i);
}
return integers;
}
function getRandomInteger(integers:Vector.<int>):int {
var index:int = Math.random() * integers.length;
var integer:int = integers.splice(index, 1)[0];
return integer;
}
Example:
// create all the possible integers
var integers:Vector.<int> = createRangeOfIntegers(1, 50);
// select a random integer
var random:int = getRandomInteger(integers);
// When you've selected all integers you can start over
if (integers.length == 0)
integers = createRangeOfIntegers(1, 50);

As3 - Script Error on Arrays

please inspect me coding:
function createRandomList():void
{
var newlist:Array = [0,1,2];
var curlist:Array = item[selectedlevel - 1] //selectedlevel = 1;
var normal:int = curlist[0];
var tempboo1:Boolean = false;
var tempboo2:Boolean = false;
var tempboo3:Boolean = false;
while (curlist[0] + curlist[1] + curlist[2] > 0)
{
if (Number(curlist[0]) == 0 && tempboo1 == false)
{
newlist.splice(newlist.indexOf(0), 1);
tempboo1 = true;
}
if (Number(curlist[1]) == 0 && tempboo2 == false)
{
newlist.splice(newlist.indexOf(1), 1);
tempboo2 = true;
}
if (Number(curlist[2]) == 0 && tempboo3 == false)
{
newlist.splice(newlist.indexOf(2), 1);
tempboo3 = true;
}
var temp:int = Math.floor(Math.random()*(newlist.length));
curlist[temp] -= 1;
generatedlist.push(Number(newlist[temp]));
trace(item);
}
while (normal > 0)
{
var temp2:int = Math.floor(Math.random() * 3) + 1;
generatednormal.push(Number(temp2));
normal--;
}
}
My item was [[5,0,0],[10,0,0]];
But after became [[0,0,0],[0,0,0]];
I just want to duplicate Array item to be a new variable curlist.
Every time it traces, returning item[0][0] decreasing 1, I only want to use curlist as a temp Array to calculate a new random Array based on item[0].
Ouput:
4,0,0,10,0,0
3,0,0,10,0,0
2,0,0,10,0,0
1,0,0,10,0,0
0,0,0,10,0,0
Is there any links between them, or is it my problem? Please help! If you need any more infoemation, please comment me!
Arrays are passed by reference, not value. That means when you modify an array through any property that points to it, the original array will be modified.
To make a duplicate, you can use .slice()
Returns a new array that consists of a range of elements from the original array, without modifying the original array. The returned array includes the startIndex element and all elements up to, but not including, the endIndex element.
If you don't pass any parameters, the new array is a duplicate (shallow clone) of the original array.
You can clone your arrays if you want to create a new reference.
function clone( source:Object ):*
{
var myBA:ByteArray = new ByteArray();
myBA.writeObject( source );
myBA.position = 0;
return( myBA.readObject() );
}
var a:Array = [[0,0],[1,1]];
var b:Array = clone(a);
b[0] = [2,2];
trace(a)
trace(b)
Output
0,0,1,1
2,2,1,1
It works for any object, not only arrays.
More infos here : AS3 - Clone an object
var array : Array = [ 1, 2, 3];
var array2 : Array = array.concnt();
array[ 0 ] = 4;
trace( array );// 1, 2, 3
trace( array 2);// 4, 2 ,3
So use .concat() to duplicate an array with primitives. If you have an arrays with arrays. Duplicate the children arrays, and put them into an empty one. If you have children of children arrays and so forth, make something recursive.

passing random values from one array to another without repetitions

I have an array (say 'origA') which contains 20 values and also another array (say "itemA" with only 1 value in it. I need to push any 10 random values of "origA" into "itemA". But i cannot push a same value which is already pushed into "itemA".
How can we do this?
You can create a copy of origA and remove from it the items you add to itemA:
Non optimized version:
var origA:Array = [1, 2, 3, 4, 5, 6, 7];
var itemA:Array = [0];
var copyA:Array = origA.concat();
var N:int = 10;
var n:int = Math.min(N, copyA.length);
for (var i:int = 0; i < n; i++) {
// Get random value
var index:int = Math.floor(Math.random() * copyA.length);
var value:int = copyA[index];
// Remove the selected value from copyA
copyA.splice(index, 1);
// Add the selected value to itemA
itemA.push(value);
}
trace(itemA);
//0,1,7,2,6,4,3,5
Optimized version (no calls to length, indexOf, splice or push inside the loop):
var origA:Array = [1, 2, 3, 4, 5, 6, 7];
var itemA:Array = [0];
var copyA:Array = origA.concat();
var copyALength:int = copyA.length;
var itemALength:int = itemA.length;
var N:int = 10;
var n:int = Math.min(N, copyALength);
for (var i:int = 0; i < n; i++) {
// Get random value
var index:int = Math.floor(Math.random() * copyALength);
var value:int = copyA[index];
// Remove the selected value from copyA
copyA[index] = copyA[--copyALength];
// Add the selected value to itemA
itemA[itemALength++] = value;
}
trace(itemA);
//0,2,5,7,4,1,3,6
Edit1: If your original array has only a few items, use my first version or any other solution in the other answers. But if it may have thousands items or more, then I recommend you use my optimized version.
Edit:2 Here is the time taken to copy 1,000 randomly chosen items from an array containing 1,000,000 items:
All other versions: 2000ms
Optimized version: 12ms
Optimized version without cloning the original array: 1ms
// Define how many random numbers are required.
const REQUIRED:int = 10;
// Loop until either the original array runs out of numbers,
// or the destination array reaches the required length.
while(origA.length > 0 && itemA.length < REQUIRED)
{
// Decide on a random index and pull the value from there.
var i:int = Math.random() * origA.length;
var r:Number = origA[i];
// Add the value to the destination array if it does not exist yet.
if(itemA.indexOf(r) == -1)
{
itemA.push(r);
}
// Remove the value we looked at this iteration.
origA.splice(i, 1);
}
Here's a real short one. Remove random items from the original array until you reach MAX, then concat to the target Array:
const MAX:int = 10;
var orig:Array = [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20];
var target:Array = [];
var tmp:Array = [];
var i : int = -1;
var len : int = orig.length;
while (++i < MAX && len > 0) {
var index:int = int( Math.random()*len );
tmp[i] = orig[index];
orig[index] = orig[--len];
}
target = target.concat(tmp);
EDIT
Adopted #sch's way of removing items. It's his answer that should be accepted. I just kept this one for the while-loop.

Actionscript 3: Check an array for a match

If you have an array with six numbers, say:
public var check:Array = new Array[10,12,5,11,9,4];
or
public var check:Array = new Array[10,10,5,11,9,4];
How do you check for a match (of a pair?)
Array class has an indexOf method:
function indexOf(searchElement:*, fromIndex:int = 0):int
Searches for an item in an array by using strict equality (===) and returns the index position of the item.
Parameters
searchElement:* — The item to find in the array.
fromIndex:int (default = 0) — The location in the array from which to start searching for the item.
Returns
int — A zero-based index position of the item in the array. If the searchElement argument is not found, the return value is -1.
Got it (I think). Used the following:
public var match:Array = [10,12,5,10,9,4];
checkArray(match);
private function checkArray(check:Array) {
var i:int;
var j:int;
for (i= 0; i < check.length; i++) {
for (j= i+1; j < check.length; j++) {
if (check[i] === check[j]) {
trace(check[i] + " at " + i + " is a match with "+check[j] + " at " + j);
}
}
}
}