appendRow from an array - arrays

If I have an array, [Joe, John, Adam, Sam, Bill, Bob] and I want to try to add this to a new row by doing SpreadsheetApp.getActive().getSheetByName('Sheet4').appendRow([array]); , what happens is that the entire list of names goes into 1 cell. Is there a way to break this up so they file away into the same row, but different columns? I need to continue using appendRow however.
I get this:
But I really want to have it look like this:
var my2DArrayFromRng = datasheet.getRange("A:A").getValues();
var a = my2DArrayFromRng.join().split(',').filter(Boolean);
var array = [];
for (d in a) {
array.push(a[d]);
}
SpreadsheetApp.getActive().getSheetByName('Sheet4').appendRow([array.toString()]);

You are converting your array to a string before you post it which is causing your issue.
Do not use the array.toString() method inside append row. Instead just append the array as it is.
SpreadsheetApp.getActive().getSheetByName('Sheet4').appendRow(array);

Related

AppScript: 'number of columns in the data does not match the number of columns in the range.' setValues method not reading array correctly?

I'm trying to automate the collection of phone numbers from an API into a Google Sheet with app script. I can get the data and place it in an array with the following code:
const options = {
method: 'GET',
headers: {
Authorization: 'Bearer XXXXXXXXXXXXXXX',
Accept: 'Application/JSON',
}
};
var serviceUrl = "dummyurl.com/?params";
var data=UrlFetchApp.fetch(serviceUrl, options);
if(data.getResponseCode() == 200) {
var response = JSON.parse(data.getContentText());
if (response !== null){
var keys = Object.keys(response.call).length;
var phoneArray = [];
for(i = 0; i < keys; i++) {
phoneArray.push(response.call[i].caller.caller_id);
}
This works as expected - it grabs yesterday's caller ID values from a particular marketing campaign from my API. Next, I want to import this data into a column in my spreadsheet. To do this, I use the setValues method like so:
Logger.log(phoneArray);
var arrayWrapper = [];
arrayWrapper.push(phoneArray);
Logger.log(arrayWrapper);
for(i = 0; i < keys; i++) {
var sheet = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
var cell = sheet.getRange("A8");
cell.setValues(arrayWrapper);
}
}
}
}
I am aware that I need my array length to equal the length of the selected range of cells in my sheet. However, I get conflicting errors depending on the length I set for my getRange method. If I set it to a single cell, as you see above, the error I get is:
The number of columns in the data does not match the number of columns in the range. The data has 8 but the range has 1.
However, if I set the length of my range to 8 (or any value except 1), I get the error:
The number of columns in the data does not match the number of columns in the range. The data has 1 but the range has 8.
As you see, the error swaps values. Now I have the appropriate number of columns in the range, but my script only finds 1 cell of data. When I check the log, I see that my 2D array looks normal in both cases - 8 phone numbers in an array wrapped in another array.
What is causing this error? I cannot find reference to similar errors on SO or elsewhere.
Also, please note that I'm aware this code is a little wonky (weird variables and two for loops where one would do). I've been troubleshooting this for a couple hours and was originally using setValue instead of setValues. While trying to debug it, things got split up and moved around a lot.
The dimension of your range is one row and several columns
If you push an array into another array, the dimension will be [[...],[...],[...]] - i.e. you have one column and multiple rows
What you want instead is one row and multiple columns: [[...,...,...]]
To achieve this you need to create a two-dimensional array and push all entries into the first row of your array: phoneArray[0]=[]; phoneArray[0].push(...);
Sample:
var phoneArray = [];
phoneArray[0]=[];
for(i = 0; i < keys; i++) {
var phoneNumber = response.call[i].caller.caller_id;
phoneNumber = phoneNumber.replace(/-/g,'');
phoneArray[0].push(phoneNumber);
}
var range = sheet.getRange(1,8,1, keys);
range.setValues(phoneArray);
So I figured out how to make this work, though I can't speak to why the error is occurring, or rather why one receives reversed error messages depending on the setRange value.
Rather than pushing the whole list of values from the API to phoneArray, I structured my first for loop to reset the value of phoneArray each loop and push a single value array to my arrayWrapper, like so:
for(i = 0; i < keys; i++) {
var phoneArray = [];
var phoneNumber = response.call[i].caller.caller_id;
phoneNumber = phoneNumber.replace(/-/g,'');
phoneArray.push(phoneNumber);
arrayWrapper.push(phoneArray);
}
Note that I also edited the formatting of the phone numbers to suit my needs, so I pulled each value into a variable to make replacing a character simple. What this new for loop results in is a 2D array like so:
[[1235556789],[0987776543],[0009872345]]
Rather than what I had before, which was like this:
[[1235556789,0987776543,0009872345]]
It would appear that this is how the setValues method wants its data structured, although the documentation suggests otherwise.
Regardless, if anyone were to run into similar issues, this is the gist of what must be done to fix it, or at least the method I found worked. I'm sure there are far more performant and elegant solutions than mine, but I will be dealing with dozens of rows of data, not thousands or millions. Performance isn't a big concern for me.
var correct = [[data],[data]] -
is the data structure that is required for setValues()
therefore
?.setValues(correct)

Accessing element of an perl Array element

I have a perl code which read csv file. It contains grid data which needs to be updated at the front end.
First, here is the perl code which reads data and formats it so that the data can be pushed to front end for display.
my #array;
for my $column ($csv->column_headers) {
my $json = encode_json([ map { $_->{$column} } #$data ]);
push(#array, "$json;");
}
The final data is the #array which is passed to front end javascript code. The contents of #array is as follows.
["1","2"]; ["dd","ddd"]; ["wow","cool"]; ["HOLD","HOLD"];
This data is actually 4 columns with column header names as Id, Name, Comment and type. All these data are bundled up together in #array and passed to Javascript.
var header=[];
header[0] = #array[0];
}
This code above displays the below output if I do a console.log(header[0]); It means it is displaying the first element of the array. but I want to display the first element's element.
["1", "2"]
whereas it should display below output.
["1"]
In short, I want to know how can I access array elements elements. I tried using below code but it didn't work. Can someone please suggest?
var header=[];
header[0] = #array[0][0];
I am ultimately trying to put this data in grid by using below code.
for (var i=0;i<row_cnt;i++){
var row={};
row["Id"]=Id[i];
row["Name"]=Name[i];
row["Comment"]=Comment[i];
row["type"]= type[i];
data[i]=row;
}
where Id[i] will corresponding to "1" in first loop and "2" in second loop. Similarly it will generate data for other columns. These are then assigned to rows and updated in grid.
As per matts suggestion, I edited the code like this
my $json = encode_json($data);
for my $column ($csv->column_names) {
push(#data_array, "var $column= $json;");
}
Now it displays below values at every cell of the grid.
[object Object]
Building on the answer to your previous question, I think you just need to swap out the loop at the end for this:
my $json = encode_json($data);
print "var data = $json;\n";

actionscript 3: how to access to elements of an array created in a loop dynamically

In the library of the .fla file I have a square exported as Class "cuad" on frame 1
I want to create an Array with 100 squares so as to move them later
So I do like this:
for (var i:uint = 0; i<100;i++)
{
var cuad_mc = new cuad();
addChild(cuad_mc);
myArray.push("cuad_mc");
trace(myArray[i]);
}
I have a runtime error
The error you experience is
Error #1069: Did not find alpha propiety in the String and there is not any value predetermined
The problem comes from your line
myArray.push("cuad_mc");
What you are doing here is pushing a String Object into your Array, not the cuad Object you want. String Objects don't have Alpha values, or x values.
What you want to do is
myArray.push(cuad_mc);
cuad_mc (without the " quotation marks) is a reference to the object you just created.
This should solve your problem. I also recommend using Vectors instead of Array if you only need to store one type of Object. Like this:
var myArray:Vector<cuad> = new Vector<cuad>();
for(var i:int=0;i<100;i++){
var cuad_mc:cuad = new cuad();
addChild(cuad_mc);
myArray.push(cuad_mc);
trace(myArray[i]);
}
Vectors are just like Arrays, but they only allow one specific type, so that a situation like yours doesn't occur.

Sorted array: how to get position before and after using name? as3

I have been working on a project and Stack Overflow has helped me with a few problems so far, so I am very thankful!
My question is this:
I have an array like this:
var records:Object = {};
var arr:Array = [
records["nh"] = { medinc:66303, statename:"New Hampshire"},
records["ct"] = { medinc:65958, statename:"Connecticut"},
records["nj"] = { medinc:65173, statename:"New Jersey"},
records["md"] = { medinc:64596, statename:"Maryland"},
etc... for all 50 states. And then I have the array sorted reverse numerically (descending) like this:
arr.sortOn("medinc", Array.NUMERIC);
arr.reverse();
Can I call the name of the record (i.e. "nj" for new jersey) and then get the value from the numeric position above and below the record in the array?
Basically, medinc is medium income of US states, and I am trying to show a ranking system... a user would click Texas for example, and it would show the medinc value for Texas, along with the state the ranks one position below and the state that ranks one position above in the array.
Thanks for your help!
If you know the object, you can use the array.indexOf().
var index:int = records.indexOf(records["nj"]);
var above:Object;
var below:Object;
if(index + 1 < records.length){ //make sure your not already at the top
above = records[index+1];
}
if(index > 0){ //make sure your not already at the bottom
below = records[index-1];
}
I think this is the answer based on my understanding of your data.
var index:int = arr.indexOf(records["nh"]);
That will get you the index of the record that was clicked on and then for find the ones below and above just:
var clickedRecord:Object = arr[index]
var higherRecord:Object = arr[index++]
var lowerRecord:Object = arr[index--]
Hope that answers your question
Do you really need records to be hash?
If no, you can simply move key to record field and change records to simple array:
var records: Array = new Array();
records.push({ short: "nh", medinc:66303, statename:"New Hampshire"}),
records.push({ short: "ct", medinc:65958, statename:"Connecticut"}),
....
This gives you opportunity to create class for State, change Array to Vector and make all of this type-safe, what is always good.
If you really need those keys, you can add objects like above (with "short" field) in the same way you are doing it now (maybe using some helper function which will help to avoid typing shortname twice, like addState(records, data) { records[data.short] = data }).
Finally, you can also keep those records in two objects (or an object and an array or whatever you need). This will not be expensive, if you will create state object once and keep references in array/object/vector. It would be nice idea if you need states sorted on different keys often.
This is not really a good way to have your data set up - too much typing (you are repeating "records", "medinc", "statename" over and over again, while you definitely could've avoided it, for example:
var records:Array = [];
var states:Array = ["nh", "ct", "nj" ... ];
var statenames:Array = ["New Hampshire", "Connecticut", "New Jersey" ... ];
var medincs:Array = [66303, 65958, 65173 ... ];
var hash:Object = { };
function addState(state:String, medinc:int, statename:String, hash:Object):Object
{
return hash[state] = { medinc: medinc, statename: statename };
}
for (var i:int; i < 50; i++)
{
records[i] = addState(states[i], medincs[i], statenames[i], hash);
}
While you have done it already the way you did, that's not essential, but this could've saved you some keystrokes, if you haven't...
Now, onto your search problem - first of all, true, it would be worth to sort the array before you search, but if you need to search an array by the value of the parameter it was sorted on, there is a better algorithm for that. That is, if given the data in your example, your specific task was to find out in what state the income is 65958, then, knowing that array is sorted on income you could employ binary search.
Now, for the example with 50 states the difference will not be noticeable, unless you do it some hundreds of thousands times per second, but in general, the binary search would be the way to go.
If the article in Wiki looks too long to read ;) the idea behind the binary search is that at first you guess that the searched value is exactly in the middle of the array - you try that assumption and if you guessed correct, return the index you just found, else - you select the interval containing the searched value (either one half of the array remaining) and do so until you either find the value, or check the same index - which would mean that the value is not found). This reduces asymptotic complexity of the algorithm from O(n) to O(log n).
Now, if your goal was to find the correspondence between the income and the state, but it wasn't important how that scales with other states (i.e. the index in the array is not important), you could have another hash table, where the income would be the key, and the state information object would be the value, using my example above:
function addState(state:String, medinc:int, statename:String,
hash:Object, incomeHash:Object):Object
{
return incomeHash[medinc] =
hash[state] = { medinc: medinc, statename: statename };
}
Then incomeHash[medinc] would give you the state by income in O(1) time.

ActionScript: How to push to multidimensional arrays and later retrieve just one 'row'

I am reading a set of latitude & Longitude Coordinates that define a polygone area. They are keyed to an area ID and I retrieve them from a SQL database. So for example, Area ID 153 might have 20 coordinates and area ID 77 might have 11 coordinates. I wish to save these in a 2-D array indexed by the area ID, and where each coordinate pair is combined into one Google LatLng object. At a later point I wish to retrieve just one row i.e. the set of coordinates for one area, and send them to a function that accepts an array of coordinates and draws the polygon on a map. Here's what I have:
private var coordsFromSql:ArrayCollection = new ArrayCollection();
var polyArray:Array = new Array();
for each(var item:COORDINATES in coordsFromSql)
{
// add coordinates to the array for each Area id
polyArray[item.AREA_ID].push( new LatLng(item.LATITUDE, item.LONGITUDE) );
}
So this is where the first problem ocurrs. I don't know how to add a variable number of new items to a 2-D array into a known index. i.e considering polyArray like a 2-D spreadsheet how do I for example add values to 'row' 77 i.e. polyArray[77] ?
If I run the above code, I get runtime error #1010 'A term is undefined and has no properties'
The second part of the question is how do you extract one 'row' as a new array?
Using the above example to call a drawPolygon function, can I do this?
var polyArraySlice:Array = polyArray[77].slice();
drawPolygon(color, polyArraySlice );
It looks like your loading code is close, but not quite. In your for loop you're doing:
polyArray[item.AREA_ID].push(/*...*/)
but you never actually put anything in the array there.
So your load would probably be something like this:
var polyArray:Array = []
for each(var item:COORDINATES in coordsFromSql)
{
// add coordinates to the array for each Area id
var id:Number = item.AREA_ID;
if(polyArray[id] == null) { polyArray[id] = [] }
polyArray[id].push( new LatLng(item.LATITUDE, item.LONGITUDE) );
}
Getting a copy of the one of the individual locations would work just like you had:
var polyArraySlice:Array = polyArray[77].slice();
drawPolygon(color, polyArraySlice );

Resources