Related
I have generated random set of numbers (generated number) for each individual multiplier (numbers from 2 - 10).
The code itself does generates the numbers although not as expected.
Current behaviour:
it renders numbers (sometimes repetetive) within an array (for example 2x4 and 2x4)
it renders array with different length each time
rendered numbers multiplication value is repetetive (if there's an object with 4x7 and 7x4 it should replace one of these sets with a new value)
number objects are rendered on given conditions (for example number 9 multiplier will render at least once but no more than 3 times)
Expected behaviour:
it renders unique set of numbers for each multiplier
renders the array with the same length all the time (with length === 18)
checks if multiplication of multiplier and generated number matches the value within the array, if so then it renders another set of numbers within (still within the conditions)
This is what I got so far
const randomNumbersGenerator = () => {
function getRandomInt(min, max) {
min = Math.ceil(min);
max = Math.floor(max);
return Math.floor(Math.random() * (max - min) + min);
}
const number2 = getRandomInt(0, 2);
const number3 = getRandomInt(0, 3);
const number4 = getRandomInt(0, 3);
const number5 = getRandomInt(0, 3);
const number6 = getRandomInt(1, 4);
const number7 = getRandomInt(1, 4);
const number8 = getRandomInt(1, 4);
const number9 = getRandomInt(1, 4);
const number10 = getRandomInt(0, 2);
const number11 = getRandomInt(0, 3);
const randomNumber = () => getRandomInt(2, 12);
let current;
const numbersArray = [];
for (let i = 0; i < number2; i += 1) {
if (numbersArray.indexOf((current = randomNumber())) === -1) {
numbersArray.push({
multiplier: 2,
generated: current
});
}
}
for (let i = 0; i < number3; i += 1) {
if (numbersArray.indexOf((current = randomNumber())) === -1) {
numbersArray.push({
multiplier: 3,
generated: current
});
}
}
for (let i = 0; i < number4; i += 1) {
if (numbersArray.indexOf((current = randomNumber())) === -1) {
numbersArray.push({
multiplier: 4,
generated: current
});
}
}
for (let i = 0; i < number5; i += 1) {
if (numbersArray.indexOf((current = randomNumber())) === -1) {
numbersArray.push({
multiplier: 5,
generated: current
});
}
}
for (let i = 0; i < number6; i += 1) {
if (numbersArray.indexOf((current = randomNumber())) === -1) {
numbersArray.push({
multiplier: 6,
generated: current
});
}
}
for (let i = 0; i < number7; i += 1) {
if (numbersArray.indexOf((current = randomNumber())) === -1) {
numbersArray.push({
multiplier: 7,
generated: current
});
}
}
for (let i = 0; i < number8; i += 1) {
if (numbersArray.indexOf((current = randomNumber())) === -1) {
numbersArray.push({
multiplier: 8,
generated: current
});
}
}
for (let i = 0; i < number9; i += 1) {
if (numbersArray.indexOf((current = randomNumber())) === -1) {
numbersArray.push({
multiplier: 9,
generated: current
});
}
}
for (let i = 0; i < number10; i += 1) {
if (numbersArray.indexOf((current = randomNumber())) === -1) {
numbersArray.push({
multiplier: 10,
generated: current
});
}
}
for (let i = 0; i < number11; i += 1) {
if (numbersArray.indexOf((current = randomNumber())) === -1) {
numbersArray.push({
multiplier: 11,
generated: current
});
}
}
console.log(numbersArray);
return numbersArray;
};
randomNumbersGenerator();
You can also check it out via the codeSandbox:
https://codesandbox.io/s/upbeat-jang-coqd5?file=/src/index.js:660-672
I think this is what you are looking for. I took a completely different approach.
First, I'm using a Map because it is simple to ensure uniqueness. (keys must be unique)
Note I'm using a simple string for the key to ensure they are unique (using objects there get's a bit more complicated)
The ranges array represents your 'number2, number3` etc.
The loop starts at 2 to satisfy your multiplier range (2 - 11). This requires a bit of trickery to get index cone correctly.
This generates unique pairs (as key) and the value of the map is the generated value and the multiplier multiplied together.
The size and Map are printed in the console.
const randomNumbersGenerator = () => {
function getRandomInt(min, max) {
min = Math.ceil(min);
max = Math.floor(max);
return Math.floor(Math.random() * (max - min) + min);
}
const randomNumber = () => getRandomInt(2, 12);
const multiplierMap = new Map();
const ranges = [[0, 2], [0, 3], [0, 3], [0, 3], [0, 3], [1, 4], [1, 4], [1, 4], [1, 4], [0, 2], [0, 3]];
while(multiplierMap.size < 17) {
for (let i = 2; i < ranges.length+1; i++) {
const randomInt = randomNumber();
if(Array.from(multiplierMap.values).includes(randomInt * i)){
--i;
} else {
multiplierMap.set(randomInt + " " + i, randomInt * i);
}
if(multiplierMap.size === 18) break;
}
}
console.log('MultiplierMap size: ', multiplierMap.size);
for(let [pair, multiple] of multiplierMap){
console.log('Generated Multiplier: ' + pair, '||', 'Generated * Multiplier: ' + multiple);
}
return multiplierMap;
};
randomNumbersGenerator();
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"));
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)
I want to insert numbers to an array by the next following:
the number should be between 1-5
the first number can't be 1, the second can't be 2, etc..
chosen number can't be inserted to another index
for example:
[1,2,3,4,5]
I randomize the first number: 1 [condition 2 doesn't exists: 1 can't be in the first index, so I randomize again and got 4).
so new array:
0 - 4
1 -
2 -
3 -
4 -
I randomize a number to the second cell and got 4, but 4 was inserted to the first element [condition 3], so I randomize again and got 2, but 2 can't be the second element [condition 2], so I randomize again and got 5.
0 - 4
1 - 5
2 -
3 -
4 -
etc
I tried to init a vec by the numbers (1-5):
var array = new Array();
array[0] = 1;
array[1] = 2;
array[2] = 3;
array[3] = 4;
array[4] = 5;
var newarr = new Array();
function getRandomInt (min, max) {
return Math.floor(Math.random() * (max - min + 1)) + min;
}
$(document).ready(function() {
for (var i = 0; i < 5; i++) {
var rand;
// check condition 2
while((rand = getRandomInt(1, 5)) == (i+1));
newarr[i] = rand;
//array.splice(i, 1);
}
// print the new array
for (var i = 0; i < 5; i++) {
alert((i+1) + '->' + newarr[i]);
}
});
but I need to add condition 3 to my code,
any help appreciated!
Try this:
$(document).ready(function() {
for (var i = 0; i < 5; i++) {
var rand;
// check condition 2
while((rand = getRandomInt(1, 5)) == (i+1) || $.inArray(rand, newarr)) // Also check, if generated number is already in the array
newarr[i] = rand;
//array.splice(i, 1);
}
// print the new array
for (var i = 0; i < 5; i++) {
alert((i+1) + '->' + newarr[i]);
}
});
But beware. If you generate for example this array:
[2, 1, 4, 3]
You will end up having an endless while loop, since the only available number is 5, but it can't be inserted in that position.
var values = [1,2,3,4,5];
var output = [];
for(var i=0;i<5;i++)
{
do{
var index = Math.floor(Math.random() * values.length);
}while(values[index] == i +1);
output[i] = values[index];
values.splice(index, 1);
}
console.log(output);
Demo : http://jsfiddle.net/aJ8sH/
There is an array of numbers [1,2,3,4,5,6,7,8,9,10]
I need to get all numbers from this sequence that are different from current for more than 2 items, but looped.
For example if current number is one, so new list should have everything except 9,10,1,2,3, or if current number is four so new list should be everything except 2,3,4,5,6.
Is there any technique how to make this, without creating multiple loops for items at start and at the end?
Thank you.
var a = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
var exclude = function (start, distance, array) {
var result = [];
for (var i = 0; i < array.length; i++) {
var d = Math.min(
Math.abs(start - i - 1),
Math.abs(array.length + start - i - 1)
)
if (d > distance) {
result.push(array[i]);
}
}
return result;
}
I think this performs what you asked:
// Sorry about the name
function strangePick(value, array) {
var n = array.length
, i = array.indexOf(value);
if (i >= 0) {
// Picked number
var result = [value];
// Previous 2 numbers
result.unshift(array[(i + n - 1) % n]);
result.unshift(array[(i + n - 2) % n]);
// Next 2 numbers
result.push(array[(i + 1) % n]);
result.push(array[(i + 2) % n]);
return result;
} else {
return [];
}
}
Some tests:
var array = [1,2,3,4,5,6,7,8,9,10];
console.log(strangePick(1, array)); // [9,10,1,2,3]
console.log(strangePick(4, array)); // [2,3,4,5,6]
You may use javascript array.slice:
function get_offset_sequence(arr, index, offset) {
var result = [];
if (index - offset < 0) {
result = arr.slice(index - offset).concat(arr.slice(0, index + offset + 1));
}
else if (index + offset > arr.length - 1) {
result = arr.slice(index - offset).concat(arr.slice(0, Math.abs(arr.length - 1 - index - offset)));
}
else {
result = arr.slice(index - offset, index + offset + 1)
}
return result;
}
Example of use:
var arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
var index = 1;
var offset = 2;
for (var i=0; i < 10; i++) { console.log(i, arr[i], get_offset_sequence(arr, i, offset)) }