Javascript: using a for statement as a variable - javascript

I'm fairly new to javascript and something I've been playing with lately is the 'for' statement. I'm questioning one thing, though. I've learned how to make a 'for' statement do things as if it was an output, like this:
for (i = 0; i < 3; i++) {
console.log(i);
}
But what if you want to set a variable for the whole output of the 'for' statement?
var destinationArray = ["town", "areas", "bosses"];
var destinationArraySet = 1;
var i;
for ( i = 0; i < destinationArraySet; i++) {
console.log(destinationArray[i]);
} /*the whole thing should be equal to var destination */
var userDestinationPrompt = ("Where would you like to go? Available places: " +
/* var destination */
+
".").toUpperCase();
To give some more context: I'm making a game that allows further destinations when the destination before is cleared. Once that's achieved, I set destinationArraySet to a higher value, which means that more places would be logged and put after 'Available places'.
Help would be very appreciated! If there's something not clear enough let me know.

The for statement is not an expression, so it doesn't have a return value. Use a variable to collect values in the loop:
var destination = '';
for (var i = 0; i < destinationArraySet; i++) {
destination += destinationArray[i] + ' ';
}
Of course, if you only want to concatenate the values in part of an array, you can use the slice method to get part of it, then the join method:
var destination = destinationArray.slice(0, destinationArraySet).join(' ');

var destination = '';
var destinationArray = ["town", "areas", "bosses"];
var destinationArraySet = 1;
for (var i = 0; i < destinationArraySet; i++) {
destination += destinationArray[i] + '\n';
}
console.log(destination);

Try this -
var destinationArray = ["town", "areas", "bosses"];
var destinationArraySet = 1;
var i;
var availablePlaces = '';
var separator = '';
for ( i = 0; i < destinationArraySet; i++) {
availablePlaces += separator + destinationArray[i];
separator = ', ';
}
var userDestinationPrompt = ("Where would you like to go? Available places: " +
availablePlaces + ".").toUpperCase();

The for statement doesn't have an "output", it's not a function. Thinking for as a function will give you troubles later on. for is simply a statement that continuously execute the block of code inside. It does not "output", or in other words, return any value.
Do this instead:
var destinationArray = ["town", "areas", "bosses"], destinationArraySet = 1;
var userDestinationPrompt = ("Where would you like to go? Available places: " +
destinationArray.slice(0, destinationArraySet).join("\n")
+ ".").toUpperCase();
prompt(userDestinationPrompt);
Demo: http://jsfiddle.net/7c2b9q7m/1/
destinationArray.slice(0, destinationArraySet): Cuts the array to the specified length.
.join("\n"): Join the newly created array by \ns (newline) to micic the default console.log behavior.

Related

Looping through a table rows with comparisons using VUgen

I have a table I need to compare each of the values within to an existing parameter.
I have this Xpath here: //*[#id="maincontent"]/messages/div/div[1]/div[1]/table/tbody/tr[1]/td[4]/div/span
and would like to insert an increment variable from the loop to go through the /tr/ in the table only.
Here is what i have so far:
var i;
var max = 10;
var xpathleft = `*[#id="maincontent"]/messages/div/div[1]/div[1]/table/tbody/tr[`;
var xpathright = `]/td[4]/div/span`;
for (i = 1; i < max, i++)
{
var currentXpath = string.concat(xpathleft, i, xpathright);
}
if (currentXpath.innerHTML == PartnerIDs)
{
lr_log_message("Match Found!");
}
This is currently sitting in an Evaluate Javascript step in TruClient/VUgen and is giving me Syntax Error: Unexpected Token )
The element here doesn't have any ID I can reference and looks like this: Partner ID
and has been difficult to pull the needed Partner ID text within code.
Some of your JavaScript syntax is incorrect.
Try this:
var i;
var max = 10;
var xpathleft = `*[#id="maincontent"]/messages/div/div[1]/div[1]/table/tbody/tr[`;
var xpathright = `]/td[4]/div/span`;
for (i = 1; i < max; i++){
var currentXpath = `${xpathleft}${i}${xpathright}`;
if (currentXpath.innerHTML == PartnerIDs) {
lr_log_message("Match Found!");
}
}

How to generate an array of Images using for loop in javascript?

I'm trying to write an array of images, but I have a lot of images so I'm trying to use "for loop" to generate it.
my current code is :
var images = [
"/images/image0000.png",
"/images/image0005.png",
"/images/image0010.png",
"/images/image0015.png",
"/images/image0020.png",
"/images/image0025.png",
"/images/image0030.png",
"/images/image0040.png",
"/images/image0045.png",
"/images/image0050.png"
];
I have more images to add. so I would like to know how to use for loop to generate this.
The last image is /images/image3360.png
Thank you!
I think you don't want to generate the actual images, but rather fill an array with filenames. The simplest way would be:
const MAX = 3360;
const PREFIX = "/images/image";
const EXT = ".png";
const arr = [];
for (let i = 0; i <= MAX; i += 5) {
arr.push(
PREFIX + ("0000" + i).slice(-4) + EXT
);
}
The slice thing comes from this answer.
const step = 5; // Steps
const imgNumber = 3360/step; // Image number
const images = []; // Array to hold images
for(i = 0; i<=imgNumber; i++) {
const currNum = i*step; // Calculate suffix
let str = "/images/image0000";
str = str.substring(0, str.length - currNum.toString().length); // Compile number
images.push(`${str}${currNum}.png`); // Store the image in the array
}
console.log(images);
You can do it like this:
let images = [];
for (let i = 0; i <= 3360; i += 5) {
let imageString = "";
let numberOfZeros = 4 - i.toString().length;
for (let j = 0; j < numberOfZeros; j++) {
imageString += "0";
}
images.push("/images/image" + imageString + i.toString() + ".png");
}
This essentially runs a for loop which increments by 5 each time, calculates the amount of leading zeros needed, then runs another for loop to add these leading zeros, and inserts a concatenation of this and the actual number inside the string which gets pushed to the array.

Perform a merge on two strings

I'm trying to build a collaborative doc editor and implement operational transformation. Imagine we have a string that is manipulated simultaneously by 2 users. They can only add characters, not remove them. We want to incorporate both of their changes.
The original string is: catspider
The first user does this: cat<span id>spider</span>
The second user does this: c<span id>atspi</span>der
I'm trying to write a function that will produce: c<span id>at<span id>spi</span>der</span>
The function I've written is close, but it produces c<span id>at<span i</span>d>spider</span> codepen here
String.prototype.splice = function(start, newSubStr) {
return this.slice(0, start) + newSubStr + this.slice(start);
};
function merge(saved, working, requested) {
if (!saved || !working || !requested) {
return false;
}
var diffSavedWorking = createDiff(working, saved);
var diffRequestedWorking = createDiff(working, requested);
var newStr = working;
for (var i = 0; i < Math.max(diffRequestedWorking.length, diffSavedWorking.length); i++) {
//splice does an insert `before` -- we will assume that the saved document characters
//should always appear before the requested document characters in this merger operation
//so we first insert requested and then saved, which means that the final string will have the
//original characters first.
if (diffRequestedWorking[i]) {
newStr = newStr.splice(i, diffRequestedWorking[i]);
//we need to update the merge arrays by the number of
//inserted characters.
var length = diffRequestedWorking[i].length;
insertNatX(diffSavedWorking, length, i + 1);
insertNatX(diffRequestedWorking, length, i + 1);
}
if (diffSavedWorking[i]) {
newStr = newStr.splice(i, diffSavedWorking[i]);
//we need to update the merge arrays by the number of
//inserted characters.
var length = diffSavedWorking[i].length;
insertNatX(diffSavedWorking, length, i + 1);
insertNatX(diffRequestedWorking, length, i + 1);
}
}
return newStr;
}
//arr1 should be the shorter array.
//returns inserted characters at their
//insertion index.
function createDiff(arr1, arr2) {
var diff = [];
var j = 0;
for (var i = 0; i < arr1.length; i++) {
diff[i] = "";
while (arr2[j] !== arr1[i]) {
diff[i] += arr2[j];
j++;
}
j++;
}
var remainder = arr2.substr(j);
if (remainder) diff[i] = remainder;
return diff;
}
function insertNatX(arr, length, pos) {
for (var j = 0; j < length; j++) {
arr.splice(pos, 0, "");
}
}
var saved = 'cat<span id>spider</span>';
var working = 'catspider';
var requested = 'c<span id>atspi</span>der';
console.log(merge(saved, working, requested));
Would appreciate any thoughts on a better / simpler way to achieve this.

Syntax to build object properties in loop - javascript

I would like to loop through a list of objects and display one property on a graph on the page but I can't seem to get the right syntax to get this data in a loop.
Without the loop this gives an idea of what I want to do:
document.getElementById("v1").innerHTML = zone1.sensor;
document.getElementById("v2").innerHTML = zone2.sensor;
document.getElementById("v3").innerHTML = zone3.sensor;
I can't figure out how to loop through the objects, something like this:
for(i = 1; i < 7; i++) {
document.getElementById("v" + i).innerHTML = ("zone" + i + ".sensor");
}
While that can be done with eval() or new Function (), that's just plain wrong. Put your values in an array and access them by index. If you absolutely have to use independent variables, do:
var arr = [zone1, zone2, zone3];
and then use
arr[i].sensor
I would go this way to avoid the use of eval:
var zone1 = new Object;
var zone2 = new Object;
var zone3 = new Object;
zone1.sensor = "sensor1";
zone2.sensor = "sensor2";
zone3.sensor = "sensor3";
var zones = [zone1, zone2, zone3];
for( var i = 1; i < 4; i++) {
document.getElementById("v" + i).innerHTML = zones[i - 1]["sensor"];
}
<div id="v1"></div>
<div id="v2"></div>
<div id="v3"></div>
Hope it helps!

textarea duplicate string check ignoring leading and trailing whitespace

Users will enter various serials in a textarea. Each newline will indicate a new serial. Some requirements/restrictions:
Leading and trailing white spaces are not allowed.
White space within a serial is okay.
Blank serials are not allowed
I'd prefer to not use JQuery.
Store duplicates so they can be shown to the user.
Based on my tests I have a working solution. I want to make sure I'm not missing or overlooking anything. My questions are:
Is there a more efficient ways to check for duplicates?
Are there any glaring test cases that my solution won't catch?
Working Example: http://jsbin.com/ivusuj/1/
function duplicateCheck() {
var output = document.getElementById('Output');
output.innerHTML = '';
var duplicateSerials = [];
var count = 0;
var textArea = document.getElementById('Serials');
var serials = textArea.value.trim().split(/ *\n */);
for(var i = 0;i < serials.length;i++){
var serial = serials[i];
if(serials.indexOf(serial) != serials.lastIndexOf(serial) &&
duplicateSerials.indexOf(serial) == -1 && serial !== '') {
duplicateSerials.push(serial);
}
}
// For testing
output.innerHTML = '<pre>Serials:\t' + serials.toString() + "<br />" +
'Duplicates:\t' + duplicateSerials.toString() + "<br>" +
'</pre>';
}
Note: the above is for a client side check. The same check will be performed server side as well to ensure the data is valid.
Update
Solution comparison: http://jsbin.com/ivusuj/4/edit
I put together a jsfiddle her: http://jsfiddle.net/wrexroad/yFJjR/3/
Actually checking for duplicates that way is pretty inefficient.
Instead of checking for duplicates, this just adds a property to an object where the property's name is is the serial. Then it prints out all of the property names.
This way if you have duplicates, it will just create the property, then overwrite it.
Here is the function:
function duplicateCheck() {
var output = document.getElementById('Output');
output.innerHTML = '';
var textArea = document.getElementById('Serials');
var inputSerials =
textArea.value.trim().split(/ *\n */);
var outputSerials = new Object();
for(var i = 0;i < inputSerials.length;i++){
var serial = inputSerials[i];
//build an object whose properties are serials
//if the serial exists, incremint a counter
if(outputSerials[serial]){
outputSerials[serial]++;
}else{
outputSerials[serial] = 1;
}
}
output.innerHTML =
'Serials: <br />';
for(var i in outputSerials){
output.innerHTML += i + " ";
}
output.innerHTML +=
'<br /><br />Duplicate Serials: <br />';
for(var i in outputSerials){
//check to see if we have any duplicates
if(outputSerials[i] > 1){
output.innerHTML += i + " ";
}
}
}
I think you'd get significantly better performance if you used an object to determine which serials you'd seen before. Something closer to this:
var seen = {};
for (var i = 0, j = serials.length; i < j; ++i) {
var serial = serials[i];
if (seen.hasOwnProperty(serial)) {
// Dupe code goes here.
continue;
}
// Can't be a duplicate if we get to this point.
}
Though that won't work with serials that use periods.
Here's a solution to filter out duplicates.
function formatInput() {
var arrUnique = [], dups = [],
str = document.getElementById('Serials').value
.replace(/\r\n?/g,'\n')
// normalize newlines - not sure what PC's
// return. Mac's are using \n's
.replace(/(^((?!\n)\s)+|((?!\n)\s)+$)/gm,'')
// trim each line
.replace(/^\n+|\n+$|\n+(?=\n(?!\n))/g,''),
// delete empty lines and trim the whole string
arr = str.length ? str.split(/\n/) : [];
// split each line, if any
for (var i = 0; i < arr.length; i++) {
if (arrUnique.indexOf(arr[i]) == -1)
arrUnique.push(arr[i]);
else dups.push(arr[i]);
}
//document.getElementById('Serials').value = arrUnique.join('\n');
console.log('serials:', arr);
console.log('unique:', arrUnique);
console.log('duplicates:', dups);
}

Categories

Resources