Bucket Sort JavaScript - javascript

I am having trouble implementing a search engine for my webpage in JavaScript. Firstly, I have an array[strings] of classnames. With the classnames I want to do a bucketsort with buckets namely a-z, so a bucketSize[a-z]. Once I detect the first letter of the classname[i] I place it in the correct bucket. That is my first function classSort().
Then next I want to be able to read an input from HTML tag and search the buckets with the first letter and return it. I am having trouble creating a for loop that run through the bucket and return every string with the letter that the user typed. I am still fairly new to programming and im trying to challenge by self to built a website, but i keep getting stuck on the searching of the webpage. This is my code so far.
let classNames;
let bucketSize;
function classSort(classNames, bucketSize){
//empty check
if(classNames.length === 0){
return classNames;
}
//initialize buckets
var bucketSize = new Array();
for (var aToz = 'a'; aToz <= 'z'; aToz++){
bucketSize.push(new Array());
}
//Detect first letter of each ith String and put it in the right bucket
for ( var i = 0; i <= classNames.length; i++){
for (var aToz = 'a'; aToz <= 'z'; aToz++){
if (className[i].startsWith(String.valueOf(aToz)){
bucketSize.find(aToz).push(classNames[i]);
}
}
}
function classSearch(inputSearch){
document.getElementById("submit").onsubmit = function()
inputSearch = document.getElementById("search").value;
if (inputSearch === ""){
return ("Nothing was typed!")
}else{
for (var aToz = 'a'; aToz <= 'z'; aToz++){
if (inputSearch.startsWith(String.valueOf(aToz)){
//for (var i = 0; i <= )
bucketSize.find(aToz).pop(classNames[i]);
}
}
}
}
Any help is greatly appreciated. THANKS!!!!

Related

Best approach to group people into teams using Google Apps Script

Essentially there are around ~200 in this department. We are looking to create squads of 4, where each squad must be from a different team, located in the same city, one must be a driver (and the other 3 therefore should not be drivers), and all four people on the team should have similar preferences. These criteria are captured via a Google Form so ultimately we will get the relevant data we need to build out the conditions. My only challenge currently is that I am not well-versed in Apps Script so will need high level guidance on how to approach it.
Currently, I am thinking of storing each column in their own respective arrays and then using a For loop and conditional statements within that to try to satisfy all the requirements. For example, the first conditional statement would be whether the person drives, and if they do then put them into this new array (which will be defined). Next, check the next response and if that person doesnt drive, and has same same preferences, is located in same city, and is on a different team, then include them into that array. Otherwise, move onto the next person and check for those requirements. Once the group hits 4 people, set the values into the Google Sheet somewhere and then search for the next driver in the list and build another group using same logic.
Alternative approach might be to first sort people into 2 groups (based on the two cities), then within each group sort folks based on driver and add in the other criterias as well.
Regardless of which approach I take in terms of algorithm, would first storing each column into an array make the most sense, then managing the array values using various conditional statements.
Here is what I have so far:
function matchUsers() {
//store each column into arrays for use later on
var responseSheet = SpreadsheetApp.getActive().getSheetByName("Responses");
var Alast = responseSheet.getRange("A2:A").getValues().filter(String).length;
Logger.log(Alast);
var emails = responseSheet.getRange("A2:A").getValues();
var userEmails = responseSheet.getRange(2,1, Alast,1).getValues();
var tmName = responseSheet.getRange(2,2, Alast,1).getValues();
var team = responseSheet.getRange(2,3, Alast,1).getValues();
var city = responseSheet.getRange(2,4, Alast,1).getValues();
var firstChoice = responseSheet.getRange(2,5, Alast,1).getValues();
var secChoice = responseSheet.getRange(2,6, Alast,1).getValues();
var thirdChoice = responseSheet.getRange(2,7, Alast,1).getValues();
var driveStatus = responseSheet.getRange(2,8, Alast,1).getValues();
var arrayResponses = [userEmails,tmName,team,city,firstChoice,secChoice,thirdChoice, driveStatus];
//clear sheets
SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Output").getRange(2, 1,20,50).clearContent();
SpreadsheetApp.getActiveSpreadsheet().getSheetByName("CitySort").getRange(2, 1,20,50).clearContent();
//prepare arrays
var edmTMs = [];
var calTMs = [];
var edmDrivers = [];
var calDrivers = [];
//loop through each row and sort team members by respective city and driving capability
for (let i = 0; i < Alast;i+=1){
if (arrayResponses[3][i] == "Edmonton" && arrayResponses[7][i] == "Yes"){
edmDrivers.push(arrayResponses[1][i]);
}else if (arrayResponses[3][i] == "Edmonton" && arrayResponses[7][i] == "No"){
edmTMs.push(arrayResponses[1][i]);
}else if (arrayResponses[3][i] == "Calgary" && arrayResponses[7][i] == "Yes"){
calDrivers.push(arrayResponses[1][i]);
}else if (arrayResponses[3][i] == "Calgary" && arrayResponses[7][i] == "No"){
calTMs.push(arrayResponses[1][i]);
}
}
Logger.log("\nEdmonton: "+edmTMs + "\nCalgary: "+calTMs );
var range = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("CitySort").getRange(2,1,edmTMs.length,1);
range.setValues(edmTMs);
var range = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("CitySort").getRange(2,2,calTMs.length,1);
range.setValues(calTMs);
var range = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("CitySort").getRange(2,3,edmDrivers.length,1);
range.setValues(edmDrivers);
var range = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("CitySort").getRange(2,4,calDrivers.length,1);
range.setValues(calDrivers);
}
Let's see if this fits your needs. I'm pretty sure there are more elegant and efficient solutions than this one, so I appreciate any suggestion.
I tested the script with 34 users, and I got 8 teams of 4 and 2 teams of 1:
Don't mind the repeated names, they are all different rows with different Cities, Teams and Choices. I added a letter to some of them to differentiate.
The script works as follows:
It gets each user row and compares the City, Teams and Choices with all the other 33. It also discards the users that are already in a team. The priority is City > Team > Choice 1 > Choice 2 > Choice 3.
It will also try to force teams of 4 members, so in case there is a team of 3, it will ignore the Teams to try to find the 4th, but it still will respect the Choices and Cities. You can disable this by setting the boolean ignoreTeams to false. In my test, only 3 groups have 1 repeated team.
The script will never put two users from different cities in the same group.
function main() {
var sprsheet = SpreadsheetApp.getActiveSpreadsheet();
var sheet_1 = sprsheet.getSheetByName("Members");
var sheet_2 = sprsheet.getSheetByName("Output");
var number = sheet_1.getLastRow() - 1;
var members = []; //Each row of Members will be stored here
getMembers(sheet_1, members, number);
orderMembers(sheet_2, members);
}
function getMembers(sheet_1, members, number){
for (var i = 0; i < number; i++){
var values = sheet_1.getRange(i+2, 1, 1, 8).getValues();
members.push(new Person(values[0][0],values[0][1],values[0][2],values[0][3],values[0][4],values[0][5],values[0][6],values[0][7]));
}
}
function orderMembers(sheet_2, members){
var col = 1;
var counter = 0; //Number of Persons in each group column [0-3]
loop1:
for (var i = 0; i < members.length; i++){
var loopbreaker = 0; //Avoids an endless loop if ignoreTeams = true
var ignoreTeams = false;
var row = 2;
if (!members[i].assigned || i == 0){
var teams = []; //Array of teams of each group
sheet_2.getRange(row, col).setValue(members[i].name);
members[i].assigned = true;
teams.push(members[i].team);
loop2:
for (var loop = 0; loop < 9; loop++){
var value = order_params(i, loop, members, teams, ignoreTeams);
if (value != null){
sheet_2.getRange(row + 1, col).setValue(value); //Writes in sheet Output
counter++;
row++;
}
//If the group is smaller than 4 and the loop is over, it will ignore the teams and start again in order to complete the group.
if (counter < 3 && loop == 8 && loopbreaker < 1){
loop = 0;
ignoreTeams = true; //Set to false to never ignore teams
loopbreaker++;//The loopbreaker avoids an endless loop
} else if (counter == 3 || loop == 8){
col++;
counter = 0;
break loop2;
}
}
}
}
}
function order_params(i, loop, members, teams, ignoreTeams){
for (var x = 0; x < members.length; x++){
if (!members[x].assigned && members[x].email != members[i].email && members[x].city == members[i].city && (!checkTeams(members[x].team, teams) || ignoreTeams)) {
if (members[x].choice1 == members[i].choice1 && loop < 3) {
members[x].assigned = true;
teams.push(members[x].team);
return members[x].name
} else if (members[x].choice2 == members[i].choice1 && loop >= 3 && loop < 6) {
members[x].assigned = true;
teams.push(members[x].team);
return members[x].name
} else if (members[x].choice3 == members[i].choice1 && loop >= 6 && loop < 9) {
members[x].assigned = true;
teams.push(members[x].team);
return members[x].name
}
}
}
}
//Checks for duplicate teams in the group
function checkTeams(member_t, teams){
for (var i = 0; i < teams.length; i++){
if (member_t == teams[i]){
return true;
}
}
}
//Converts the data from the Sheet into Person objects.
function Person(email, name, team, city, choice1, choice2, choice3, driver){
this.email = email;
this.name = name;
this.team = team;
this.city = city;
this.choice1 = choice1;
this.choice2 = choice2;
this.choice3 = choice3;
this.driver = driver;
this.assigned = false; //Assigned = true means the Person is already in a group
}
As you see I'm not using the field Driver, so you can make a condition in case you see too many groups without drivers, or change the members manually. If this is a serious problem, I will modify the code.

Javascript Random Name Guesser: Unresponsive Script Issues

This is my first post here and I am having trouble wording a question, so please bear with me as I have been on this issue for hours.
My friend and I have thought of a fun little function that is supposed to guess the user's name (through an <input> tag) in a certain amount of trials using the random number function to access string letters from an alphabet array numbered 0-25. The function is also supposed to give the user the number of trials it took to guess their name.
I keep getting a non-responsive script, (line 33 - The line containing the second "for loop").
var goal = document.getElementById("your_Name").value;
var alphabet = ["a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z"];
var goalArray = goal.split("");
var trials = 0;
var guessArray = new Array();
var i;
var n;
for (i = 0; i < goalArray.length; i++){
guessArray.push(alphabet[Math.floor(Math.random()*26)]);
}
while (goalArray != guessArray){
trials++;
guessArray = [];
for (n = 0; n < goalArray.length; n++){
guessArray.push(alphabet[Math.floor(Math.random()*26)]);
}
}
document.getElementById("appendomatic").innerHTML = "It took " + guessArray + " trials to guess correctly";
Any help or attempt to help would be immensely appreciated!
In case anyone was wondering: This little idea of ours was to test the randomness of Javascript's random function through trials (he made the same program in MatLab, so we are going to compare results of the random functions from both languages).
goalArray != guessArray is always true since they are two separate arrays; even if they contain the same elements.
Since they appear to just be arrays of individual letters in a-z you could compare them with something like goalArray + '' != guessArray, because the toString() of the arrays will compare correctly.
This is how I eventually got it to work (by nesting the while loop and second for loop in another for loop):
var goal = document.getElementById("your_Name").value;
var goalArray = goal.split("");
var alphabet = ["a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z"];
var trials = 0;
var guessArray = [];
for (i = 0; i < goalArray.length; i++){
guessArray.push(alphabet[Math.floor(Math.random()*26)]);
}
for (x = 0; x < goalArray.length; x++){
while (goalArray[x] != guessArray[x]){
trials++;
guessArray = [];
for (n = 0; n < goalArray.length; n++){
guessArray.push(alphabet[Math.floor(Math.random()*26)]);
}
}
document.getElementById("appendomatic").innerHTML = "It took " + trials + " trials to guess correctly";
}
}

Google sheets: How do I get my custom function to refresh automatically?

I have written a Google Sheet application for myself that (among other things) has a schedule for consultants to work on projects. I have written a custom function that displays summary information from the calendar; for example:
Tubb, Ernest|Project 1
Tubb, Ernest|Project 2
Perkins, Carl|Project 1
I wrote the function because the mess of FILTER() functions I was using was incomprehensible; and the javascript required to do the same thing is relatively straightforward.
What I find however, is that when the underlying data changes, the cells written by my function are NOT recalculated the way they were with the FILTER() function. How can I program some sort of listener that makes my function's output be refreshed when the underlying data changes? Do I have to do this by hand with the onEdit() function?
And here is my function:
// Global Constants - these will change each quarter based on the calendar structure.
var CALENDAR_QUARTER_START = "F"
var CALENDAR_QUARTER_END = "CS"
// Generate a nice 2-column display of Consultant and Project(s) they are scheduled on,
// based on the consultant names and calendar codes in the Calendar tab.
// "billable" parameter specifies the return of only uppercase activities (true) or all activities (false)
function fortifyConsultantsAndProjects( billable ){
// Resolve arguments
var billable = arguments[0];
if (arguments[0] == undefined) billable = true;
var calendar = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Calendar");
var consultants = calendar.getRange( "A8:A" ).getValues();
var ret = [];
var row = 0;
for ( var i=0; i<consultants.length; i++ ){
var consultant = consultants[i].toString();
var projects = fortifyGetProjectsForConsultant( consultant, billable );
for (var j=0; j < projects.length; j++ ) {
ret.push( [] );
ret[row][0] = consultant;
ret[row][1] = projects[j];
row++;
}
}
return ret;
}
function fortifyGetProjectsForConsultant( consultant, billable ){
// Resolve arguments
var consultant = arguments[0];
if (arguments[0] == undefined) consultant = "Held, Doug";
var billable = arguments[1];
if (arguments[1] == undefined) billable = true;
// Get the range of consultants defined in Column A of Calendar tab.
var calendar = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Calendar");
var consultants = calendar.getRange( "A8:A" ).getValues();
// Identify which Calendar row contains the specified consultant's schedule.
var row;
for ( var i=0; i< consultants.length; i++){
//Browser.msgBox( "compare " + consultant + " and " + consultants[i] );
if ( consultants[i].toString() == consultant ){
row = i+8;
break;
}
}
// Obtain all the consultant's schedulings. Contains many duplicates, so sort.
var projects = calendar.getRange( CALENDAR_QUARTER_START + row + ":" + CALENDAR_QUARTER_END + row + "" ).getValues()[0].sort();
// Iterate through the sorted project codes, removing duplicates and blanks
var ret = [];
var row = 0;
var prev = "";
for ( var i = 0; i< projects.length; i++ ){
var temp = projects[i].toString();
if (temp != "" && temp != prev ){
// Resolve whether to return each row based on project billability (uppercase)
if ( temp.toUpperCase() == temp || billable == false ){
ret[row] = temp;
row++;
}
prev = temp;
}
}
return ret;
}
Well since nobody ever answered, I will explain how I solved the problem.
Instead of a zero-argument function parameter list, I receive all of the ranges (for instance the range Calendar!A8:A that you see hard coded here). Then any time data in the parameter ranges changes, the function is invoked again. This does occasionally cause some sort of runtime error in Google sheets - on update, I sometimes get "the document is not available" and an instruction to reload the sheet.
When a range is received as a parameter, that data is received byvalue as a 2 dimensional array of cell values -- the same as the array returned from Range.getValues().

Text area transposition

I am a beginner and I've found some useful examples for what I want to do. The problem is the examples that I've found don't have enough comments for me to understand what is going on. So, I hope someone can help me implement the code I've found into the code that I already have. I'm making a text manipulation area to use to play with cipher text. It's all being done inside a single HTML text area. I've got a functions called, "function G_Group(size, count)", that breaks the text into rows and columns of choice and it is working great. The next tool that I want to add will transpose this matrix from (x,y) to (y,x). Because I have the "function G-Group" function, I don't believe I need to slice anything. I found a bit of JavaScript transposition code at http://rosettacode.org/wiki/Matrix_transposition#JavaScript but I don't know how to change the values to add it to what I've got already.
Function G_Group(size, count) is called like this.
<input type= button value="Grouping" onclick = "return G_Group(0, 0)" title="grouping" />
And here is the how i break text up into rows and columns:
function G_Group(size, count)
{
if (size <= 0)
{
size = document.encoder.group_size.value;
if (size <= 0)
{
alert('Invalid group size');
return false;
}
}
if (count <= 0)
{
count = document.encoder.group_count.value;
if (count <= 0)
{
alert('Invalid group count');
return false;
}
}
var t = document.encoder.text.value;
var o = '', groups = 0;
t = Tr(t, " \r\n\t");
while (t.length > 0)
{
if (o.length > 0)
{
o += ' ';
}
if (groups >= count)
{
o += "\n";
groups = 0;
}
groups ++;
o += t.slice(0, size);
t = t.slice(size, t.length);
}
document.encoder.text.value = o;
return false;
}
And this is the code that I want modify to transpose the array.
function Matrix(ary) {
this.mtx = ary
this.height = ary.length;
this.width = ary[0].length;
}
Matrix.prototype.toString = function() {
var s = []
for (var i = 0; i < this.mtx.length; i++)
s.push( this.mtx[i].join(",") );
return s.join("\n");
}
// returns a new matrix
Matrix.prototype.transpose = function() {
var transposed = [];
for (var i = 0; i < this.width; i++) {
transposed[i] = [];
for (var j = 0; j < this.height; j++) {
transposed[i][j] = this.mtx[j][i];
}
}
return new Matrix(transposed);
}
I am aware that I may be approaching this all wrong. And I'm aware that the questions I have are very basic, I'm a little embarrassed to ask these simple questions. Please excuse me. I'm 43 years old and had c programming in college 20 years ago. I'm pretty good with HTML and CSS but I'm lacking in a lot of areas. Hope someone can help me with this. Thanks.

Javascript var name counting variable

I have the following bit of code:
function finalCheck(theForm) {
var z = 0;
for(var i=0;i<15;i++){
var _i = theForm.elements[i].value;
if(_i == ""){
theForm.elements[i].style.background = '#FFD6D6';
z = 1;
}
}
if(z == 1){
alert("Please correct the fields highlighted in red");
return false;
} else {
return true;
}
}
What I was attempting to do was set the name of var _i to var _ and then the index that the counting variable was currently on. For example, _1 _2 _3 etc. Any way to do this?
So I under stand what you are trying to do, and your solution is to use eval
eval("var _" + i + "= theForm.elements[i].value;");
Anyways your code doesn't need any dynamic generation of variable names as var _i is a local variable.
I hope you are asking this question for learning purpose.

Categories

Resources