Swap columns in a one-dimensional array in Javascript - javascript

I'm trying to swap 2 columns from a delimited text, but the farthest I got is grabbing the first column. This is what I'm trying to achieve.
// Input
A1—B1—C1
A2—B2—C2
A3—B3—C3
Swap column #1 with column #3. Delimiter is "—".
// Result
C1—B1—A1
C2—B2—A2
C3—B3—A3
JSFiddle
var text = $('#input').val().split("\n");
var delimiter = "—";
var col_1 = $('#col_1').val() - 1;
var col_2 = $('#col_2').val() - 1;
var out = [];
var col_arr = [];
var col = '';
// Get first column
for (var i = 0; i < text.length; i++) {
col_arr = text[i].split(delimiter);
col = col_arr[col_1];
if (col != undefined) col = col;
else col = '';
out[i] = col;
}
text = out.join('\n');

You've successfully split the text into an array of its constituent parts using split, you can now use the reverse Array function to reverse the order, and then rejoin all the parts together using the join Array function and your delimiter.
This simplifies your code in your for loop to this:
for (var i = 0; i < text.length; i++) {
out[i] = text[i].split(delimiter).reverse().join(delimiter);
}

It's a simple swap with a temp variable. I've used Array.map() to iterate the text array, but you can replace it with a `for...loop.
$("button").click(function() {
var delimiter = "—";
var rowDelimiter = "\n";
var text = $('#input').val()
.trim() // remove white space before and after the text
.split(rowDelimiter);
var col_1 = $('#col_1').val() - 1;
var col_2 = $('#col_2').val() - 1;
// check the cols to be a number between 0 and the amount of columns
// and notify user if their not
var result = text.map(function(row) {
var arr = row.split(delimiter);
var temp = arr[col_1]; // cache the value of col_1
arr[col_1] = arr[col_2]; // set the value of col_2 1 to be that of column 2
arr[col_2] = temp; // set the value of col_2 to be the value of temp
return arr.join(delimiter);
}).join(rowDelimiter);
$('#output').val(result);
});
textarea {
width: 100%;
height: 120px
}
button {
margin: 10px 0
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
Swap col #<input id="col_1" value="2"> with col #<input id="col_2" value="3">
<br>
<textarea id="input">
A1—B1—C1—D1
A2—B2—C2—D2
A3—B3—C3—D3
</textarea>
<button>Swap</button>
<textarea id="output">
</textarea>

split() returns an array, so what you can do is first processing your text data to an actual array so its easier to work on it :
function getArrayFromInput(){
var arr = [];
var lines = $('#input').val().split("\n");
for (let line of lines){
let column = line.split('—');
arr.push(column);
}
return arr;
}
//returns [['A1','B1','C1'],['A2','B2','C2'],['A3','B3','C3']]
It'll be easier to do what you're trying to do then :)
function swapColumns(inputArr, col1, col2){
var arr = JSON.parse(JSON.stringify(inputArr)); //get inputArr structure
for(let i = 0; i<arr.length; i++){
//swap the values
arr[i][col1] = inputArr[i][col2];
arr[i][col2] = inputArr[i][col1];
}
return arr;
}
//return your array with swaped columns
I'll then let you handle the array to text conversion !
Feel free to ask any question

Related

How to automate randomizing 46 names to create 46 x 6 unique rows and columns in Google sheet?

I am working with automation in Google sheet. Can you help me?
This problem is for sending surveys to 46 people. Each people needs to rate 5 people from those 46 people.
Requirements:
1. 1 rater, for 5 uniques ratees
2. No duplicate name per row (it should be 6 unique names in a row)
3. No duplicate name per column (it should be 46 unique names per column)
Expected output is for us to create 46x6 random names with no duplicates in row and columns.
-
-
Flow:
If a unique matrix across and below can be created, then it's values can be used as keys to the actual name array.
Create a 2D number array with length = number of rows
Loop through required number of columns and rows
Create a temporary array (tempCol) to store current column data
Fill the array with random numbers
Use indexOf to figure out if any random numbers are already present in the currentrow/ current column, if so, get a new random number.
In random cases, where it's impossible to fill up the temporary column with unique random numbers across and below, delete the temporary column and redo this iteration.
Snippet:
function getRandUniqMatrix(numCols, numRows) {
var maxIter = 1000; //Worst case number of iterations, after which the loop and tempCol resets
var output = Array.apply(null, Array(numRows)).map(function(_, i) {
return [i++]; //[[0],[1],[2],...]
});
var currRandNum;
var getRandom = function() {
currRandNum = Math.floor(Math.random() * numRows);
}; //get random number within numRows
while (numCols--) {//loop through columns
getRandom();
for (
var row = 0, tempCol = [], iter = 0;
row < numRows;
++row, getRandom()
) {//loop through rows
if (//unique condition check
!~output[row].indexOf(currRandNum) &&
!~tempCol.indexOf(currRandNum)
) {
tempCol.push(currRandNum);
} else {
--row;
++iter;
if (iter > maxIter) {//reset loop
iter = 0;
tempCol = [];
row = -1;
}
}
}
output.forEach(function(e, i) {//push tempCol to output
e.push(tempCol[i]);
});
}
return output;
}
console.info(getRandUniqMatrix(6, 46));
var data1d = data.map(function(e){return e[0]});
var finalArr = getRandUniqMatrix(6, 46).map(function(row){return row.map(function(col){return data1d[col]})});
destSheet.getRange(1,1,finalArr.length, finalArr[0].length).setValues(finalArr);
The OP wants to create a review matrix in which the names of the reviewed employees are chosen at random, the reviewer cannot review themselves, and the matrix is completed for 46 employees.
Based on previous code, this version builds an array of employee names for each row, in which the name of the reviewer is not included in the array. Five names are chosen at random and applied to the reviewer. The loop then repeats through each of the 46 employees.
For example, in the first round of reviews, "name01" is omitted from the array of employees from which the "reviewees" are randomly chosen. In the second round, "name01" is included, but "name02" is excluded from the array of employees. And so on, such that in each case, the array of employees used for the random selection of five reviews is always 45 names in length, and excludes the name of the reviewer.
The random selection of names to be rated does not ensure an equal and even distribution of reviews among employees. Though each employee will conduct 5 reviews, some employees are reviewed more than 5 times, some less than 5 times, and (depending on the alignment of the sun, the moon and the stars) it is possible that some may not be selected for review.
function s05648755803(){
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheetname = "Sheet3";
var sheet = ss.getSheetByName(sheetname);
// some variables
var randomcount = 30; // how many random names
var rowstart = 7; // ignore row 1 - the header row
var width = 5; // how many names in each row - 1/rater plus 5/ratee
var thelastrow = sheet.getLastRow();
//Logger.log("DEBUG:last row = "+thelastrow)
// get the employee names
var employeecount = thelastrow-rowstart+1;
//Logger.log("DEBUG: employee count = "+employeecount);//DEBUG
// get the data
var datarange = sheet.getRange(rowstart, 1, thelastrow - rowstart+1);
//Logger.log("DEBUG: range = "+datarange.getA1Notation());//DEBUG
var data = datarange.getValues();
//Logger.log("data length = "+data.length);
//Logger.log(data);
var counter = 0;
var newarray = [];
for (c = 0;c<46;c++){
counter = c;
for (i=0;i<data.length;i++){
if(i!=counter){
newarray.push(data[i]);
}
}
//Logger.log(newarray);
var rowdata = [];
var results = selectRandomElements(newarray, 5);
Logger.log(results)
rowdata.push(results);
var newrange = sheet.getRange(rowstart+c, 3, 1, 5);
newrange.setValues(rowdata);
// clear the arrays for the next loop
var newarray=[];
var rowdata = []
}
}
/*
// selectRandomElements and getRandomInt
// Credit: Vidar S. Ramdal
// https://webapps.stackexchange.com/a/102666/196152
*/
function selectRandomElements(fromValueRows, count) {
var pickedRows = []; // This will hold the selected rows
for (var i = 0; i < count && fromValueRows.length > 0; i++) {
var pickedIndex = getRandomInt(0, fromValueRows.length);
// Pick the element at position pickedIndex, and remove it from fromValueRows. See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/splice
var pickedRow = fromValueRows.splice(pickedIndex, 1)[0];
// Add the selected row to our result array
pickedRows.push(pickedRow);
}
return pickedRows;
}
function getRandomInt(min,
max) { // From https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/random
min = Math.ceil(min);
max = Math.floor(max);
return Math.floor(Math.random() * (max - min)) + min;
}
Screenshot#1
Screenshot#2
Try this. Satisfies all the three requirements.
HTML/JS:
<html>
<title>Unique Employees</title>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.0/jquery.min.js"></script>
</head>
<table id="survey_table" border="1" width="85%" cellspacing="0">
<thead>
<th>Rater</th>
<th>Ratee1</th>
<th>Ratee2</th>
<th>Ratee3</th>
<th>Ratee4</th>
<th>Ratee5</th>
</thead>
<tbody id="table_body">
</tbody>
</table>
<script type="text/javascript">
function arrayRemove(arr, value) {
return arr.filter(function(ele) {
return ele != value;
});
}
function getRandomInt(rm_row, rm_col) {
var temp_arr = [];
for (var k = 1; k <= 46; k++) {
temp_arr.push(k);
}
for (var k = 0; k < rm_row.length; k++) {
temp_arr = arrayRemove(temp_arr, rm_row[k]);
}
for (var k = 0; k < rm_col.length; k++) {
temp_arr = arrayRemove(temp_arr, rm_col[k]);
}
var rand = temp_arr[Math.floor(Math.random() * temp_arr.length)];
return rand;
}
function exclude_num(row_unq, col_unq) {
var rand_int = getRandomInt(row_unq, col_unq);
if (!row_unq.includes(rand_int) && !col_unq.includes(rand_int)) {
arr_row.push(rand_int);
return rand_int;
} else {
return exclude_num(arr_row, arr_cols);
}
}
for (var i = 1; i <= 46; i++) {
var arr_row = [];
arr_row.push(i);
var table_html = '<tr id="Row' + i + '">';
for (var j = 1; j <= 6; j++)
{
if (j == 1) {
table_html += '<td class="Column' + j + ' cells_unq">' + i + '</td>';
} else {
var arr_cols = []
$('.Column' + j).each(function() {
arr_cols.push(Number($(this).text()));
});
var num = exclude_num(arr_row, arr_cols);
table_html += '<td class="Column' + j + ' cells_unq">' + num + '</td>';
}
}
table_html += '</tr>';
var row_html = $('#table_body').html();
$('#table_body').html(row_html + table_html);
}
$('.cells_unq').each(function() {
temp_text = $(this).text();
$(this).text('Name' + temp_text);
});
</script>
<style type="text/css">
td {
text-align: center;
}
</style>
</html>

Cannot add value into array in Google Script

I want to add the word "Flag" into column "G" or Array [6] where the corresponding row shows a value greater than 0.5 in column "E" or Array [5]. Note, that Array [6] is empty and only the script can add a value there if condition is met.
Here is my attempt but it does not add the word "Flag" into the cell.
I appreciate any help or pointer. Thanks in advance!
function test() {
var ss=SpreadsheetApp.getActive();
var sh=ss.getSheetByName('Sheet1');
var rg=sh.getDataRange()
var vA=rg.getValues();
var g = [];
for(var i=1;i<vA.length;i++) {
g[i] = [vA[i][6]];
if(Number(vA[i][5])>0.5)g[i] = ['Flag']; {
SpreadsheetApp.getActiveSheet().getRange(2,7,g.length,1).setValues(g);
}}}
The error states:Cannot convert Array to Object[].
Here is an amended version of your code that will work if all your data is plain values and not formulas.
Please note this will overwrite any formulas.
function test() {
var ss = SpreadsheetApp.getActive();
var sh = ss.getSheetByName('Sheet1');
var rg = sh.getDataRange();
var vA = rg.getValues();
for (var i = 1; i < vA.length; ++i) {
if (Number(vA[i][5]) > 0.5) {
vA[i][6] = 'Flag';
//change value of array element
}
}
rg.setValues(vA);
//set changed values to source range
}
Edit
This checks column F and makes changes to column G.
It will not overwrite the formulas in column F, but it will overwrite any formulas in column G.
function test() {
var ss = SpreadsheetApp.getActive();
var sh = ss.getSheetByName('Sheet1');
var lastRow = sh.getLastRow();
var checkRg = sh.getRange('F2:F' + lastRow);
var flagRg = sh.getRange('G2:G' + lastRow);
var checkVa = checkRg.getValues();
var flagVa = flagRg.getValues();
for (var i = 0; i < checkVa.length; ++i) {
if (Number(checkVa[i][0]) > 0.5) {
flagVa[i][0] = 'Flag';
//change value of array element
}
}
flagRg.setValues(flagVa);
//set changed values to source range
}
Not sure what is in columns A thru F and beyond G.
for(var i=1;i<vA.length;i++) {
if(Number(vA[i][5])>0.5) vA[i][6] = 'Flag';
}
SpreadsheetApp.getActiveSheet().getDataRange.setValues(vA);
Or if you only want to replace G.
var g = [];
for(var i=1;i<vA.length;i++) {
g[i-1] = [vA[i][6]]; // Notice its an array
if(Number(vA[i][5])>0.5) g[i-1] = ['Flag']; // Notice an array again
}
SpreadsheetApp.getActiveSheet().getRange(2,7,g.length,1).setValues(g);

Shift letters from input to the next in alpabhet

I have been searching the web and I have found a few examples about my current problem, and all seems to be addressing the same topic: deciphering text. But I cannot find anything written in javascript. I gave it a shot, but I'm stuck when trying to convert the string in to an array.
Lets say that the current alphabet is
var alpabhet=[
'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','å','ä','ö'
];
And I have a string ammj, that I enter in the input. Then I want to be able to shift with right and left key and view the output of that current shift. So a shift of two (2) would result in the string cool. And a shift of 5 for the string åjjg would also result in cool.
So my main concern is, how can I convert a user input to an array with javascript?
I have a input filed:<input id="text_to_be_shifted" type="text"> and then I'm trying to loop the input and arrange into a array
var values = {};
var inputs = document.getElementById('text_to_be_shifted');
for( var i = 0; i < inputs.length; i++ ) {
values[inputs[i].name] = inputs[i].value;
}
Have a look at my fiddle: http://jsfiddle.net/p8kqmdL1/
Here you have a live and working example, with a check so that shifting letter 'a' with -1 will convert it to last letter of the alphabet 'ö', -2 to 'ä' e.t.c. and shifting last letter of alphabet with 1 will set it to 'a', with 2 to 'b' e.t.c:
var alpabhet=[
'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 values = {};
var inputs = document.getElementById('text_to_be_shifted');
for( var i = 0; i < inputs.length; i++ ) {
values[inputs[i].name] = inputs[i].value;
}
function outputText(number){
var newtext = [];
var inputtext = document.getElementById('text_to_be_shifted').value.split('');
inputtext.forEach(letter=> {
var ind_ofLetter = alpabhet.indexOf(letter);
ind_ofLetter = ind_ofLetter + number;
if (ind_ofLetter < 0){
ind_ofLetter = alpabhet.length + ind_ofLetter;
}else if(ind_ofLetter > alpabhet.length-1){
ind_ofLetter = ind_ofLetter - alpabhet.length;
}
newtext.push(alpabhet[ind_ofLetter]);
});
document.getElementsByClassName('output')[0].innerHTML = newtext.join('');
}
function shiftUp() {
var currentShift = document.getElementById('currentShift');
var number = currentShift.innerHTML;
number++;
currentShift.innerHTML = number;
outputText(number);
}
function shiftDown() {
var currentShift = document.getElementById('currentShift');
var number = currentShift.innerHTML;
number--;
currentShift.innerHTML = number;
outputText(number);
}
document.onkeydown = checkKey;
function checkKey(e) {
e = e || window.event;
if (e.keyCode == '37') {
console.log('left arrow')
shiftDown()
}
else if (e.keyCode == '39') {
console.log('right arrow')
shiftUp()
}
}
<b>Current shift: </b><span id="currentShift">0</span>
<br><input id="text_to_be_shifted" type="text">
<div id='output' class="output"></div>
There is only one input, so there is no point in looping over it.
To get an array, you should use something like:
document.getElementById('text_to_be_shifted').split("");
You can then use the map function to shift the elements
let arr = document.getElementById('text_to_be_shifted').split("");
let shifted = arr.map((c) => alpabhet[(alpabhet.indexOf(c) + 1) % alpabhet.length]).join("");
in your for loop you can utilize the charAt() function to get the individual character at a given index. W3 schools has a good lesson on this function if needed: https://www.w3schools.com/jsref/jsref_charat.asp
var inputArray = [];
var inputs = document.getElemenById('text_to_be_shifted');
for(let i = 0; i < inputs.length; i++){
inputArray[i] = inputs.charAt(i);
}
Something like this should work to get you an array with a single letter at each index.

split not working for second time

Unable to split same string for two times.What i am doing wrong?
// my original string
var str = "Left,Right-broken at left side";
var ary = "Left,Right-broken at left side";
//getting text after - (working fine)
var res = str.split("-").pop();
$('#disc_comm_tlside_ed').empty();
$('#disc_comm_tlside_ed').val(res);
// with this i can get text before -once again i need to splt by comma only
var myarrays= str.substr(0, str.indexOf('-'));
//even this also returning original string
var splt = ary.split(',');
// alert(splt) when i alert this getting full string
for(var i = 0; i < splt.length; i++)
{
//alert(myarray[i]);
$(this).find("option[value ='"+myarray[i]+"']").attr("selected",true);
$('.batch_ed').multiselect('rebuild');
}
Finally returning original string!!
Need to get text before-and split text separated by ,
need to get left and right only as array
Edit: adding the code snippet posted in the comment.
var elements = "";
var batchnoe= "";
$.each(data.response.frc_disloc, function (a,b){
batchnoe = '.batch_ed';
$(batchnoe).each(function(i, obj) {
var batch_splt = b.frac_side;
var myarray = batch_splt.split(',');
for(var i = 0; i < myarray.length; i++) {
$(this).find("option[value ='"+myarray[i]+"']").attr("selected",true); $('.batch_ed').multiselect('rebuild');
}
});
});
please check console logs for the output.
// my original string
var str = "Left,Right-broken at left side";
var ary = "Left,Right-broken at left side";
//getting text after - (working fine)
var res = str.split("-").pop();
$('#disc_comm_tlside_ed').empty();
$('#disc_comm_tlside_ed').val(res);
// with this i can get text before -once again i need to splt by comma only
var myarrays= str.substr(0, str.indexOf('-'));
//even this also returning original string
var splt = myarrays.split(',');
console.log(splt);
// alert(splt) when i alert this getting full string
for(var i = 0; i < splt.length; i++)
{
console.log(splt[i]);
$(this).find("option[value ='"+splt[i]+"']").attr("selected",true);
//$('.batch_ed').multiselect('rebuild');
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="disc_comm_tlside_ed"></div>

How to get numbers from string in Javascript?

I have a strings that can look like this:
left 10 top 50
How can i extract the numbers, while the numbers can range from 0 to 100 and words can be left/right top/bottom? Thanks
Try match()
var text = "top 50 right 100 left 33";
var arr = text.match(/[0-9]{1,3}/g);
console.log(arr); //Returns an array with "50", "100", "33"
You can also use [\d+] (digits) instead of [0-9]
Place this string in a var, if you know every number will be seperated by a space you can easely do the following:
var string = "top 50 left 100";
// split at the empty space
string.split(" ");
var numbers = new Array();
// run through the array
for(var i = 0; i < string.length; i++){
// check if the string is a number
if(parseInt(string[i], 10)){
// add the number to the results
numbers.push(string[i]);
}
}
Now you can wrap the whole bit in a function to run it at any time you want:
function extractNumbers(string){
var temp = string.split(" ");
var numbers = new Array();
for(var i = 0; i < temp.length; i++){
if(parseInt(temp[i], 10)){
numbers.push(temp[i]);
}
}
return numbers;
}
var myNumbers = extractNumbers("top 50 left 100");
Update
After reading #AmirPopovich s answer, it helped me to improve it a bit more:
if(!isNaN(Number(string[i]))){
numbers.push(Number(string[i]));
}
This will return any type of number, not just Integers. Then you could technically extend the string prototype to extract numbers from any string:
String.prototype.extractNumbers = function(){ /*The rest of the function body here, replacing the keyword 'string' with 'this' */ };
Now you can do var result = "top 50 right 100".extractNumbers();
Split and extract the 2nd and 4th tokens:
var arr = "left 10 top 50".split(" ");
var a = +arr[1];
var b = +arr[3];
var str = 'left 10 top 50';
var splitted = str.split(' ');
var arr = [];
for(var i = 0 ; i < splitted.length ; i++)
{
var num = Number(splitted[i]);
if(!isNaN(num) && num >= 0 && num <= 100){
arr.push(num);
}
}
console.log(arr);
JSFIDDLE
If you want it dynamically by different keywords try something like this:
var testString = "left 10 top 50";
var result = getNumber("top", testString);
function getNumber(keyword, testString) {
var tmpString = testString;
var tmpKeyword = keyword;
tmpString = tmpString.split(tmpKeyword + " ");
tmpString = tmpString[1].split(' ')[0];
return tmpString;
}
var myArray = "left 10 top 50".split(" ");
var numbers;
for ( var index = 0; index < myArray.length; index++ ) {
if ( !isNaN(myArray[index]))
numbers= myArray[index]
}
find working example on the link below
http://jsfiddle.net/shouvik1990/cnrbv485/

Categories