Credit Card Checker by Luhm Algorithm on Javascript - javascript

The goal is to write function which gets an array as a parametr and returns new array by using Luhm Algorithm. The function is not finished but I have an issue with new array part. I don't know why but there is not even any errors in console, but just nothing.
const card = [4, 5, 3, 9, 6, 7, 7, 9, 0, 8, 0, 1, 6, 8, 0, 8];
function validateCred(arr) {
let algResult = [];
for (let i = arr.length - 1; i => 0; i--) {
if (i % 2 !== 0) {
algResult.push(arr[i]);
}
else if (i % 2 == 0) {
let nx2 = arr[i] * 2;
if (nx2 > 9) {
nx2 -= 9;
algResult.push(nx2);
}
else {
algResult.push(arr[i]);
};
}
};
return algResult;
}
console.log(validateCred(card))

I took a look on Luhm Algorithm that you provided in your question, and I made a function that takes an input card number as string because you will validate input type text value which is string and not a number and it returns true or false (whether it's valid or not).
function isValidCardNumber(cardStrInput) {
var sum = 0;
cardStrInput.split("").reverse().forEach(function(digit, ind) {
var a = Number(digit);
sum += ind % 2 === 1 ? (a * 2 > 9 ? a * 2 - 9 : a * 2) : a;
});
return sum % 10 === 0;
}
console.log(isValidCardNumber("4539689887705798"));

Related

Sum and Difference between odds and evens

So I manage to separate the odd and even numbers but I'm having trouble figuring out how to add the odds with odds and even with evens and then subtract that to get the answer. i.e
(1 + 3 + 5 + 7 + 9) - (2 + 4 + 6 + 8) = 5
let numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9]
sumDiff(numbers);
function sumDiff(numbers) {
let even = [];
let odd = [];
for (let i = 0; i < numbers.length; i++) {
if (numbers[i] % 2 === 0) {
even.push(numbers[i]);
} // end
else {
odd.push(numbers[i]);
}// end else
} //end of for loop
console.log(odd);
console.log(even);
} // end of function
Now I don't want the full answer, but a nudge in the right direction. I figured I can separate the odd and even numbers first and then go from there.
Would I have to create a new function or could I still get it done within the same function?
Your code works just fine, for the missing functionality you're looking for, you could use the Array.prototype.reduce() function to sum the values of the two arrays you created, like this:
let numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9]
sumDiff(numbers);
function sumDiff(numbers) {
let even = [];
let odd = [];
for (let i = 0; i < numbers.length; i++) {
if (numbers[i] % 2 === 0) {
even.push(numbers[i]);
} // end
else {
odd.push(numbers[i]);
}// end else
} //end of for loop
console.log(odd);
console.log(even);
let oddSum = odd.reduce((r, s) => r += s, 0)
let oddEven = even.reduce((r, s) => r += s, 0)
console.log("odd sum total: " + oddSum)
console.log("even sum total: " + oddEven)
console.log("difference: " + (oddSum - oddEven))
} // end of function

A better way to write this recursive function that finds an odd amount of numbers in an array

I made this recursive solution to find if a number is in an array an odd amount of times and if not return null. I was wondering if anyone had any suggestions for better cleaner code. Just trying to improve, Thanks!
let odd = [0, 5, 6, 6, 4, 0, 1, 5, 2, 4];
let j = 1;
let number;
function tryAgain(odd) {
let counter = 0;
odd.forEach((num, i, arr) => {
if (num === arr[j]) {
counter++;
number = arr[j];
}
});
if (counter > 1 && counter % 2 !== 0) {
return number;
} else {
j++;
if (j > odd.length) {
number = null;
return false;
} else {
tryAgain(odd);
}
}
return number;
}
Using inductive reasoning, we can structure our program in a straightforward way -
if the input t is empty, there is nothing to count, return false
(by induction) the input is NOT empty. If the first element of t matches the query q, return the opposite of the recursive result
(by induction) the input is NOT empty and the first element of t does NOT match the query q. return the recursive result
const oddCount = (t = [], q = null) =>
t.length === 0
? false // 1
: t[0] === q
? !oddCount(t.slice(1), q) // 2
: oddCount(t.slice(1), q) // 3
const data =
[ 1, 1, 2, 1, 2, 3, 1, 2, 3, 4 ]
console.log
( oddCount(data, 1) // false
, oddCount(data, 2) // true
, oddCount(data, 3) // false
, oddCount(data, 4) // true
, oddCount(data, 9) // false
)
There is an odd count of 2s and 4s in the data array. However 1, 3, and 9 do not have an odd count.

Array of numbers to batches of given sum

I've a JavaScript array and sum as input
array = [4,8,2,4,2,2,8,12,4,2, 2]
sum = 12 // all the time sum will be 12
I want 2d array, the numbers in batches should be sum equals or less than 12
The output array should look like
[
[4,8],
[2,4,2,2,2],
[8, 4],
[12],
[2]
]
4 + 8 = 12
2 + 4 + 2 + 2 + 2 = 12
...
2 is left at the end
Other examples
1) array = [6,5,3,3,3,2,2,2,2]
sum = 12
output: [ [6,3,3], [5,3,2,2], [2,2] ]
One the number is allotted to subset, it should not used to other subset
remaining numbers can be added to the last but sum should be less than 12, else add one more array and add remaining ones
The input array can have any integer from 1 - 12
How can I get the output I want?
Try this function. I commented the code as much as possible to clarify it.
const example1 = [4, 8, 2, 4, 2, 2, 8, 12, 4, 2, 2];
const example2 = [6, 5, 3, 3, 3, 2, 2, 2, 2];
const example3 = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12];
const example4 = [5,12,3,4,4,1,1,1,5,8,12,6,9,11,6];
const example5 = [4, 2, 1, 2, 3, 3, 5, 7, 8, 9];
const lookAhead = function(array, searchFor) {
return array.some(val => {
return val <= searchFor;
});
}
function findPairs(inputArray) {
// First sort array in descending order
inputArray.sort((a, b) => b - a);
console.log("input", JSON.stringify(inputArray.slice(0)));
// set variables
const pairArray = [];
const max = 12;
inputArray.forEach(function(num, index) {
// when looping the array we will replace values with null once completed,
// Therefore if value is null no need to go futher
if (num == null)
return;
// initiate pair value with current number
const pair = [num];
// set it to null in input array
inputArray[index] = null;
// if number equals to max (ie. 12) no need to go futher
if (num == max) {
pairArray.push(pair);
return;
}
let total = num;
// Loop through array again to see matching numbers
for (let i = 0; i < inputArray.length; i++) {
// Don't go futher if it is a null value
if (inputArray[i] == null)
continue;
const add = total + inputArray[i];
/* if the total is less than max (12) then we check if we have an edge case
* For example in an array like [6, 5, 3, 3, 3], 6 + 5 is 11 but in next loops we
* will not find any "1" to get to 12. Therefore we escape this iteration and check
* next numbers. In this case the result would be 6 + 3 + 3
*/
if (add < max) {
const found = lookAhead(inputArray.slice(i), max - add);
if (found) {
pair.push(inputArray[i]);
total = add;
inputArray[i] = null;
}
} else if (add == max) {
// The addition is equals to max. Push the number and set it to null in input array
pair.push(inputArray[i]);
inputArray[i] = null;
total = 0;
break;
}
}
// Push pair array from this iteration to pairArray
pairArray.push(pair);
});
console.log("output", JSON.stringify(pairArray));
console.log("-------");
}
findPairs(example1);
findPairs(example2);
findPairs(example3);
findPairs(example4);
findPairs(example5);
A little complex to understand but here you go...
let originalArray = [7, 7, 7, 7, 7]
let sum = 12;
let twoDiArray = [];
let CalculateSum = (array, element) => {
array = [...array, element]
return array.reduce((x, y) => {
return x + y;
})
}
twoDiArray.push([]);
originalArray.forEach(element => {
for (let i = 0; i < twoDiArray.length; i++) {
if (CalculateSum(twoDiArray[i], element) <= 12) {
twoDiArray[i].push(element);
break;
} else {
if (twoDiArray.length - 1 === i) {
twoDiArray.push([element]);
break;
}
}
}
})
console.log(twoDiArray)
Here you... I will keep both answers open for future use of others...
let originalArray = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
let sum = 12;
let twoDiArray = [];
let CalculateSum = (array, element) => {
array = [...array, element]
return array.reduce((x, y) => {
return x + y;
})
}
twoDiArray.push([originalArray[0]]);
originalArray.splice(0, 1);
do {
originalArray.forEach((element, index) => {
for (let i = 0; i < twoDiArray.length; i++) {
let summ = CalculateSum(twoDiArray[i], element);
if (summ === 12) {
twoDiArray[i].push(element);
originalArray.splice(index, 1);
break;
} else {
if (index === originalArray.length - 1) {
if (CalculateSum(twoDiArray[twoDiArray.length - 1], originalArray[0]) <= 12) {
twoDiArray[twoDiArray.length - 1].push(originalArray[0]);
break;
} else {
twoDiArray.push([originalArray[0]]);
}
originalArray.splice(0, 1);
}
}
}
})
}
while (originalArray.length > 0);
console.log(twoDiArray)

Given an array of integers ‘num’ return the array incremented by 1

Given an array of integers, return a new array that has that original values incremented by 1.
Each value in the array can't exceed 9 and you can't use any function that converts the array into an integer.
i.e:
Original Array = [1,2,7,9]
Returned Array = [2,3,8,0]
#param (array) num
#return (array)
This is what I am currently doing. Just wondering if there is anything that will be more efficient.
function increment (num) {
for (var i = num.length - 1; i >= 0; i--) {
num[i]++;
if (num[i] > 9) num[i] = 0;
else break;
}
return num;
}
console.log(increment([1, 2, 7, 9]));
There's one problem: if the input array is composed of all 9s, you want a desired output of, eg, [1, 0, 0, 0, 0] (rather than [0, 0, 0, 0]):
function increment (num) {
for (var i = num.length - 1; i >= 0; i--) {
num[i]++;
if (num[i] > 9) {
num[i] = 0;
if (i === 0) {
// Last iteration, but we need to carry - unshift a 1:
num.unshift(1);
}
}
else break;
}
return num;
}
console.log(increment([1, 2, 7, 9]));
console.log(increment([3, 9, 9, 9]));
console.log(increment([9, 9, 9, 9]));
console.log(increment([1, 1, 1, 1]));
A little late but here's a recursive version, same edge case issue if the argument is [9,9,9,9].
function increment(array, index = NaN) {
if (isNaN(index)) {
index = array.length - 1;
}
if (++array[index] % 10 === 0) {
array[index] = 0;
increment(array, --index);
}
return array;
}
console.log(increment([1,2,7,9]))
console.log(increment([9,9,9,9]))

Finding maximum size of range in a sorted integer array

I am looking for an implementation in JavaScript for the following problem.
Consider a sorted array:
[1,2,5,9,10,12,20,21,22,23,24,26,27]
I would like to calculate the length of the maximum range that increased by 1, duplicates are not allowed.
The given example has the following ranges:
1,2
9,10
20,21,22,23,24 // the maximum range
26,27
So the return value for the given example should be 5.
I know how to solve this problem with the obvious solution, but I believe it is possible to solve the problem with more efficient and short algorithm.
A short solution
I don't think this is any more efficient than what pretty much everybody else has suggested, but the code is reasonably short and only loops over the array once, except for the first element. Not sure if it's any help:
var arr = [1, 2, 5, 9, 10, 12, 20, 21, 22, 23, 24, 26, 27];
var streak = 0, best = 0, bestStart;
for (var i = 1; i < arr.length; i++) {
if(arr[i]-arr[i-1] === 1) streak++;
else streak = 0;
if (streak > best) [best, bestStart] = [streak, i - streak];
}
var bestArr = arr.slice(bestStart, bestStart + best + 1);
console.log('Best streak: '+bestArr);
Speeding it up
After looking at the code, I realized that there is a way to speed it up slightly, by not checking the last few elements of the array, based on the previous value of best:
var arr = [1, 2, 5, 9, 10, 12, 20, 21, 22, 23, 24, 26, 27];
var streak = 0, best = 0, bestStart;
for (var i = 1; i < arr.length; i++) {
if(best > arr.length - i + streak) break;
if(arr[i]-arr[i-1] === 1) streak++;
else streak = 0;
if (streak > best) [best, bestStart] = [streak, i - streak];
}
var bestArr = arr.slice(bestStart, bestStart + best + 1);
console.log('Best streak: '+bestArr);
One possible solution would be to iterate the array, keeping the the current range as long as the numbers are successors. If the next number is not a successor of the previous number, close the current range and store its length - by comparing it to the length of the last range.
In this approach, the array is iterated only once and the maximum found length of a range is updated in constant time, yielding an O(n) algorithm where n is the number of elements in the input.
An implementation in C#-like pseudocode could be as follows.
int MaximumLength = minus infinity
int CurrentValue = Input[0];
int CurrentLength = 1;
for(int i = 1; i < Input.Length; i++)
{
if ( CurrentValue + 1 == Input[i] )
{
// same range
CurrentLength = CurrentLength + 1;
}
else
{
// new range
MaximumLength = Math.Max(MaximumLength, CurrentLength);
CurrentLength = 1;
}
CurrentValue = Input[i];
}
// check current length again after loop termination
MaximumLength = Math.Max(MaximumLength, CurrentLength);
It is impossible to obtain better than O(n) because the input cannot be read in less than O(n) time. If that would be possible, it would imply that there are instances for which the result does not depend on every element of the input, which is not the case for the given problem. The algorithm Philipp Maurer has sketched below would also yield an O(n) runtime bound if the maximum range length is 1, i.e. no adjacent numbers in the input are successors.
Something like this should find the maximum length first and not last.
Let max = 0
Let n = array length
While n > 2
Let m = 0
While m <= (array length - n)
Let first = m
Let last = m + n - 1
Let diff = (value of element 'last' in array) - (value of element 'first' in array)
if diff = n - 1 then
max = n
stop
end if
Increase m
end while
Decrease n
end while
Edit (javascript implementation)
var a = [1,2,5,9,10,12,20,21,22,23,24,26,27];
var max = 1;
var n = a.length;
while(n > 2) {
var m = 0;
while(m <= a.length - n)
{
var first = m;
var last = m + n - 1;
var diff = a[last] - a[first];
if (diff == n - 1 && diff > max) {
max = n;
break;
}
m++;
}
n--;
}
console.log(max);
JSFiddle
I think looping and comparing with stored previous maximum length is optimal solution. Maybe like this:
function findLongestRange(input) {
let maxLength = 0
let currentLength = 0
for (let i = 0; i < input.length; i++) {
if (i !== input.length) {
if (input[i] === input[i + 1] - 1) {
currentLength++
} else {
if (maxLength <= currentLength && currentLength !== 0) {
maxLength = currentLength + 1
}
currentLength = 0
}
}
}
return maxLength
}
const data = [1, 2, 5, 9, 10, 12, 20, 21, 22, 23, 24, 26, 27]
console.log(findLongestRange(data))
Here is the version with tests to check how it works with different input.
const data = [1, 2, 5, 9, 10, 12, 20, 21, 22, 23, 24, 26, 27]
function findLongestRange(input) {
let maxLength = 0
let currentLength = 0
for (let i = 0; i < input.length; i++) {
if (i !== input.length) {
if (input[i] === input[i + 1] - 1) {
currentLength++
} else {
if (maxLength <= currentLength && currentLength !== 0) {
maxLength = currentLength + 1
}
currentLength = 0
}
}
}
return maxLength
}
console.clear()
;[
[[1,2,5,6,7,1,2], 3],
[[], 0],
[data, 5],
[[1,2,3], 3],
[[1,3,4,6,8,1], 2],
[[1,3,5], 0],
].forEach((test, index) => {
const result = findLongestRange(test[0])
console.assert(result === test[1], `Fail #${index}: Exp: ${test[1]}, got ${result}`)
})
A Python answer:
l = [1,2,5,9,10,12,20,21,22,23,24,26,27]
current_range = None
current_range_val = 0
max_range = 0
max_range_val = 0
for i, j in zip(l, l[1:]):
if j - i == 1:
current_range_val += 1
if current_range is None:
current_range = (i, j)
current_range = (current_range[0], j)
else:
if current_range_val > max_range_val:
max_range = current_range
max_range_val = current_range_val
current_range_val = 0
current_range = (j, None)
print(max_range)
gives
(20, 24)

Categories