Get a limit on arrays (Javascript) - javascript

I've a problem with set a limit into my own lightbox for a gallery
<script>
var imagenumber = 0;
function btnleft(){
load = imagenumber-=1;
document.getElementById('lightboxcontent').innerHTML=imagelist[load];
}
function btnright(){
load = imagenumber+=1;
if (load==undefined){load=imagenumber-=1}
document.getElementById('lightboxcontent').innerHTML=imagelist[load];
}
</script>
Then the array
var imagelist=new Array(); // regular array (add an optional integer
imagelist[0]="image1.jpg"; // argument to control array's size)
imagelist[1]="image2.jpg";
imagelist[2]="image3.jpg";
When I click more then 3 times on the next button I got the error-message "undefined".
How should I do to get a limit on my arrays?

Try it with
function btnleft(){
var load = imagelist[imagenumber-=1];
if (load) // imagenumber in array boundaries
document.getElementById('lightboxcontent').innerHTML = load;
else
imagenumber = 0;
}
function btnright(){
var load = imagelist[imagenumber+=1];
if (load) // imagenumber in array boundaries
document.getElementById('lightboxcontent').innerHTML = load;
else
imagenumber = imagelist.length-1;
}
Yet, Arrays in Javascript have no limited size, they are more like (infinite) lists. You can hardly set a limit on their length - espcially not with the constructor, whose number argument is just for initialisation purposes.
You can use the length property of an array to check whether your index is in the array boundaries: i >= 0 && i < arr.length. My code just checks whether there is an item at that index (as your second function seems to intend, too) and resets the index otherwise.

I assume that clicking on the "next button" calls the btnright() function.
If that is the case then you are testing the wrong value for undefined. You could rewrite your function as:
function btnright(){
load = imagenumber += 1;
// Test the value at the index of the array, not your index variable.
if (imagelist[load] === undefined) {
load = imagenumber-= 1;
}
document.getElementById('lightboxcontent').innerHTML = imagelist[load];
}
Stylistically this is still no the best. Your load variable is not required since its value always duplicates imagenumber. You could refactor the function such:
function btnright() {
// If we have a new array value do something.
if (imagelist[imagenumber + 1] !== undefined) {
// Increment the index and load the new image.
document.getElementById('lightboxcontent').innerHTML = imagelist[++imagenumber];
}
}
function btnleft() {
// If we're not on the first image do something.
if (imagenumber !== 0) {
// Decrement the index and load the new image.
document.getElementById('lightboxcontent').innerHTML = imagelist[--imagenumber];
}
}

Related

Hackerrank: Frequency Queries Timeout

I know that there are plenty of similar questions on SO on this specific thing, but I have a solution that works for all test cases EXCEPT for one (it gets timed out). Is there anyway I can make my code run faster or more efficiently... or do I need to start all over?
My logic:
I create three arrays.
Whenever there is a new value, I add it to my data array. At the same time, I add a "1" to my frequency array. The positions should be the same.
Whenever it is the same value, I simply increase the frequency value for the corresponding value by 1.
Whenever I need to return a value to say whether or not my array has a value with frequency "_", I just indexOf my frequency and tada if it's there I return 0, else I return 1.
function freqQuery(queries) {
var answer = new Array(),
data = new Array(),
frequency = new Array();
for (var i = 0; i < queries.length; i++){
var test = queries[i][0];
if (test == 1) { // first test
var place = data.indexOf(queries[i][1]);
if (place == -1){
data.push(queries[i][1]);
frequency.push(1);
} else {
frequency[place]++;
}
} else if (test == 2) { // second test
var place = data.indexOf(queries[i][1]);
if ((place != -1) && (frequency[place] > 0)) {
frequency[place]--;
}
} else if (test == 3) { // third test
if (frequency.indexOf(queries[i][1]) == -1) {
answer.push(0);
} else {
answer.push(1);
}
}
}
return answer;
}
Link: Hackerrank
Task is in category "Dictionaries and Hashmaps". Instead of data and frequency arrays create object with keys being data values and keys being frequencies. Instead of using indexOf which is O(n) you would be doing frequenciesMap[queries[i][1]] which is O(1).

Is there a function for retrieving last array's element value?

I have an array of inputs that accepts a range of 0 and 1. var array = [0,1,0,0,1];//that is not static
Is there a function for retrieving the last element of the array?
function myfn(){
var array = [1,0,0,0,1,0]; //that may change depending on the user inputs
var b= 0;
let l = array.length;
for(b=0; b<l; b++)
if(array [l-1]==0)
document.getElementById('print').textContent = 'Last element is 0';
}//end function
P.S: I am editing this old and bad question in order to get give the community time to re-evaluate it.
Please try this
function myfn(){
var array = [1,0,0,0,1,0]; //that may change depending on the user inputs
var b=0;
if(array[array.length-1] == 0)
document.getElementById('print').textContent = 'Last element is 0';
}
You could take the length of the array and reduce it by 1 and take the element at this position for checking. You need no loop for the access.
if (array[array.length - 1] === 0) {
Doesn't really need a function, you can even write it inline.
function last_element_is_0(arr){
return !arr[arr.length -1]
}
function myfn(){
var array = [1,0,0,0,1,0]; //that may change depending on the user input
if(last_element_is_0(array))
document.getElementById('print').textContent = 'Last element is 0';
}

How to generate a new random number (that's different from the previous random number)

I'm trying to change the following (that currently returns a random number from an array), so that each random number is different from the last one chosen.
function randomize(arr) {
return arr[Math.floor(Math.random()*arr.length)];
}
oracleImg = [];
for (var i=1;i<=6;i++) {
oracleImg.push(i);
}
randOracleImg = randomize(oracleImg);
I tried the following, but it's not always giving me a number different from the last number.
function randomize(arr) {
var arr = Math.floor(Math.random()*arr.length);
if(arr == this.lastSelected) {
randomize();
}
else {
this.lastSelected = arr;
return arr;
}
}
How can I fix this?
Your existing function's recursive randomize() call doesn't make sense because you don't pass it the arr argument and you don't do anything with its return value. That line should be:
return randomize(arr);
...except that by the time it gets to that line you have reassigned arr so that it no longer refers to the original array. Using an additional variable as in the following version should work.
Note that I've also added a test to make sure that if the array has only one element we return that item immediately because in that case it's not possible to select a different item each time. (The function returns undefined if the array is empty.)
function randomize(arr) {
if (arr.length < 2) return arr[0];
var num = Math.floor(Math.random()*arr.length);
if(num == this.lastSelected) {
return randomize(arr);
} else {
this.lastSelected = num;
return arr[num];
}
}
document.querySelector("button").addEventListener("click", function() {
console.log(randomize(["a","b","c","d"]));
});
<button>Test</button>
Note that your original function seemed to be returning a random array index, but the code shown in my answer returns a random array element.
Note also that the way you are calling your function means that within the function this is window - not sure if that's what you intended; it works, but basically lastSelected is a global variable.
Given that I'm not keen on creating global variables needlessly, here's an alternative implementation with no global variables, and without recursion because in my opinion a simple while loop is a more semantic way to implement the concept of "keep trying until x happens":
var randomize = function () {
var lastSelected, num;
return function randomize(arr) {
if (arr.length < 2) return arr[0];
while (lastSelected === (num = Math.floor(Math.random()*arr.length)));
lastSelected = num;
return arr[num];
};
}();
document.querySelector("button").addEventListener("click", function() {
console.log(randomize(["a","b","c","d"]));
});
<button>Test</button>
Below code is just an example, it will generate 99 numbers and all will be unique and random (Range is 0-1000), logic is simple just add random number in a temporary array and compare new random if it is already generated or not.
var tempArray = [];
var i=0;
while (i != 99) {
var random = Math.floor((Math.random() * 999) + 0);
if (tempArray.indexOf(random)==-1) {
tempArray.push(random);
i++;
} else {
continue;
}
}
console.log(tempArray);
here is a version which will ensure a random number that is always different from the last one. additionally you can control the max and min value of the generated random value. defaults are max: 100 and min: 1
var randomize = (function () {
var last;
return function randomize(min, max) {
max = typeof max != 'number' ? 100 : max;
min = typeof min != 'number' ? 1 : min;
var random = Math.floor(Math.random() * (max - min)) + min;
if (random == last) {
return randomize(min, max);
}
last = random;
return random;
};
})();
If you want to ALWAYS return a different number from an array then don't randomize, shuffle instead!*
The simplest fair (truly random) shuffling algorithm is the Fisher-Yates algorithm. Don't make the same mistake Microsoft did and try to abuse .sort() to implement a shuffle. Just implement Fisher-Yates (otherwise known as the Knuth shuffle):
// Fisher-Yates shuffle:
// Note: This function shuffles in-place, if you don't
// want the original array to change then pass a copy
// using [].slice()
function shuffle (theArray) {
var tmp;
for (var i=0; i<theArray.length;i++) {
// Generate random index into the array:
var j = Math.floor(Math.random()*theArray.length);
// Swap current item with random item:
tmp = theArray[i];
theArray[j] = theArray[i];
theArray[i] = tmp;
}
return theArray;
}
So just do:
shuffledOracleImg = shuffle(oracleImg.slice());
var i=0;
randOracleImg = shuffledOracleImg[i++]; // just get the next image
// to get a random image
How you want to handle running out of images is up to you. Media players like iTunes or the music player on iPhones, iPads and iPods give users the option of stop playing or repeat from beginning. Some card game software will reshuffle and start again.
*note: One of my pet-peeves is music player software that randomize instead of shuffle. Randomize is exactly the wrong thing to do because 1. some implementations don't check if the next song is the same as the current song so you get a song played twice (what you seem to want to avoid) and 2. some songs end up NEVER getting played. Shuffling and playing the shuffled playlist from beginning to end avoids both problems. CD player manufacturers got it right. MP3 player developers tend to get it wrong.

Solving for two variables in the same for loop

So I have a situation in which I have two pieces of data I am trying to get from the same for loop (well I want it to come out of the same for loop to not have repetitive code).
I am searching for the finalFloor my array of data will take me too; but I am also looking for at what index in address[] the variable currentFloor becomes a negative value.
Below is my code and currently I am running this as two separate functions (floorCalculator & inTheBasement) that run identical code (don't want, not good coding practice) except for the end goal of what is being found. I'm really struggling at trying to figure out how to combine this. Any ideas or pointers? Thanks for the help!
/* ----------------- Declaration of Variables ---------------- */
var up = '('; // represents moving up 1 floor.
var down = ')'; // represents moving down 1 floor.
var input_form = $('#input-form'); // represents the html input form.
var userInput = input_form.find('#address-input'); // represents the finding of the user's input.
var input; // stores user input value.
var address = []; // stores user's input value as an array of characters.
var currentFloor = 0; // represents the current floor in the for loop, set to ground floor (0).
var finalFloor; // represents the ending floor from the instructions given.
var results = $('.results'); // represents the div .results for appending data to.
/* ----------------- Parent Function ---------------- */
$(document).ready(initLoad);
/* ----------------- Child Functions ---------------- */
function initLoad()
{
input_form.submit(function(event) // Listens for submission event at #input-form.
{
event.preventDefault(); // Prevents default method of html element.
takeInAddress(); // Calls function.
});
};
function takeInAddress()
{
input = userInput.val(); // Stores the user input found at #address-input as var input.
userInput.val(''); // Clears the input field for next user input.
address = input.split(''); // Splits the string input into single characters stored now in the array address[ ].
floorCalculator(); // Calls funciton.
};
function floorCalculator()
{
for (var i = 0; i < address.length; i++)
{
if (address[i] == up) // For any '(' present at the current index...
{
currentFloor++; // Increase the value of currentFloor by 1.
}
else if (address[i] == down) // For any ')' present at the current index...
{
currentFloor--; // Decrease the value of currentFloor by 1.
}
} // end for loop
finalFloor = currentFloor; // Store the value of currentFloor now as finalFloor.
// console.log(finalFloor);
results.append('<h2>Floor to deliver to: ' + finalFloor + '</h2>'); // Append finalFloor value to .results html.
inTheBasement(); // Calls function.
};
function inTheBasement()
{
currentFloor = 0; // Resets currentFloor to zero.
for (var i = 0; i < address.length; i++)
{
if (address[i] == up) // For any '(' present at the current index...
{
currentFloor++; // Increase the value of currentFloor by 1.
}
else if (address[i] == down) // For any ')' present at the current index...
{
currentFloor--; // Decrease the value of currentFloor by 1.
if (currentFloor < 0) // if currentFloor becomes a negative value...
{
// console.log(i);
// Append value of i
results.append('<h2>When you will arrive in the basement: ' + i + 'th instruction. </h2>');
break; // break from loop
} // end if loop
} // end else if loop
} // end for loop
};
So, your first loop is a classic use case for "reduce": it turns an array into a single value.
reduce takes a function, and an optional base value:
[1,2,1,1].reduce(aFunction, startValue)
We're going to write a function that, when passed to reduce, adds all values of an array together. The function we pass into reduce should accept two values--a 'memo' that will store state between the function calls, and be passed between them, and a 'value' that will represent the next value into the array, passed one by one. It should return whatever the state is after it has taken the value into account, and whatever it returns will be passed into the function again on the next call, along with the next value in the array.
function aFunction(value, memo) {
return value + memo;
}
startValue = 0; // we start with 0 for our use case
We can make the function syntax shorter, like this:
(memo, value) => value + memo
// the return statement is implicit in this syntax
As a result, passing our function and our start value becomes a one liner:
[1,2,1,1].reduce((memo, value) => value + memo, 0)
The only other piece of knowledge necessary is the ternary:
(memo, value) => value === ")" ? memo + 1 : memo - 1
The above is equivalent to:
function (memo, value) {
if (value === ")") {
return memo + 1;
}
else {
return memo - 1;
}
}
Finally, if we want to do this all in one reduce call, we just need to pass a little more state along in our memo, and do another evaluation.
ourInput = ")()()((())))))()()()(".split("");
// it's now an array, as you know
state = { floor: 0, basementTrigger: false, becameNegative: undefined };
result = ourInput.reduce( (memo, value, index) => {
memo.floor += value === "(" ? 1 : -1; // add either 1 or negative one to our floor
if (!memo.basementTrigger && memo.floor < 0) {
memo.becameNegative = index
memo.basementTrigger = true;
}
return memo;
}, state) // state is passed in as 'memo' on the inner functions's first call
For every value, this:
either adds or subtracts from floor, based on whether value is "(".
if the trigger is false, and the floor is negative, it:
flips the trigger to true, and stores the current index
then we just add:
output += ("result = " + result.floor);
if (result.basementTrigger) output += ("follow instruction: " + result.becameNegative)
Hopefully this helps on an alternative take to the question.
disclaimer: did not proofread or test code, may be mistakes; my goal isn't to give you code anyways, but to show you concepts. This is a hacky rendering thrown up quickly, but should illustrate the tools you can use on your own.
Check for currentFloor < 0 in the first for loop. To keep from printing the message twice, use a variable to remember if you already did it.
function floorCalculator()
{
var foundBasement = false;
var basementStep;
for (var i = 0; i < address.length; i++)
{
if (address[i] == up) // For any '(' present at the current index...
{
currentFloor++; // Increase the value of currentFloor by 1.
}
else if (address[i] == down) // For any ')' present at the current index...
{
currentFloor--; // Decrease the value of currentFloor by 1.
if (currentFloor < 0 && !foundBasement) {
foundBasement = true;
basementStep = i;
}
}
} // end for loop
finalFloor = currentFloor; // Store the value of currentFloor now as finalFloor.
// console.log(finalFloor);
results.append('<h2>Floor to deliver to: ' + finalFloor + '</h2>'); // Append finalFloor value to .results html.
if (foundBasement) {
results.append('<h2>When you will arrive in the basement: ' + basementStep + 'th instruction. </h2>');
}
};

How do I correctly use an iteration value in JavaScript?

I am creating a 'simple' javaScript function which basically displays new information on the page when a user clicks next or previous.
The information is taken from an array and I want to use either i++ or i-- to call an element of the array.
Heres my JavaScript:
var titles = ["Dundalk", "Navan", "Drogheda", "Dublin"];
var i = 0;
function next()
{
i++;
if (i == titles.length)
{
i = 0;
}
var object = document.getElementById('tname');
object.innerHTML = titles[i];
}
function prev()
{
if (i == 0)
{
i = titles.length;
}
i--;
var object = document.getElementById('tname');
object.innerHTML = titles[i];
}
The problem is, when I run this code in my HTML page, I get an 'UNDEFINED' result. The JavaScript is not recognizing that i has been initialized as 0 in the beginning.
If i change titles[i] to titles[2], for example, the correct text is displayed in HTML.
What am I forgetting or how can I overcome this?
Thanks
The fact that you're seeing undefined indicates that you're accessing an array index which hasn't been set. Your code looks fine at a glance, so I would guess that there's some more code you're not showing which also uses i as a loop variable and leaves it set to a value > titles.length after the code above has run.

Categories