Issues with array[i].match and array[i].substring - javascript

I wanna use array[i].match and array[i].substring but this presents a problem to me.
If I wanna output this matches I get a blank page.
JavaScript
var List = ["example1", "example2", "example3", "example21", "example12"];
var array = [];
for (var i = 0; i < List.length; i++) {
Entry = List[i];
var counts = Entry.match(/1/g).length;
//var n = Entry.search("example1");
if (counts >= 1) {
array.push(Entry);
}
}
for (var i = 0; i < array.length; i++) {
var Eintrag = document.createElement("div");
Eintrag.style.background = "DodgerBlue";
Eintrag.style.width = "50px";
Eintrag.style.height = "10px";
Eintrag.style.marginLeft = "1%";
Eintrag.style.marginRight = "1%";
Eintrag.style.border = "thin solid red";
CallOutputBox.appendChild(Eintrag);
}
With array[i].search it works fine.

It's not working because you're assuming there will be an array. If there's no match, there's no array. So you need to check to see if counts exists and then check the length.
DOCS
An Array containing the entire match result and any parentheses-captured matched results; null if there were no matches.
DEMO
var counts = Entry.match(/1/g);
if (counts && counts.length >= 1) {
// do stuff
}

Related

Randomize Unique Named Groups of Arrays with no Repetition of Elements per Grouping

I have 149 groups composed of individuals from a list of ~250. The grouping (tribe) composition is fixed, meaning the 3 members of each group cannot be switched. I need to create a schedule (6 days total) that will distribute the 149 groups into 25 groups per day, except the last day, with the condition that no single individual should have more than 1 occurrence per day.
Here is a copy of my dataset with dummy names.
Here is my Google Apps Script code so far:
var ui = SpreadsheetApp.getUi();
var sht = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Tribes');
var schedSht = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Schedule');
var nameSht = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Names');
var tribesArr = sht.getRange(2, 1, sht.getLastRow() - 1, 1).getValues();
var tribesOrder = tribesArr.map(function(t) { return t[0] });
tribesArr = tribesArr.map(function(t) { return t[0] });
var tribes = randomize(tribesArr);
var takenTribes = [];
var tribeSet = [];
var nameSet = [];
var LastDayTribeNum = 24;
var otherDaysTribeNum = 25;
var numDays = 6;
function makeMenu() {
ui.createMenu('My Menu').addItem('Create Randomized Schedule', 'makeSchedule').addToUi();
}
function makeSchedule() {
var dayNum = 1;
while (dayNum < numDays + 1) {
var remainingTribes = tribes.filter(function(r) { return takenTribes.indexOf(r) < 0; });
var daySched = fillUpDay(dayNum, remainingTribes);
tribeSet.push(daySched.tribes);
nameSet.push(daySched.names);
dayNum++;
}
remainingTribes = tribes.filter(function(r) { return takenTribes.indexOf(r) < 0; });
if (takenTribes.length < tribes.length) {
remainingTribes.forEach(swap);
}
tribeSet.forEach(function(tribe) {
schedSht.appendRow(tribe);
});
nameSet.forEach(function(name) {
nameSht.appendRow(name);
});
}
function fillUpDay(revDay, remTribes) {
var sched = {};
var namesToday = [];
var tribesToday = [];
var currIdx = 0;
var tribeMaxNum = (revDay === numDays) ? LastDayTribeNum : otherDaysTribeNum;
while (tribesToday.length < tribeMaxNum && currIdx < remTribes.length) {
var row = tribesOrder.indexOf(remTribes[currIdx]) + 2;
var currNames = sht.getRange(row, 2, 1, 3).getValues()[0];
var nameFound = false;
//check if name of tribe already in today's list
for (var t = 0; t < 3; t++) {
if (namesToday.indexOf(currNames[t]) !== -1) {
nameFound = true;
}
}
if (!nameFound) {
//if names of all three not in the list, add all three to today's list and remove tribe from list of unscheduled tribes
namesToday = namesToday.concat(currNames);
tribesToday.push(remTribes[currIdx]);
takenTribes.push(remTribes[currIdx]);
currIdx++;
} else {
//go to next tribe
currIdx++;
}
}
sched.tribes = tribesToday;
sched.names = namesToday;
return sched;
}
function swap(tribeToSwap) {
var row = tribesOrder.indexOf(tribeToSwap) + 2;
var namesInTribe = sht.getRange(row, 2, 1, 3).getValues()[0];
var len = nameSet.length;
var idx = 0;
var found = checkInSet(namesInTribe, nameSet[idx]);
var swapped = false;
while (!swapped && idx < len - 1) {
if (!found) {
// try swap
var tempNameArr = nameSet[idx];
tempNameArr.slice(3);
tempNameArr.push(namesInTribe);
var removedNames = nameSet[idx];
removedNames.slice(0, 3);
var lastNames = nameSet[len - 1];
var good = true;
for (var c = 0; c < 3; c++) {
if (lastNames.indexOf(removedNames[c]) > -1) {
good = false;
}
}
if (good) {
// swap
tribeSet[idx].slice(1);
nameSet[idx] = tempNameArr;
tribeSet[len - 1].push(tribeToSwap);
nameSet[len - 1].push(removedNames);
swapped = true;
}
} else {
// try next day
idx++;
found = checkInSet(namesInTribe, nameSet[idx]);
}
}
}
function checkInSet(names, setNames) {
var found = false;
for (var idx = 0; idx < names.length; idx++) {
if (setNames.indexOf(names[idx]) > -1) {
found = true;
}
}
return found;
}
function randomize(array) {
//https://stackoverflow.com/questions/2450954/how-to-randomize-shuffle-a-javascript-array
var currentIndex = array.length,
temporaryValue, randomIndex;
while (0 !== currentIndex) {
randomIndex = Math.floor(Math.random() * currentIndex);
currentIndex -= 1;
temporaryValue = array[currentIndex];
array[currentIndex] = array[randomIndex];
array[randomIndex] = temporaryValue;
}
return array;
}
What I did was to create an array per day and check if a member of the current index's corresponding group (tribe) exists in the day's names array, and move on to the next index if found until the quota for the day (25) is reached. If names are not found for the day, the tribe will be marked as taken and will no longer be included in the subsequent schedules. Results will be appended to their respective sheets. If there are tribes that weren't matched because a name already appears for that day, I try to swap it in another day.
The code runs most of the time (gets completed in ~5s). Some other times, it runs for minutes that I cancel it. BUT, I never get what I need in any run. I will get 149 tribes in the Schedule sheet, but when I check the names, I don't get 447 names (with no repetition per day). I can't pinpoint where to adjust the algorithm. I hope someone can at least give hints, and better, a solution. Pardon the messy code.
I found out that the errors come from the swap() function. I revised the entire function this way:
function swap(tribeToSwap) {
var row = tribesOrder.indexOf(tribeToSwap) + 2;
var namesInTribe = sht.getRange(row, 2, 1, 3).getValues()[0];
var len = nameSet.length - 1;
var tempNames = [];
for (var days = 0; days < nameSet.length; days++) {
var currNameSet = nameSet[days];
tempNames[days] = currNameSet.concat(namesInTribe);
}
var noDupIdx = [];
tempNames.forEach(function (n) {
if (!checkDuplicate(n)) { noDupIdx.push(tempNames.indexOf(n)) };
});
var swapped = false;
for (var idx = 0; idx < noDupIdx.length; idx++) {
var currDay = noDupIdx[idx];
var allOrigNames = [nameSet[currDay], nameSet[len]];
var removedNames = allOrigNames[0].slice(0,3); //remove first 3 names
var newSoonNames = tempNames[currDay].slice(3); //add the names in swapping tribe
var newLateNames = allOrigNames[1].concat(removedNames);
if (!checkDuplicate(newLateNames)) {
nameSet[currDay] = newSoonNames;
nameSet[len] = newLateNames;
var swappedTribe = tribeSet[currDay][0];
tribeSet[currDay].slice(1).concat(tribeToSwap);
tribeSet[len] = tribeSet[len].concat(swappedTribe);
swapped = true;
break;
}
}
success.push(swapped);
}
I added a success array so that when the swap fails (as I've come to expect that is sometimes will), I will just get a UI alert about it.
I removed the checkInSet() function and replaced it with a checkDuplicate() function.
function checkDuplicate(arr) {
var map = {};
var duplicates = false;
for (var i = 0; i < arr.length; i++) {
if (map[arr[i]]) {
duplicates = true;
break;
}
map[arr[i]] = true;
}
return duplicates;
}
Good enough for now. Doesn't run forever anymore.

Setting multiple items in array to disabled with JavaScript

The current process of setting multiple inputs to disabled works for me, but seems to be way too much code due to the multiple for loops:
var textEditors = document.getElementsByClassName('textEditor'),
textareas = document.getElementsByTagName('textarea'),
radioInputs = document.getElementsByClassName('radioSelect'),
textInputs = document.getElementsByTagName('input');
for (var i = 0; i < textEditors.length; i++) {
textEditors[i].disabled = true;
}
for (var g = 0; g < textInputs.length; g++) {
textInputs[g].disabled = true;
}
for (var f = 0; f < textareas.length; f++) {
textareas[f].disabled = true;
}
for (var z = 0; z < radioInputs.length; z++) {
radioInputs[z].disabled = true;
}
But this above works fine for me. The below is what I would assume would work instead - put all elements into a single array, and iterate over a single array to set each to disabled. When I view the HTMLCollection via console.log it says disabled:true yet the element on the screen is not disabled. What am I missing here?
var textEditors = document.getElementsByClassName('textEditor'),
textareas = document.getElementsByTagName('textarea'),
radioInputs = document.getElementsByClassName('radioSelect'),
textInputs = document.getElementsByTagName('input');
var normalInputs = [];
normalInputs.push(textEditors);
normalInputs.push(textInputs);
normalInputs.push(radioInputs);
normalInputs.push(textareas);
for (var i = 0; i < normalInputs.length; i++) {
console.log(normalInputs[i])
normalInputs[i].disabled = true;
}
This will serve your purpose.
In your second method you're pushing the array capture from getElement into normalInputs array and than looping through that array and applying disable property on elements of inputArray which is eventually array of all the selected elements not individual element.
var textEditors = document.getElementsByClassName('textEditor'),
textareas = document.getElementsByTagName('textarea'),
radioInputs = document.getElementsByClassName('radioSelect'),
textInputs = document.getElementsByTagName('input');
var normalInputs = [];
normalInputs.push(textEditors);
normalInputs.push(textInputs);
normalInputs.push(radioInputs);
normalInputs.push(textareas);
normalInputs.forEach(e=>{
e.forEach(ele =>{
ele.disabled = true;
})
})
Without ES6
for (var i = 0; i < normalInputs.length; i++) {
for(let j=0; j< normalInputs[i].length; j++){
normalInputs[i][j].disabled = true;
}
}
A better approach is use concat
var normalInputs = [];
normalInputs = normalInputs.concat(textEditors,textInputs,radioInputs, textareas);
for(let i=0; i<normalInputs.length; i++){
normalInputs[i].disabled = true;
}
Well, give all of them same class like .inputs and get all of them with one expression:
var items = document.querySelectorAll( '.inputs' );
if it's not possible, get all of them like this:
var items = document.querySelectorAll( 'input, .textEditor, .radioSelect, textarea' );
then you can fix that with one loop for all of them:
for ( var i = 0; i < items.length; i++ )
items[ i ].disabled = true;

Google Apps Script: Comparing Arrays for Unique Values

I'm working from the solution provided HERE to compare two arrays. The example provided returns values found in both arrays to Array1 (same) and values only found on one or the other two Array2 (diff).
ISSUE: When I apply it to my own script, valuesDATA returns nothing and valuesCheckSeeding returns ALL values from both arrays
DESIRED RESULT: I have two arrays that I'd either like to create a third out of, or only select values from the first array, valuesDATA which are NOT present in the second, valuesCheckSeeding. Using the solution above, I was trying to have all values not found in valuesCheckSeeding AND valuesDATA pushed to valuesDATA.
SAMPLE OF valuesDATA: "U09 F
Harford FC Hill/Healey - A
MD
CMSA Girls Saturday U09 A/B North
Premier - Top
TID0118"
What am I doing wrong? I tinkered with changing matchfound==false and matchfound=true in the loop, but that still didn't give me the desired result.
MOST RELEVANT SNIPPET
var matchfound = false;
for (var i = 0; i < valuesDATA.length; i++) {
matchfound=false;
for (var j = 0; j < valuesCheckSeeding.length; j++) {
if (valuesDATA[i] == valuesCheckSeeding[j]) {
valuesCheckSeeding.splice(j, 1);
matchfound=true;
continue;
}
}
if (matchfound==false) {
valuesCheckSeeding.push(valuesDATA[i]);
valuesDATA.splice(i, 1);
i=i-1;
}
}
WORKIG SCRIPT EDITED FROM COMMENTS/ANSWERS BELOW
//UPDATE SEEDING SHEET
function updateSeedingSheet() {
var today = Utilities.formatDate(new Date(),Session.getScriptTimeZone(), "MM/dd/yyyy hh:mm a");
//INPUT SHEET INFO
var inputCurrentRow = 4;
var inputCurrentColumn = 20;
var inputNumRows = 1000;
var inputNumColumns =1;
var ssInput = SpreadsheetApp.openById('1Wzg2BklQb6sOZzeC0OEvQ7s7gIQ07sXygEtC0CSGOh4');
var sheetDATA = ssInput.getSheetByName('DATAREF');
var rangeDATA = sheetDATA.getRange(inputCurrentRow, inputCurrentColumn, inputNumRows, inputNumColumns);
var valuesDATA = rangeDATA.getValues();
//SEEDING SHEET INFO
var seedingCurrentRow = 4;
var seedingCurrentColumn = 1;
var seedingNumRows = 1000;
var seedingNumColumns = 1;
var ssSeeding = SpreadsheetApp.openById('1DuCHeZ3zba-nHq-7vYTrylncPGqcA1J9jNyW9DaS3mU');
var sheetSeeding = ssSeeding.getSheetByName('Seeding');
var rangeCheckSeeding = sheetSeeding.getRange(4, 102, 1000, 1);
var columnToClear = sheetSeeding.getRange(seedingCurrentRow, seedingCurrentColumn, seedingNumRows, seedingNumColumns);
var valuesCheckSeeding = rangeCheckSeeding.getValues();
//METHOD TO FILTER
valuesCheckSeeding = valuesCheckSeeding.map(function(e){return e[0];}); //flatten this array
var filteredArr = valuesDATA.filter(function(e){
return !(this.indexOf(e[0])+1);
},valuesCheckSeeding);
Logger.log(filteredArr);
Logger.log(filteredArr.length);
var rangeSeeding = sheetSeeding.getRange(seedingCurrentRow, seedingCurrentColumn, filteredArr.length, seedingNumColumns);
sheetSeeding.getRange('A1').setValue(today);
columnToClear.clearContent();
rangeSeeding.setValues(filteredArr);
/*
//ALTERNATIVE METHOD USING LOOPS
for (var i = 0; i < valuesDATA.length; i++) {
for (var j = 0; j < valuesCheckSeeding.length; j++) {
if (valuesDATA[i][0] == valuesCheckSeeding[j][0]) {
valuesDATA.splice(i, 1);
i--; //account for the splice
break; //go to next i iteration of loop
}
}
}
Logger.log("VALUES DATA:" + valuesDATA);
Logger.log("VALUES CHECK SEEDING: " + valuesCheckSeeding);
//sheetSeeding.getRange('A1').setValue(today);
//rangeSeeding.clearContent();
//rangeSeeding.setValues(valuesDATA); //INCORRECT RANGE HEIGHT, WAS 71 BUT SHOULD BE 1000 - Is splice affecting this?
*/
}//END FUNCTION
V8(ES2016 update):
You can use newer and efficient set class
const array1 = [[1],[2],[3]],
array2 = [[1],[3],[4]],
set = new Set(array2.flat())
console.info(array1.filter(e => !set.has(e[0])))
//expected output [[2]]
You're checking a 2D array. You'd need to use [i][0] and [j][0]
You can try only splicing valuesDATA
Try
for (var i = 0; i < valuesDATA.length; i++) {
for (var j = 0; j < valuesCheckSeeding.length; j++) {
if (valuesDATA[i][0] == valuesCheckSeeding[j][0]) {
valuesDATA.splice(i, 1);
i--; //account for the splice
break; //go to next i iteration of loop
}
}
}
Logger.log(valuesDATA);
Alternatively, try
valuesCheckSeeding = valuesCheckSeeding.map(function(e){return e[0];}); //flatten this array
var filteredArr = valuesDATA.filter(function(e){
return !(this.indexOf(e[0])+1);
},valuesCheckSeeding);
Logger.log(filteredArr);

Split string in Array by space in JavaScript

I am trying to get my array reversed without using the reverse() method. What am I doing wrong here?
This is the code that I have for now. I think I'm close but I'm stuck.
var zin = ["Kan jij achterstevoren praten?"];
var woorden = zin.split(" ");
woordenOmgedraaid = achterstevoren(woorden);
document.write(woordenOmgedraaid);
function achterstevoren(omgedraaid) {
var length = omgedraaid.length;
var woordenOmgedraaid = [];
var counter = 0;
for (var i = omgedraaid.length - 1; i >= 0; i -= 1) {
woordenOmgedraaid[counter] = omgedraaid[i];
counter += 1;
}
return woordenOmgedraaid;
}
Take the brackets off the "zin" variable.
var zin = "Kan jij achterstevoren praten?";
var woorden = zin.split(" ");
woordenOmgedraaid = achterstevoren(woorden);
console.log(woordenOmgedraaid);
function achterstevoren(omgedraaid) {
var length = omgedraaid.length;
var woordenOmgedraaid = [];
var counter = 0;
for (var i = omgedraaid.length - 1; i >= 0; i -= 1) {
woordenOmgedraaid[counter] = omgedraaid[i];
counter += 1;
}
return woordenOmgedraaid;
}
If you're trying to create a for loop that goes backwards through an array, you can simply write it as:
var arr = [1,2,3,4,5]
var reversedArr = []
for (var i = arr.length-1; i >= 0; i--) {
reversedArr.push(arr[i])
}
console.log(reversedArr)

Using Javascript find array values in another array and in order

Here is one to get your brain going! I've not had any luck with it.
[1,2,1,1,2,1,1,1,2,2]
[1,2,1,1,2,1]
I would like to use the second array to find the values in the first, but they must be in the same order.
Once for I would like it to return the next key up from the last key in the second array.
So in this example it would use the first six digits in the first array and then return 6 as the key after the final one in the second array.
var a2 = [1,2,1,1,2,1,1,1,2,2]
var a1 = [1,2,1,1,0,1]
function find(arr1, arr2) {
var len = 1
var result = 0;
var s2 = arr2.toString();
for (len=1;len <= a1.length; len++)
{
var aa1 = arr1.slice(0, len)
var s1 = aa1.toString();
if(s2.indexOf(s1)>=0){
result = aa1.length;
}
else {
break;
}
}
return result;
}
alert(find(a1, a2));
var find = function(haystack, needle) {
var doesMatch = function(offset) {
for (var i = 0; i < needle.length; i++) {
if (haystack[i+offset] !== needle[i]) {
return false;
}
}
return true;
};
for (var j=0; j < haystack.length - needle.length; j++) {
if (doesMatch(j)) {
return j;
}
}
return -1;
};
This is quick, this is dirty, and this is correct only if your data doesn't include any comma.
var needle = [1,2,1,1,2,1];
var haystack = [1,2,1,1,2,1,1,1,2,2];
if ( needle.length <= 0 ) return 0;
var fromStr = ','+haystack.toString()+','
var findStr = ','+needle.toString()+','
// Find ',1,2,1,1,2,1,' in ',1,2,1,1,2,1,1,1,2,2,'
var pos = fromStr.indexOf(findStr);
// Count the end position requested
return pos >= 0 ? fromStr.slice(0,pos+1).match(/,/g).length + needle.length - 1 : -1;
Note: The comma at head and tail is to make sure [22,12] doesn't match [2,1].

Categories

Resources