Javascript - IndexOf is returning random numbers - javascript

I'm trying to generate a random number between 1-75, then compare it to an array so that I can later use the result as an argument for an if / else statement; (i.e., if the number is in the array, do this, otherwise do that.)
Here is the relevant code:
var pickable = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75];
var grid = [7,14,8,10,4,25,18,20,26,27,37,33,40,45,32,48,55,49,52,53,61,63,74,73,67];
function pick()
{
var temp1 = Math.floor(Math.random() * (pickable.length));
var temp2 = temp1.toString();
var check = grid.indexOf(temp2);
alert (check + "\n" + grid);
}
But this code isn't giving me index numbers that make sense; It returns -1 when the number is clearly in the array, returns other numbers for numbers that are not in the array, or returns a number that has no obvious relationship to the position of the number in the array. Why is this not working, and what would work better? Please keep in mind, I'm just learning to code, so detailed explanations are appreciated.
After a bit of experimenting, I've found that what it is doing is picking the random number, writing it to the appropriate places on the screen, then subtracting the number of iterations of the loop before using that number to check the index. (I think.) In other words, the first time I cick the button, it displays 48 on the screen, but searches the index for 47. The next time I click the button it displays 56, but searches for 54, etc. Here is the entire function:
function pick()
{
if (pickable.length > 0)
{
var temp1 = Math.floor(Math.random() * (pickable.length));
var temp2 = temp1.toString();
var check = grid.indexOf(temp2);
alert ("index: " + check + "\nball: " + temp1 + "\n");
document.getElementById("ballNum").innerHTML = pickable[temp1];
pickable[temp1] = pickable[0];
pickable.shift();
picked.push(document.getElementById("ballNum").innerHTML);
document.getElementById("pickedNums").innerHTML = picked.join("| ");
}
else
{
alert("You are out of Bingo balls! \nPlease start over by clicking the " +
" \n\"Populate Board\" button.");
}
}

Related

Generating user id based on some input values

I came across this question on Mettl :
The function takes four parameters -
first name(String)
last name(String)
pin(int) : a number that contains digits of any length
eg: 1234,34565789
number(int) : a number(1-9 both inclusive and less than the length of the pin) that determines the number of digits that has to be used for the generation of id, from the beginning and the end of the pin entered above.
Conditions for generating the id are:
the name with smaller length is taken as the small name and the name with bigger length is taken as large name.
if the lengths of both the first and last name are equal, then the name occurring alphabetically first is taken as the small name.
the number for the generation is obtained using the 'number' and 'pin' inputs.
after the id is generated the letters are toggled,i.e the lowercase letters are changed to uppercase and vice-versa.
Example 1:
first name: Rajiv
last name: Roy
pin: 123456
number: 3
Here 'Roy' is smaller in length than 'Rajiv'. So 'Roy' becomes the small name and 'Rajiv' becomes the large name. The 3rd digit from starting of the pin is '3' and the 3rd digit from the end of the pin is '4'. Therefore the number generated is 34.
The last letter of smaller name is 'y'. So the id generated is yRajiv34.
After toggling the letters, the final id generated is YrAJIV34.
function generateId(firstName, lastName, pin, n) {
var result = '';
var smallName = '';
var largeName = '';
if (firstName.length != lastName.length) {
if (firstName.length < lastName.length) {
smallName = firstName;
largeName = lastName;
} else {
largeName = firstName;
smallName = lastName;
}
} else {
var names = [firstName.toLowerCase(), lastName.toLowerCase()];
var sorted = names.sort(function (a, b) {
return a > b;
});
smallName = sorted[0];
largeName = sorted[1];
}
result += smallName.substr(smallName.length - 1, 1).toUpperCase();
result += largeName.substr(0, 1).toLowerCase() + largeName.substr(1, largeName.length).toUpperCase();
var pinString = pin.toString();
var numberLength = pinString.length;
result += pinString.charAt(n - 1) + pinString.charAt(numberLength - n);
return result;
}
var x = generateId('Kumar', 'Kumud', 530076, 2);
console.log(x);
var y = generateId('Rajiv', 'Roy', 345678, 3);
console.log(y);
problem:
its working well for all the test cases I pass and even got 7/10 test cases correct in the mettl site. I don't know what the reason is for the failure of the remaining 3 test cases. Is there a way to improve the algorithm or anything wrong with my code?
You are not toggling the characters, you are just assuming that first character of the string will be uppercase and making it lower case and all other characters will be in lower case and making them uppercase.
This won't work for cases such as:
generateId('RajIV', 'Roy', 345678, 6); // YrAJIV83
Also you are not handling the case where number is greater than the length of pin. It still gives an output.
generateId('RajIV', 'Roy', 345678, 7); // YrAJIV

Hacker Rank Annagrams

I am trying to solve the problem described here with JavaScript...
https://www.hackerrank.com/challenges/ctci-making-anagrams
I have to output the number of letters that would need to be removed from two strings in order for there to only be matching letters (compare the two strings for matching letters and total the letters that don't match)
for example...
string a = cbe
string b = abc
the only matching letter is between both strings is the two c's so I would be removing 4 letters (beab).
My code works, but it seems to keep timing out. If I download the individual test case instances, I seem to fail when variables a and b are set to large strings. If I test these individually, I seem to get the right output but i still also get the message "Terminated due to timeout".
I'm thinking it might be obvious to someone why my code timesout. I'm not sure it's the most elegant way of solving the problem but I'd love to get it working. Any help would be much appreciated...
function main() {
var a = readLine();
var b = readLine();
var arraya = a.split('');
var arrayb = b.split('');
var arraylengths = arraya.length + arrayb.length;
//console.log(arraylengths);
if (arraya.length <= arrayb.length) {
var shortestarray = arraya;
var longestarray = arrayb;
} else {
var shortestarray = arrayb;
var longestarray = arraya;
}
var subtract = 0;
for (x = 0; x < shortestarray.length; x++) {
var theletter = shortestarray[x];
var thenumber = x;
if (longestarray.indexOf(theletter, 0) > -1) {
var index = longestarray.indexOf(theletter, 0);
longestarray.splice(index, 1);
subtract = subtract + 2;
}
}
var total = arraylengths - subtract;
console.log(total);
}
Your algorithm is good. It's straight forward and easy to understand.
There are certain things you can do to improve the performance of your code.
You don't have to calculate the indexOf operation twice. you can reduce it to one.
the splice operation is the costliest operation because the JS engine has to delete the element from an array and reassign the indexes of all the elements.
A point to be noted here is that the JS engine does an extra step of correcting the index of the array, which is not required for your purpose. So you can safely remove longestarray.splice(index, 1); and replace it with delete longestarray[index]
Here is a snippet which will increase your performance of the code without changing your logic
for (var x = 0; x < shortestarray.length; x++) {
var theletter = shortestarray[x];
var thenumber = longestarray.indexOf(theletter, 0); // <-- check only once
if (thenumber > -1) {
var index = thenumber;
delete longestarray[index]; // <-- less costlier than splice
subtract = subtract + 2;
}
}
Note: I am not suggesting you to use delete for all the cases. It's useful here because you are not going to do much with the array elements after the element is deleted.
All the best. Happy Coding
I would suggest you hashing. make the characters of string key and its numbers of occurrences value. Do the same for both strings. After that take string 1 and match the count of its every character with the count of same character in string then calculate the difference in the number of occurrences of the same character and delete that character till the difference becomes 0 and count that how many times you performed delete operation.
ALGORITHM:
step 1: Let arr1[255]= an integer array for storing the count of string1[i]
and initialized to zero
ex: string1[i]='a', then arr1[97]=1, because ASCII value of a is 97
and its count is 1. so we made hash table for arr1 where key is
ASCII value of character and value is its no of occurrences.
step 2: Now declare an another array of same type and same size for string 2
step 3: For i=0 to length(string1):
do arr1[string1[i]]++;
step 4: For i=0 to length(string2):
do arr2[string2[i]]++;
step 5: Declare an boolean char_status[255] array to check if the
character is visited or not during traversing and initialize it to
false
step 6: set count=0;
step 7: For i=0 to length(string1):
if(char_status[string1[i]]==false):
count=count+abs(arr1[string1[i]]-arr2[string1[i]])
char_status[string1[i]]=true
step 8: For i=0 to length(string2):
if(char_status[string2[i]]==false):
count=count+abs(arr1[string2[i]]-arr2[string2[i]])
char_status[string2[i]]=true
step 9: print count
I have applied this algo just now and passed all test cases. You may improve this algo more if you have time.

JAVASCRIPT Data Type Issue

I am currently learning JS and when I do some practice, I find some issues I am unclear on data type in Javascript. I understand that JS do NOT require specific type indication, it will automatically do the type conversion whenever possible. However, I suffer one problem when I do NOT do type conversion which is as follows:
var sum = 0;
function totalSum (a) {
if (a == 0) {
return sum;
}
else {
sum += a;
return totalSum(--a);
}
}
var i = prompt("Give me an integer");
// var num = parseInt(i);
alert("Total sum from 1 to " + i + " = " + totalSum(i));
// alert("Total sum from 1 to " + i + " = " + totalSum(num));
I notice that the code works perfectly if I change the data type from string to int using parseInt function, just as the comment in the code does. BUT when I do NOT do the type conversion, things are getting strange, and I get a final result of 054321, if I input the prompt value as 5. AND in a similar way, input of 3, gets 0321 and so on.
Why is it the case? Can someone explain to me why the totalSum will be such a number? Isn't javascript will automatically helps me to turn it into integer, in order for it to work in the function, totalSum?
The sample code can also be viewed in http://jsfiddle.net/hphchan/66ghktd2/.
Thanks.
I will try to decompose what's happening in the totalSum method.
First the method totalSum is called with a string as parameter, like doing totalSum("5");
Then sum += a; (sum = 0 + "5" : sum = "05") (note that sum become a string now)
then return totalSum(--a);, --a is converting the value of a to a number and decrement it's value. so like calling return totalSum(4);
Then sum += a (sum = "05" + 4 : sum = "054") ...
See the documentation of window.prompt: (emphasis mine)
result is a string containing the text entered by the user, or the value null.

Javascript prompt and alert inputting a number and it will loop and you will input numbers to get the average of it

I have below javascript code with loop but I can't get the average of it. I'm not sure what's wrong with my code. It's like the first prompt you will input a number and it will loop and you input numbers like how much you entered and you will get the sum of all the numbers and get the average of it after it's done. Here's the code that I have.
function show_prompt()
{
var n=prompt("Input a number: ", "Number here");
if (n==n)
{
var i=1;
do
{
var g=prompt("Input grade: " );
var grade=parseInt(g);
var total=grade+grade;
i++;
}
while(i<=n);
}
var average=(total)/n;
document.write("Average is: " +average);
}
Thanks in advance!
You are overriding your "total" variable in each interval with double the grade value.
var grade=parseInt(g);
var total=grade+grade;
should be changed to
var grade=parseInt(g);
total=total+grade;
Also, you need to initialize the "total" variable in the beginning of your code.
See demo code: http://jsfiddle.net/56ouvan3/1/
I would also recommend some input validation (such as checking that the number of grades requested to average are greater than 0, all grades are positive, etc.)
I think you wanted to accomplish something like that:
http://jsfiddle.net/3L8dL228/1/
Just replace the console.log with your own document.write.
Now, despite I totally hate using prompts and I'm not very used to them, here are you what I think you're missing in your script:
CONTROL: your "n" and "g" variables HAS to be an integers, so force the user to insert an integer.
Variables declaration: you're declaring total every single time you loop, therefore you're not storing anything at all.
To fix these, the very first piece of your code becomes this:
var n = prompt("Input a number: ", "Number here");
while (!parseInt(n) )
{
n=prompt("Input a number: ", "Number here");
}
In this way, you're asking the user to give you a NUMBER, but the script won't procede until it will effectively be able to parse an integer value.
Therefore, inputs like "hey", "hello", "foo", "bar", "baz" won't be accepted.
The second part of your code then becomes this one:
var i=1;
var total = 0;
do
{
var g = prompt("Input grade: " );
while (!parseInt(g)) {
g = prompt("Input grade: " );
}
var grade = parseInt(g);
total += grade;
i++;
}
while(i<=n);
var average=(total)/n;
console.log("Average is: " +average);
and console.log needs to be document.write in your case, but for testing purposes and because jsfiddle (of course) doesn't allow document.write you need to check your console to see the correct value.
What changes from your script to this one is that we are declaring total as a global variable, not as a local variable inside the do loop that will be reset each time you loop.
Next, we're using the same logic as the first prompt for the second one, because you want, again, an integer value, not a possible string like "hey".
After that, we're ADDING that value to the total variable, by not redeclaring it.
Finally, after the loop, we're dividing that global variable total by the global variable n, getting the average.
Try below code to get the average of the entered number.
numGrades = prompt("Enter number of grades to be entered: ");
//number of grades to be entered LOOP
for (index = 1; index <= numGrades; index++) {
numberGrades = prompt("Enter Grade " + index);
}
//Calculation
gradePointAverage = numberGrades / numGrades;
document.write("Your GPA is " + gradePointAverage );

If # is present, calculate the total, if all #s are not calculated, let the total still be calculated

as you can see in the picture, it would be silly for the user to have to type in all 5 Requested Brands (as that is not required). Maybe they only want to choose one Requested Brand. As it is currently set up, the subtotal is only calculated if the user enters 5 unit costs and 5 quantities...not good. If they don't enter all 5, subtotal returns NaN.
$("a#full_sub_total").click(function(event){
event.preventDefault();
var first = $("div#total_result").text();
var second = $("div#total_result1").text();
var third = $("div#total_result2").text();
var fourth = $("div#total_result3").text();
var fifth = $("div#total_result4").text();
$("#full_total_results p").text((parseInt(first,10) + parseInt(second,10) + parseInt(third,10) + parseInt(fourth,10) + parseInt(fifth,10)));
});
Any help is greatly appreciated.
I would loop over the total_result fields, and incrementally add their parsed values to a total var:
$("a#full_sub_total").on("click", function(){
var total = 0;
$("div[id^=total_result]").text(function(i,t){
total += parseInt( t, 10 ) || 0;
});
$(".full_total").text("$" + total);
});
Note the main part of all of this:
total += parseInt( t, 10 ) || 0;
When the attempt to parse an integer from the text of the element fails, we return 0 in its place. This will not offset the total value, and will permit us to continue along with out any NaN showing up later.
Demo: http://jsbin.com/axowew/2/edit
Basic technique:
var sum = 0;
var num1 = parseInt(text1, 10);
if (!isNaN(num1)) sum += num1;
// ...
(Loops: even better idea.)
The problem your overall total results in NaN is that anytime one or more of individual line total is empty, it will cause your overall result total to equal NaN in your attempt to add (i.e. #+#=#, #+NaN=Nan)
Simplify solution to your problem:
$('#subtotal').click(function(e) {
e.preventDefault();
// Clear overall total
$('#overallTotal').empty();
// Loop through each line total
$('div.lineTotal').each(function() {
// If line total is not empty, add
if ($(this).text() != ''){
$('#overallTotal').text(parseInt($('#overallTotal').text) += parseInt($(this).text()));
}
});
});

Categories