finding sequences in AS3 array - arrays

does anyone have any idea what to do in order to find the number of sequences in an array?
for example, my array is:
var numbers:Array = new Array(banana, banana, apple, banana, banana);
and i need to find is:
* how many times there is a sequence of "banana"
* and the length of each sequence.
what shell i do in order to get the following result:
2,1,2 (2 bananas, 1 apple, 2 bananas)
i tried with do while loop, but i i guess i miss something.
a short example will be very appreciated!
thanx

var prev:String = null;
var q:int = 0;
var result:Array = new Array();
for(var i:int=0; i<numbers.length; ++i){
if(prev!=numbers[i]){
if(q>0) result.push(q);
q=1;
prev=numbers[i];
}
else ++q;
}
if(q>0) result.push(q);
This is, assuming banana, etc. are strings (probably a typo above?). It would be simple to modify to other types of objects

Really all you want to know is whether the string at index n equals the string at index n+1...
var targetIndex:int = numbers.length - 1;
var results:Array = [1];
var resultsIndex:int = 0;
for(var n:int = 0; n < targetIndex; n++) {
if(numbers[n] == numbers[n+1]) {
results[resultsIndex]++;
} else {
results[++resultsIndex] = 1;
}
}
trace(results.join(','));

function sequencesInArray(array:Array):Array {
var sequence:Array = [];
var currSequenceCount:uint = 1;
for (var i:uint = 1; i < numbers.length; i++) {
if (numbers[i - 1] != numbers[i]) {
sequence.push(currSequenceCount);
currSequenceCount = 1;
} else {
currSequenceCount++;
}
}
return sequence;
}
Then:
var banana:int = 1;
var apple:int = 2;
sequencesInArray([banana, banana, apple, banana, banana]); //returns: [2, 1, 2]

In the question you don't define banana and apple, anyway I would use a map or a Dictionary to store key/value pairs, with the key being the string/object you want to count and the value being the counter of the object occurences in your array.
var objectsCounter:Dictionary = new Dictionary();
for (var key:String in numbers)
{
if ( objectsCounter[key] )
objectsCounter[key] = objectsCounter[key] + 1;
else
objectsCounter[key] = 1;
}
This way you can store any type in the dictionary.
edit:
for (var key:String in objectsCounter)
{
// iterates through each object key
}
for each (var value:Number in objectsCounter)
{
// iterates through each value
}

I believe this is what you're looking for:
var array:Array = [
"banana", "banana",
"apple",
"banana", "banana", "banana"
];
var sequences:Array = findSequences(array, "banana");
trace("sequences:", sequences); // prints "sequences: 2,3"
And:
private function findSequences(array:Array, searchElement:*):Array
{
var sequences:Array = [];
var currentSequence:int = 0;
for each (var element:* in array) {
if (element == searchElement) {
currentSequence++;
} else if (currentSequence > 0) {
sequences.push(currentSequence);
currentSequence = 0;
}
}
if (currentSequence > 0) {
sequences.push(currentSequence);
}
return sequences;
}

Related

Why array comparison isn't working? (GAS)

The code below used to work. Now, when comparing two arrays, even though there is a difference, as highlighted below, the code says that there is a duplicate.
I've tried it using .join() as well, but I keep getting the same result.
Script:
function SaveEditedEntry() {
const lock = LockService.getScriptLock();
lock.tryLock(3000);
if (lock.hasLock()) {
var sourceSheet = 'Entries';
var destinationSheet = 'Database';
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName(sourceSheet);
var LastRowSource = sheet.getLastRow();
//var LastColumnSource = sheet.getLastColumn();
var entryValues = sheet.getRange(7, 1, LastRowSource, 16).getValues();
var dbSheet = ss.getSheetByName(destinationSheet);
var entryDataPushed = [];
var dbData = dbSheet.getRange(2, 1, dbSheet.getLastRow(), 16).getValues();
var dbDataPushed = [];
//var dbDataPushed = new Array();
var company = sheet.getRange("B3").getValue();
var period = sheet.getRange("B4").getValue();
var entryID = sheet.getRange("J5").getValue();
var timeStamp = new Date();
var user = Session.getActiveUser().getEmail();
if (company == '') {
Browser.msgBox('Make sure that you have chosen a valid company.');
return;
}
if (period == '') {
Browser.msgBox('Please, make sure that you have chosen a valid period.');
return;
}
var emptyRow = 0;
for (var i = 0; i < entryValues.length; i++) {
if (entryValues[i][0] != '') {
emptyRow = i + 1;
}
if (emptyRow < 1) {
Browser.msgBox('Please, make sure that you have entered a transaction.');
return;
}
if (entryValues[i][0] != '') {
entryDataPushed.push(entryValues[i]);
}
}
for (var n = 0; n < dbData.length; n++) {
if (dbData[n][1] != '' && dbData[n][0] == company && dbData[n][14] == period) {
dbDataPushed.push(dbData[n]);
}
}
var duplicate = false;
loop1:
for (var x = 0; x < entryValues.length; x++) {
loop2:
for (var j = 0; j < dbDataPushed.length; j++) {
if (JSON.stringify(entryValues[x]) == JSON.stringify(dbDataPushed[j])) {
duplicate = true;
break loop1;
}
}
}
Logger.log("EntryDataPushed: " + entryDataPushed);
Logger.log("dbDataPushed: " + dbDataPushed);
if (duplicate == true) {
Browser.msgBox('No change has been made.');
return;
This is the logs print:
Could anyone point me to the right direction on getting this solved?
Thank you!
Antonio
You were comparing entryValues vs dbDataPushed but is logging entryDataPushed and dbDataPushed. Is this expected?
Anyways, since you are logging the variables, I assume the variables logged are the ones you need to compare.
Convert them into JSON string by wrapping the variables with JSON.stringify(). I use this all the time when I encounter an issue similar to yours right now.
var duplicate = false;
if (JSON.stringify(entryDataPushed) == JSON.stringify(dbDataPushed)) {
duplicate = true;
}
Output:
See resource below for other ways to properly compare arrays if the above code doesn't work.
Resources:
JSON.stringify()
StackOverflow Reference

Is their a way to find the closest number to 0 in an Array?

I've got an array like that
var tideArray = new Array();
tideArray.push({tide:"haute1", difference: "-14"});
tideArray.push({tide:"haute2", difference: "-3"});
tideArray.push({tide:"basse1", difference: "-9"});
tideArray.push({tide:"basse2", difference: "4"});
tideArray.sortOn("difference", Array.NUMERIC);
trace(tideArray[0].tide);
For now, it's choosing the minimum number (-14) but I'd like to choose the closest number to 0.
Is there a way to do that ?
EDIT
I've tried that :
trace(closestToZero(tideArray));
function closestToZero(a:Array):int
{
var curDelta:int = Math.abs(0 - a[0].difference);
var curIndex:int = 0;
for(var i:int = 1; i < a.length; i++){
var thisDelta:int = Math.abs(0 - a[i].difference);
if(thisDelta < curDelta){
curIndex = i;
}
}
return curIndex;
}
But it seems that there is a mistake somewhere because the trace result is 3 (so it means that it's telling me that "basse2" (4) is the closest to 0... But, as you can see, it's "haute2" (-3) the closest).
I think it would be more efficient to simply loop over the array to find the item with the (absolute) minimum difference value:
if (tideArray.length > 0)
{
var minItem: Object = tideArray[0];
for (var index:int = 1; index < tideArray.length; index++)
{
if (Math.abs(tideArray[index].difference) < Math.abs(minItem.difference))
{
minItem = tideArray[index];
}
}
trace(minItem.tide);
}
Something like this
var tideArray = new Array();
...
function sortMyArray(a,b):int {
if (Math.abs(a) < Math.abs(b)) {
return -1;
}
if (Math.abs(a) > Math.abs(b)) {
return 1;
}
return 0;
}
tideArray.sort(sortMyArray);
Edit :
For your array.
function sortMyArray(a,b):int {
if (Math.abs(a.difference) < Math.abs(b.difference)) {
return -1;
}
if (Math.abs(a.difference) > Math.abs(b.difference)) {
return 1;
}
return 0;
}

Combine multy arrays side by side google script

I have this code on Google script for get arrays from Sheet1 by criteria in Sheet2 at Sheet3. But now arrays placed only one under the other. What I need is place every new array from 'v' in next 5 columns like in example on my spreadsheet.
Secondly - before this, I used filter with search formula, that allow me use wildcards like * or ?. How I can use wildcards or regexp in my new function?
I would be grateful for any help.
function getval(){
var ss = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Sheet1");
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Sheet2");
var sspodbor = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Sheet3");
var range = ss.getRange("A2:A29");
var values = range.getValues();
var rangez = sheet.getRange("A1:A14");
var valuesz = rangez.getValues();
var z = []
for (var x = 0; x<valuesz.length; x++){
z.push(valuesz[x])
}
var v = [];
for (var q = 0; q < valuesz.length; q++){
for (var s = 0; s < values.length; s++){
if(values[s][5] == z[q]){
v.push([values[s][0],values[s][1],values[s][2],values[s][3],values[s][4]]);
}
//I am guessing that here must be a separating function
}
}
var range = sspodbor.getRange(4, 1, v.length,v[0].length);
range.setValues(v);
}
My spreadsheet: https://docs.google.com/spreadsheets/d/1o7ErbeFHA7yyxMC0HMn3Uj5ZBRcy2uAwa1UpolVpBFI/edit?usp=sharing
Spreading the Groups out Horizontally
It's not the prettiest solution you'll ever see and hopefully others will look it over and make improvements but here it is.
function getval()
{
var Sheet1 = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Sheet1");
var Sheet2 = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Sheet2");
var output = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("output");
var knew = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('knew');
var knewrange = knew.getRange(1,1,10,100);
var pipe = '';
var range1 = Sheet1.getRange("A2:F29");
var values1 = range1.getValues();
var range2 = Sheet2.getRange("A1:A14");
var values2 = range2.getValues();
var z = [];
for (var x = 0; x<values2.length; x++)
{
z.push(values2[x])
}
var v = [];
for (var q = 0; q < values2.length; q++)
{
for (var s = 0; s < values1.length; s++)
{
if(values1[s][5] == z[q])
{
v.push([values1[s][0],values1[s][1],values1[s][2],values1[s][3],values1[s][4],q]);
}
}
}
var vlength=v.length;
var range3 = output.getRange(1, 1, v.length,6);
range3.setValues(v);
var w = [];
var voff = 0;
var hoff = 0;
for(var m=0;m<10;m++)
{
w[m]=[];
for(var n=0;n<100;n++)
{
w[m][n]='' ;
}
}
var color = ['yellow','orange'];
for(var i=0;i<v.length;i++)
{
for(var j=0;j<5;j++)
{
if(i-voff==0){knew.getRange((i-voff + 1),(j + hoff + 1),4,5).setBackground(color[v[i][5] % 2])};
if((i-voff)==0 || v[i][5] == v[i-1][5])
{
w[i - voff][j + hoff]=v[i][j];
}
else
{
voff = i;
hoff += 5;
w[i - voff][j + hoff]=v[i][j];
}
}
}
knewrange.setValues(w);
}
I copied the data from your spreadsheet and the the original getval function. I ended up changing some of the names so I could figure out where to find the data easier. It was a difficult problem for me and one that i enjoyed.
Thanks

Search an array for a string and return the index in AS3

I want to search an array to see if it contains a specific string, and then get the index of the result.
For example, if I had:
array[0] = "dogs";
array[1] = "cats";
array[2] = "oranges";
I want to be able to search for "oran" and get 2 back. Any idea on how to do this?
You can do something like this:
function findInArray(str:String):int {
for(var i:int = 0; i < array.length; i++){
if(array[i] == str){
trace("found it at index: " + i);
return i;
}
}
return -1; //If not found
}
Then whenever you want to find something call it like:
findInArray("oranges"); // Returns 2
To search for a part of the word can pontentially return undesiderd results for bigger lists, but you can do it with the following:
function findInArrayPartially(str:String):int {
for(var i:int = 0; i < array.length; i++){
if(array[i].indexOf(str) > -1){
trace("found it at index: " + i);
return i;
}
}
return -1; //If not found
}
Another way to do it:
var arr:Array = ["dogs", "cats", "oranges", "apples"];
function indexOfSubstring(array:Array, stringToFind:String):int
{
var answer:int = array.indexOf(stringToFind);
if (answer == -1)
{
var separator:String = "|";
var arrayToString:String = array.join(separator);
var indexInString:int = arrayToString.indexOf(stringToFind);
if (indexInString != -1)
{
var shorterStr:String = arrayToString.substring(0, indexInString);
answer = shorterStr.split(separator).length - 1;
}
}
return answer;
}
trace(indexOfSubstring(arr, "oran")); // returns 2
trace(indexOfSubstring(arr, "les")); // returns 3
trace(indexOfSubstring(arr, "ts")); // returns 1
trace(indexOfSubstring(arr, "broom")); // returns -1

Sorting an array to avoid neighboring items having duplicate attributes

I have an array of objects. Each object has a color attribute which could be "red", "blue", "yellow", "green", "orange" or "purple". There are 20-30 objects in the array so colors repeat. My goal is to sort the array so that no colors are next to each other. Distribution of colors is not exactly even but close.
This is what I have so far. It checks the next and previous object for a color match and if it finds a match it moves it to the end of the array.
private function sortColors():void
{
var getNext:uint;
var getPrev:uint;
var maxCount:uint = colorArray.length;
for (var i:uint = 0; i < maxCount; i++) {
var cur:ValueObject = colorArray[i];
(i == maxCount-1) ? getNext = 0 : getNext = i+1;
(i == 0) ? getPrev = maxCount-1 : getPrev = i-1;
var next:ValueObject = colorArray[getNext];
var prev:ValueObject = colorArray[getPrev];
if (cur.color == next.color) {
var move:ValueObject = colorArray[getNext];
colorArray.splice(getNext, 1);
colorArray.push(move);
}
if (cur.color == prev.color) {
var move:ValueObject = colorArray[getPrev];
colorArray.splice(getPrev, 1);
colorArray.push(move);
}
}
}
This works OK but if there is more of a certain color they end up repeating at the end. I could add something to the end to throw those back into the mix but I feel like there must be a better way. Someone enlighten me.
Try:
var colorObjects:Array = [/* list of objects with colors - populated below*/];
var jumbled:Array = [];
var lastColor:String = "";
function getDifferentTile():void
{
if(lastColor.length == 0)
{
jumbled.push(colorObjects.pop());
lastColor = jumbled[0].mycolor;
}
else
{
var i:Object;
for each(i in colorObjects)
{
var repeat:uint = 0;
if(i.mycolor != lastColor)
{
jumbled.push(i);
lastColor = i.mycolor;
colorObjects.splice(colorObjects.indexOf(i), 1);
return;
} else {
repeat++;
}
if (repeat > 0 && repeat == colorObjects.length) {
jumbled.push(i);
colorObjects.splice(colorObjects.indexOf(i), 1);
return;
}
}
}
}
// list of random colors
var colors:Array = ["0x000000","0x444444","0xFFFFFF","0xFF00FF"];
// prepare random array for test
var i:uint = 0;
for(i; i<100; i++)
{
var obj:Object =
{
mycolor: colors[uint(Math.random()*colors.length)]
};
colorObjects.push(obj);
}
// fill the jumble array until the original listing is empty
while(colorObjects.length > 0)
{
getDifferentTile();
}
// output jumbled
var j:Object;
for each(j in jumbled)
{
trace(j.mycolor);
}

Resources