Iterating GCD function in JavaScript - javascript

I am using this JavaScript function to determine the GCD of two values obtained from input fields:
Math.GCD = function(first,second) {
if (first < 0) first = -first;
if (second < 0) second = -second;
if (second > first) {var temp = first; first = second; second = temp;}
while (true) {
first %= second;
if (first == 0) return second;
second %= first;
if (second == 0) return first;
}
};
I would like to extend this to compute the GCD of three numbers, if the user enters a number into a third input field (otherwise, the user will input two and calculate as per this function). Being relatively new to JavaScript, I am not sure how to extend this function for three values. Can anyone help?
Fiddle: https://jsfiddle.net/tjj7won4/1/
Also, I would like to determine the LCM in a likewise fashion, as observed in the fiddle, but, again, I am unsure how to extend the given function. Please, help.

To extend the function for any number of parameters n, just loop n-1 times over an array of parameters.
This is because mathematically gcd(a,b,c) = gcd(a,gcd(b,c))
Usage: var GCDresult = Math.GCD([16,222,70]); // result: 2.
// numbers is an array of numbers: ex. [15,20,35,170]
Math.GCD = function(numbers) {
for (var i = 1 ; i < numbers.length ; i++){
// take the next number for GCD with the first,
// and store the result back in the first.
numbers[0] = twogcd(numbers[0], numbers[i]);
}
return numbers[0];
// following is your original GCD function
function twogcd(first, second) {
if (first < 0) first = -first;
if (second < 0) second = -second;
if (second > first) {var temp = first; first = second; second = temp;}
while (true) {
first %= second;
if (first == 0) return second;
second %= first;
if (second == 0) return first;
}
}
};
Your JSFiddle, updated for GCD case is here.

You can have something that can accept any number of arguments by using the same function.
And you may extend it too : fiddle
Math.GCDe = function() {
var result = arguments[0];
for (var i=1;i<arguments.length;i++)
result = this.GCD(result,arguments[i]);
return result;
}

Related

Print every value within range iterator generator function javascript

Iterator should print every value within range but its only printing alternate nos.
function iterator(rangeStart, rangeEnd) {
if (rangeStart == 0 && rangeEnd == 0) {
return null;
}
var iterate = function*(start = 0, end = 5, step = 1) {
let iterationcount = 0;
for (let i = start; i <= end; i += step) {
yield i;
iterationCount = i;
}
return iterationCount;
}
var values = iterate(rangeStart, rangeEnd);
var tmp = [];
while (values.next().value != undefined) {
tmp.push(values.next().value);
}
return tmp.join(",");
}
console.log(iterator(0, 10))
expected
[0,1,2,3,4,5,6,7,8,9,10]
Result
[1,3,5,7,9,10]
Every call to next will consume a value from the iterator, so the while condition is consuming a value that will therefore not get into tmp.
But... JavaScript allows you to consume values in much easier ways. For instance with Array.from or spread syntax you can collect all values from the iterator into an array.
Not your question, but:
iterationCount serves no purpose in your code, so just drop that part.
Why would the function behave differently when both range start and end are 0 than when start and end are both 10? I would remove that case. When the range end would be less than the start, it would make sense to exit, but that will happen anyway without any if statement.
The name iterator for your function is somewhat misleading, as the return value is not an iterator, but a comma separated string. I would therefore call it rangeToCsv
function rangeToCsv(rangeStart, rangeEnd) {
var iterate = function*(start = 0, end = 5, step = 1) {
for (let i = start; i <= end; i += step) {
yield i;
}
}
var values = iterate(rangeStart, rangeEnd);
return Array.from(values).join(",");
}
console.log(rangeToCsv(0, 10))

Javascript - For loop vs Linked List vs ES6 Set to find two matching integers

I have prepared 2 Javascript functions to find matching integer pairs that add up to a sum and returns a boolean.
The first function uses a binary search like that:
function find2PairsBySumLog(arr, sum) {
for (var i = 0; i < arr.length; i++) {
for (var x = i + 1; x < arr.length; x++) {
if (arr[i] + arr[x] == sum) {
return true;
}
}
}
return false;
}
For the second function I implemented my own singly Linked List, in where I add the complementary integer to the sum and search for the value in the Linked List. If value is found in the Linked List we know there is a match.
function find2PairsBySumLin(arr, sum) {
var complementList = new LinkedList();
for (var i = 0; i < arr.length; i++) {
if (complementList.find(arr[i])) {
return true;
} else {
complementList.add(sum - arr[i]);
}
}
return false;
}
When I run both functions I clearly see that the Linked List search executes ~75% faster
var arr = [9,2,4,1,3,2,2,8,1,1,6,1,2,8,7,8,2,9];
console.time('For loop search');
console.log(find2PairsBySumLog(arr, 18));
console.timeEnd(‘For loop search’);
console.time('Linked List search');
console.log(find2PairsBySumLin(arr, 18));
console.timeEnd('Linked List search');
true
For loop search: 4.590ms
true
Linked List search: 0.709ms
Here my question: Is the Linked List approach a real linear search? After all I loop through all the nodes, while my outer loop iterates through the initial array.
Here is my LinkedList search function:
LinkedList.prototype.find = function(data) {
var headNode = this.head;
if(headNode === null) {
return false;
}
while(headNode !== null) {
if(headNode.data === data) {
return true;
} else {
headNode = headNode.next;
}
}
return false;
}
UPDATE:
It was a good idea to go back and have another think of the problem based the comments so far.
Thanks to #nem035 comment on small datasets, I ran another test but this time with 100,000 integers between 1 and 8. I assigned 9 to the first and last position and searched for 18 to make sure the entire array will be searched.
I also included the relatively new ES6 Set function for comparison thanks to #Oriol.
Btw #Oriol and #Deepak you are right. The first function is not a binary search but rather a O(n*n) search, which has no logarithmic complexity.
It turns out my Linked List implementation was the slowest of all searches. I ran 10 iterations for each function individually. Here the result:
For loop search: 24.36 ms (avg)
Linked List search: 64328.98 ms (avg)
Set search: 35.63 ms (avg)
Here the same test for a dataset of 10,000,000 integers:
For loop search: 30.78 ms (avg)
Set search: 1557.98 ms (avg)
Summary:
So it seems the Linked List is really fast for smaller dataset up to ~1,000, while ES6 Set is great for larger datasets.
Nevertheless the For loop is the clear winner in all tests.
All 3 methods will scale linearly with the amount of data.
Please note: ES6 Set is not backward compatible with old browsers in case this operation has to be done client side.
Don't use this. Use a set.
function find2PairsBySum(arr, sum) {
var set = new Set();
for(var num of arr) {
if (set.has(num)) return true;
set.add(sum - num);
}
return false;
}
That's all. Both add and has are guaranteed to be sublinear (probably constant) in average.
You can optimize this substantially, by pre-sorting the array and then using a real binary search.
// Find an element in a sorted array.
function includesBinary(arr, elt) {
if (!arr.length) return false;
const middle = Math.floor(arr.length / 2);
switch (Math.sign(elt - arr[middle])) {
case -1: return includesBinary(arr.slice(0, middle - 1), elt);
case 0: return true;
case +1: return includesBinary(arr.slice(middle + 1), elt);
}
}
// Given an array, pre-sort and return a function to detect pairs adding up to a sum.
function makeFinder(arr) {
arr = arr.slice().sort((a, b) => a - b);
return function(sum) {
for (let i = 0; i < arr.length; i++) {
const remaining = sum - arr[i];
if (remaining < 0) return false;
if (includesBinary(arr, remaining)) return true;
}
return false;
};
}
// Test data: 100 random elements between 0 and 99.
const arr = Array.from(Array(100), _ => Math.floor(Math.random() * 100));
const finder = makeFinder(arr);
console.time('test');
for (let i = 0; i < 1000; i++) finder(100);
console.timeEnd('test');
According to this rough benchmark, one lookup into an array of 100 elements costs a few microseconds.
Rewriting includesBinary to avoid recursion would probably provide a further performance win.
first of all find2PairsBySumLog function is not a binary search, it's a kind of brute force method which parses all the elements of array and it's worst case time complexity should be O(n*n), and the second function is a linear search that' why you are getting the second method to run fastly, for the first function i.e. find2PairsBySumLog what you can do is initialize binary HashMap and check for every pair of integers in array kind of like you are doing in the second function probably like
bool isPairsPresent(int arr[], int arr_size, int sum)
{
int i, temp;
bool binMap[MAX] = {0};
for (i = 0; i < arr_size; i++)
{
temp = sum - arr[i];
if (temp >= 0 && binMap[temp] == 1)
return true;
binMap[arr[i]] = 1;
}
}

Fibonacci calculator steps

Everything work but I have a question on this Fibonacci calculator (see in-code comment). Could I skip the console.debug step? Why is it needed?
var getFibSum = document.getElementById("sumFib");
getFibSum.onclick = function(){
document.getElementById("sumFibResult").innerHTML = fiftyEvenFibonacciSum();
}
function fiftyEvenFibonacciSum(){
/// WRITE YOUR CODE HERE
var first,second,add;
for(var i=0;i<50;i++){
if(i === 0){
first = 1;
second = 2;
}
/** Why do I have to do the following to make it work?:*/
if(first+second > Number.MAX_VALUE){
console.debug(i, first, second);
return;
}
add = first + second;
first = second;
second = add;
}
return(add);
}
Or would this other way be the most efficient way to write the Fibonacci function to calculate the sum of first 50 numbers:
var getFibSum = document.getElementById("sumFib");
getFibSum.onclick = function(){
document.getElementById("sumFibResult").innerHTML = fiftyEvenFibonacciSum();
}
function fiftyEvenFibonacciSum(){
/// WRITE YOUR CODE HERE
var first,second,add;
for(var i=0;i<50;i++){
if(i === 0){
first = 1;
second = 2;
add = first + second;
first = second;
second = add;
}
return(add);
}
Number.MAX_VALUE is the maximum value your system can address and that part of code actually stops the script and outputs the last numbers in case you go over that max value.
Since you're doing only 50 iterations, it's highly unlikely you'll even come close to that number, so you can freely remove the whole if-clause if it bothers you.
console.debug just prints some debug information, it can be removed safely.

proper use of the array.push method

if I have a simple test function that adds even numbers to an array:
function isEven(n){
var enumbers = [];
if (n % 2 == 0){
enumbers.push (n);
}
}
how can I increment my parameter until I have a set number of members in my array? for instance, I've tried this:
function isEven(n){
var enumbers = [];
while ( enumbers.length < 10){
if (n % 2 == 0){
enumbers.push (n);
}
console.log (enumbers);
n = n + 1;
isEven(n);
}
}
isEven(1);
but it seems to just create a new array for each number until it finally throws a range error (maximum call stack size exceeded).
It's creating that array multiple times because you're constantly calling that function with:
isEven(n);
You're also not comparing to the length of the array, just the array. Add .length to enumbers. Try changing to:
var enumbers = [];
while ( enumbers.length < 10){
if (n % 2 == 0){
enumbers.push (n);
}
console.log (enumbers);
}
I'm not sure if I understood your question.
But you shouldn't use global variables, and it is unnecessary to call your function recursively inside a while loop.
The error maximum call stack size exceeded is your browser trying to break a infinity loop.
This is what you need.
Examples here jsFiddle1 and jsFiddle2
function isEven(n) {
var enumbers = [];
while (enumbers.length < 10) {
if (n % 2 == 0) {
enumbers.push(n);
}
n++;
}
return enumbers;
}
Setup a test
var n = 1;
var evenArray = isEven(n); //call isEven function and it returns an array
document.body.innerHTML = evenArray; //2,4,6,8,10,12,14,16,18,20
The problem is that (enumber < 10) apparently always evaluates to true, causing an endless loop. But it is this comparison that is wrong, since you're comparing an integer with an array I think you're trying to get the array length?:
while (enumbers.length < 10) {
Another thing. enumbers is a local variable, so each call to isEven has it's own array. Therefore, the functions is called recursively, over and over again.
I suggest you create the array outside of is even method
I would have written something like:
function isEven(n,enumbers){
while(enumbers < 10){
if (n % 2 == 0){
enumbers.push (n);
}
console.log (enumbers);
n = n + 1;
isEven(n, enumbers);
}
}
var enumbers = [];
isEven(1,enumbers);

Check for continuous order in array in javascript

var userInput = prompt('enter number here');
var number = new Array(userInput.toString().split(''));
if (number ????){ //checks if the number is in a continuous stream
alert(correct);
}
else{
alert(invalid);
}
In Javascript, what can I do at "????" to check if it is in a continuous order/stream? Also how can I do this so that it only checks for this order/stream after a specific index in the array? Meaning the user enters say "12345678901234" which would pop up correct, but "12347678901234" would pop up invalid?(note there are two 7's) For the second part "3312345678901234" would pop up correct, how can this be implemented?
You can make a function that checks any string for a stream of continuous/increasing alpha-numeric characters starting at a given index like this:
function checkContinuous(str, startIndex) {
startindex = startIndex || 0;
if (str.length <= startIndex) {
return false;
}
var last = str.charCodeAt(startIndex);
for (var i = startIndex + 1; i < str.length; i++) {
++last;
if (str.charCodeAt(i) !== last) {
return false;
}
}
return true;
}
If it's numbers only and wrapping from 9 back to 0 is considered continuous, then it's a little more complicated like this:
function checkContinuous(str, startIndex) {
// make sure startIndex is set to zero if not passed in
startIndex = startIndex || 0;
// skip chars before startIndex
str = str.substr(startIndex);
// string must be at least 2 chars long and must be all numbers
if (str.length < 2 || !/^\d+$/.test(str)) {
return false;
}
// get first char code in string
var last = str.charCodeAt(0);
// for the rest of the string, compare to last code
for (var i = 1; i < str.length; i++) {
// increment last charCode so we can compare to sequence
if (last === 57) {
// if 9, wrap back to 0
last = 48;
} else {
// else just increment
++last;
}
// if we find one char out of sequence, then it's not continuous so return false
if (str.charCodeAt(i) !== last) {
return false;
}
}
// everything was continuous
return true;
}
Working demo: http://jsfiddle.net/jfriend00/rHH4B/
No need for arrays, just back though the string one character at a time.
When you hit a 0, substitute 10, and continue until the number
is not one more than the previous one.
function continuousFromChar(str, start){
start= start || 0;
var i= 0, L= str.length, prev;
while(L){
c= +(str.charAt(-- L)) || 10; // use 10 for 0
prev=+(str.charAt(L- 1));
if(c-prev !== 1) break;
}
return start>=L;
}
var s= "3312345678901234";
continuousFromChar(s,2)
/* returned value: (Boolean)
true
*/
This will do the checking in real-time entry, but a similar principle could be used to check an entry on a button submit or similar. I was not 100% sure as to which way you wanted it, so I went for the live method.
HTML
<input id="stream" type="text" />
Javascript
window.addEventListener("load", function () {
document.getElementById("stream").addEventListener("keyup", function (evt) {
var target = evt.target;
var value = target.value;
var prev;
var last;
var expect;
target.value = value.replace(/[^\d]/, "");
if (value.length > 1) {
prev = parseInt(value.slice(-2, -1), 10);
last = parseInt(value.slice(-1), 10);
expect = prev + 1;
if (expect > 9) {
expect = 0;
}
if (last !== expect) {
target.value = value.slice(0, value.length - 1);
}
}
}, false);
});
On jsfiddle
By changing the value here
if (value.length > 1) {
You can change where the checking starts.
Update: Ok, so it is function that you want, and you insist that it splits the string into an array. Then using the above as a reference, you could convert it to something like this.
Javascript
window.addEventListener("load", function () {
var testStrings = [
"0123456789012",
"0123456789",
"0123455555",
"555012345678901234",
"0123455555"];
function test(string, offset) {
if (typeof string !== "string" || /[^\d]/.test(string)) {
return false;
}
var array = string.split("");
var prev;
var last;
var expect;
return !array.some(function (digit, index) {
if (index >= offset) {
prev = parseInt(array[index - 1], 10);
last = parseInt(digit, 10);
expect = prev + 1;
if (expect > 9) {
expect = 0;
}
if (last !== expect) {
return true;
}
}
return false;
});
}
testStrings.forEach(function (string) {
console.log(string, test(string, 1));
});
});
On jsfiddle
As your question does not fully specify all possibilities, the above will return true for an empty string (""), of course you can simply add a check at the very beginning for that.
I also do not perform any checking for a valid number for your offset, but again this is something simple that you can add.
Of course these are just one (two) of many possible solutions, but hopefully it will set your mind in the right direction of thought.
There are some good answers here, but I would like to show a slight variation. I think it is important to showcase some different aspects of JavaScript and separating interests in code.
Functions as first class objects are cool - the exact rules for "continuous" can be changed with only changing the predicate function. Perhaps we should allow skipping numbers? No problem. Perhaps we allow hex digits? No problem. Just change the appropriate follows function for the specific rules.
This can be implemented generically because strings support indexing. This will work just as well over other array-like objects with an appropriate follows function. Note that there are no string-specific functions used in the continuous function.
Code also on jsfiddle:
// returns true only iff b "follows" a; this can be changed
function follows_1Through9WithWrappingTo0(b,a) {
if (b === "1" && a === undefined) {
// start of sequence
return true;
} else if (b === "0" && a === "9") {
// wrap
return true;
} else {
// or whatever
return (+b) === (+a) + 1;
}
}
function continuous(seq, accordingTo, from) {
// strings can be treated like arrays; this code really doesn't care
// and could work with arbitrary array-like objects
var i = from || 0;
if ((seq.length - i) < 1) {
return true;
}
var a = undefined;
var b = undefined;
for (; i < seq.length; i++) {
b = seq[i];
if (!accordingTo(b, a)) {
return false; // not continuous
}
a = b;
}
return true;
}
function assert(label, expr, value) {
if (!(expr === value)) {
alert("FAILED: " + label);
}
}
var follows = follows_1Through9WithWrappingTo0;
assert("empty1", continuous("", follows), true);
assert("empty2", continuous("foobar", follows, 6), true);
assert("skip", continuous("331234", follows, 2), true);
assert("good 1", continuous("123456789", follows), true);
assert("good 2", continuous("12345678901234", follows), true);
assert("bad seq 1", continuous("12347678901234", follows), false);
assert("bad seq 2", continuous("10", follows), false);
// here a different predicate ensures all the elements are the same
var areAllSame = function (b, a) {
return a === undefined || a === b;
};
assert("same", continuous("aaaaa", areAllSame), true);
Note that the skipping could also be extracted out of the continuous function: in a language with better "functional" collection support, such as C#, this is exactly what I'd do first.

Categories