javascript compare two array find difference - javascript

I have two array, could be integer array, string array or even object array, for demo purpose, I'll use integer array.
array1: array2:
0 99
1 1
101 5
2 100
100 97
5 101
4 4
I want to have a function return the array include all the information about the difference between two arrays.
result would be:
0 -- {match:false,leftIndex:0 }
-- 99 {match:false: rightIndex:0}
1 1 {match:true: leftIndex:1,rightIndex:1}
-- 5 {match:false: rightIndex:2}
-- 100 {match:false: rightIndex:3}
-- 97 {match:false: rightIndex:4}
101 101 {match:false:leftIndex:2,rightIndex:5}
2 -- {match:false:leftIndex:3 }
100 -- {match:false:leftIndex:4 }
5 -- {match:false:leftIndex:5 }
4 4 {match:false:leftIndex:6,rightIndex:6}
What is the best way to approach this?
I'm planning to use this function to display a side by side view for those two array using angularJS directive method. will that work?

I suggest to use a Map for the values as key and indices as values for the matched check, if the delta of rightIndexand leftIndex is smaller than zero.
On this case, a matched item is found and if some other values from the right side are missing, they are picket up.
For the last part, possible leftover of array2 is pushed, too.
0 1 2 4 5 97 99 100 101 values
0 1 3 6 5 - - 4 2 leftIndex
- 1 - 6 2 4 0 3 5 rightIndex
- 0 - 0 -3 - - -1 3 delta: p2 - p1
* * * relevant only delta >= 0
var array1 = [0, 1, 101, 2, 100, 5, 4],
array2 = [ 99, 1, 5, 100, 97, 101, 4],
map = new Map,
j = 0,
result = [];
array2.forEach(map.set.bind(map));
array1.forEach(function (a, i) {
if (map.has(a) && map.get(a) >= i) {
while (j < map.get(a)) {
result.push({ value: array2[j], match: false, rightIndex: j });
j++;
}
result.push({ value: a, match: true, leftIndex: i, rightIndex: j });
j++;
return;
}
result.push({ value: a, match: false, leftIndex: i });
});
while (j < array2.length) {
result.push({ value: array2[j], match: false, rightIndex: j });
j++;
}
console.log(result);

If you can use last ES6 features I'll go with something like this:
function areArrayEqual(array1, array2) {
// Based on http://stackoverflow.com/a/14853974/2586392
if (array1.length !== array2.length) return false;
for (var i = 0, l=array1.length; i < l; i++) {
if (!areArrayEqual(array1[i], array2[i]) return false;
else if (array1[i] != array2[i]) return false;
}
return true;
})
var result = [];
array1.forEach((value, i) => {
let j = array2.findIndex(x => {
if (typeof value !== typeof x) return false;
if (typeof value === 'object') return areArrayEquals(Object.values(x), Object.values(value));
if (typeof value === 'array') return areArrayEquals(x, value);
return x === value;
});
result.push([value, j === -1 ? '---' : value , {
match: !!(j + 1),
leftIndex: i,
rightIndex: j === -1 ? '---' : j
}]);
if (j !== -1) {
delete array2[j];
}
});
array2.forEach((value, i) => {
result.push(['---', value, {match: false, leftIndex: '---', rightIndex: i}]);
});
Otherwise you can still use something similar, but you need to polyfill Object.values and maybe forEach as well

Related

Create array of all N digit numbers whose sum of digit equals S

I found some solutions to my question in other languages. When I converted them to javascript, it would not create an array.
const find_digits = (n, sum, out, index) => {
if (index > n || sum < 0) return;
let f = "";
if (index == n) {
if (sum == 0) console.log(out); // Success!
return;
}
for (var i = 0; i < 10; i++) {
out[index] = i;
find_digits(n, sum - i, out, index + 1);
}
}
const subset_sum = (n, sum) => {
var out = [].fill(false, 0, n + 1);
for (var i = 0; i < 10; i++) {
out[0] = i;
find_digits(n, sum - i, out, 1);
}
return out;
}
console.log(subset_sum(3, 17)); // Output: [9,9,9]
The first log is successful, but the final log returns [9,9,9]
I would appreciate some help.
I might make the recursion a bit more explicit. To my mind there are a number of different base-cases, for various low values of n and s:
if s < 0, then there are no results
if s == 0, then the only result is a string of n zeroes
if n == 1, then
if s < 10, then the only result is the digit s
otherwise, there are no results
The recursive case involves taking each digit as a potential first digit, then joining it with each of the results involved in recursing, taking that amount from the total and using a digit count one smaller.
Here's an implementation of that:
const subsetSum = (n, s) =>
s < 0
? []
: s == 0
? ['0' .repeat (n)]
: n == 1
? s < 10 ? [String(s)] : []
: // else
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9] .flatMap (
k => subsetSum (n - 1, s - k) .map (p => k + p)
)
console .log (
subsetSum (3, 17)
) //~> ["089", "098", "179", "188", "197", "269", "278", ..., "971", "980"] (63 entries)
.as-console-wrapper {min-height: 100% !important; top: 0}
Given your comment about licenses, I assume that it's really strings of digits you want and not numbers. That's what this returns. If you want numbers, you will need to remove all those that start with 0 and convert the strings to numbers. (Thus, 89 would not be included in subset(17, 3) even thought "089" is a legitimate digit string, because 89 is only a two-digit number.)
Update
I just realized that the s == 0 case can be subsumed in the recursive one. So it's actually a bit simpler:
const subsetSum = (n, s) =>
s < 0
? []
: n == 1
? s < 10 ? [String(s)] : []
: // else
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9] .flatMap (
k => subsetSum (n - 1, s - k) .map (p => k + p)
)
Or, phrased slightly differently, as
const subsetSum = (n, s) =>
s < 0 || (n <= 1 && s >= 10)
? []
: n == 1
? [String(s)]
: // else
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9] .flatMap (
k => subsetSum (n - 1, s - k) .map (p => k + p)
)
const find_digits = (n, sum, out, index) => {
if (index >= n) return;
out[index] = 9;
find_digits(n, sum, out, index +1);
}
const subset_sum = (n, sum) => {
var out = [].fill(false, 0, n + 1);
find_digits(n, sum, out, 0);
return out;
}
console.log(subset_sum(3, 17));
I guess the problem is with the check at the beginning of the find_digit() function for the number of times you can call this function won't exceed by any means 3 times as per your arguments passed in the subset_sum() function. I have redacted the code to the bare minimum and produced the same result as yours. If you can give me clarification as to the purpose of this code. I would be glad to help.
You should call your function without console, like this:
subset_sum(3, 17)
Because you write to console inside your code.
Your trouble is that your subset_sum returning at the end array out.
So, you have 2 options:
- call your function by name
- returning at the end of subset_sum just "return"
The function below allows you to pass in a different base/alphabet.
It first generates the permutations, then filters the results based on the value you passed in as the second parameter.
const BaseSystem = {
bin : '01',
dec : '0123456789',
hex : '0123456789ABCDEF'
};
Object.keys(BaseSystem).forEach(k =>
Object.assign(BaseSystem, { [k] : BaseSystem[k].split('') }))
const main = () => {
console.log(subsetSum(4, v => v === 2, BaseSystem.bin))
console.log(subsetSum(2, 4)) // Default = BaseSystem.dec
console.log(subsetSum(3, 0xF, BaseSystem.hex))
}
const subsetSum = (size, sum, alpha=BaseSystem.dec) => {
if (typeof sum === 'string') sum = parseInt(sum, alpha.length)
return getPermutations(alpha, size)
.filter(v => ((result) =>
typeof sum === 'function' ? sum(result, v) : sum === result
)(parseReduce(alpha.length, ...v))).map(v => v.join(''))
}
const parseReduce = (base, ...v) =>
v.reduce((t, x) => t + parseInt(x, base), 0)
/** Adapted From: https://stackoverflow.com/a/59028925/1762224 */
const getPermutations = (list, len) => {
const base = list.length
const counter = Array(len).fill(base === 1 ? arr[0] : 0)
if (base === 1) return [counter]
const results = []
const increment = i => {
if (counter[i] === base - 1) {
counter[i] = 0
increment(i - 1)
} else counter[i]++
}
for (let i = base ** len; i--;) {
const subResults = []
for (let j = 0; j < counter.length; j++)
subResults.push(list[counter[j]])
results.push(subResults)
increment(counter.length - 1)
}
return results
}
main();
.as-console-wrapper {min-height: 100% !important; top: 0}

Find int that appears an odd number of times in an array

I am working on this task where I need to find a number that happens to appear an odd number of times in an array.
I believe I've almost done it, but if some number appears more than once in a row (like 1 in [1,1,3,1,1]), it will always return that number, no matter if it appears an odd number of times or not.
function findOdd(A) {
var a;
var count = 0;
for (var i = 0; i < A.length; i++) {
a = A[i];
for (var l = i + 1; l < A.length; l++) {
if (a == A[l]) {
count++;
}
}
if (!(count % 2)) {
break;
} else {
count = 0;
}
}
return a;
}
console.log(findOdd([ 1, 1, 2, -2, 5, 2, 4, 4, -1, -2, 5 ]));
I've tried to play with adding 1 to count if [i] = [i+1], but it didn't work.
I'd expect output of findOdd([1, 1, 2, -2, 5, 2, 4, 4, -1, -2, 5]) to be -1, but it is 1. The function always returns first number that happens to be equal to next element of an array.
There's no need to reset count or use a break.
function findOdd(A) {
for (var i = 0; i < A.length; i++){
var count = 0;
for (var l = 0; l < A.length; l++) {
if (A[i] === A[l]) count++;
}
if (count % 2 !== 0) return A[i];
}
}
An important thing to note is that the inner loop is not starting at i+1, its starting at the 0. When A[i] matches A[l], we increment count. A number that appears an odd number of times will result in count becoming odd as well and we can return that number.
The following works but I wonder how the performance compares to simply doing for loops. The complexity seems to be the same.
function findOdd(a) {
let m = {};
a.forEach(e => (m[e] in m) ? m[e] += 1 : m[e] = 1);
for (k in m) {
if (m[k] % 2 != 0) return k;
}
}
console.log(findOdd([1, 1, 3, 1, 1]));
console.log(findOdd([1, 1, 2, -2, 5, 2, 4, 4, -1, -2, 5]));
You could count all values first and then get the value with an odd count.
function getOddCount(array) {
var value,
count = {},
k;
for (value of array) count[value] = (count[value] || 0) + 1;
for (k in count) if (count[k] % 2) return +k;
}
console.log(getOddCount([1, 1, 3, 1, 1]));
console.log(getOddCount([1, 1, 2, -2, 5, 2, 4, 4, -1, -2, 5]));
A naive implementation would simply use an object to store the frequency of each element and then iterate over it at the end to find the element that appeared an odd amount of times.
function findOdd(arr) {
const freq = {};
for(const num of arr){
freq[num] = (freq[num] || 0) + 1;
}
return +Object.keys(freq).find(num => freq[num] % 2 == 1);
}
A more efficient implementation could leverage the properties of the bitwise XOR (^), namely the fact that a ^ a == 0 and that the operation is commutative and associative, leading to the solution of applying XOR on each element of the array to obtain the answer.
function findOdd(arr) {
return arr.reduce((a,c)=>a ^ c, 0);
}

Finding Greatest value on array of indexes

I have to find the greatest value of array and return its index position.
This is my snippets of code:
function findGreaterNumbers(array) {
for(var i = 1; i < array.length; i++) {
if(array[i].length !== 0) {
var result = Math.max.apply(null, [i]);
} else {
return 0;
}
}
return result;
}
console.log(findGreaterNumbers([1, 2, 3]); // 2: I want 3
console.log(findGreaterNumbers([6, 1, 2, 7])); // 3: I want 4
console.log(findGreaterNumbers([5, 4, 3, 2, 1])); // 4: I want 0
console.log(findGreaterNumbers([])); // undefined: I want 0
You can do the following:
const findMax = (arr) => {
const max = Math.max.apply(Math, arr);
return arr.indexOf(max);
}
First you create a function that receives an array arr then inside this function you find the array element with the highest value by using the JS built in Math.max method. If you return this value will show you the maximum value of the numbers in the array you've supplied.
In order to return the index you can use the indexOf array method to find its index. You return this value and you have the index of the maximum number in an array.
const input = [1,5,3,4,0,-1];
function getMaxIndex() {
const max = Math.max(...input);
return input.findIndex((item) => item === max);
}
console.log(getMaxIndex())
try this way!
function findGreaterNumbers(arr) {
let count = 0;
for (let i = 0; i < arr.length - 1; i++) {
for (let j = i + 1; j < arr.length; j++) {
if (arr[i] < arr[j]) {
count ++;
}
}
}
return count;
}
findGreaterNumbers([1,2,3]) // 3
findGreaterNumbers([6,1,2,7]) // 4
findGreaterNumbers([5,4,3,2,1]) // 0
findGreaterNumbers([]) // 0
Another way you can find max number by Math.max and find index of max from Array.indexOf
var numbers = [ 0, 1, 3, 2, 5, 10 , 4 ,6];
var max = Math.max(...numbers)
var index = numbers.indexOf(max)
console.log('Index of max', index)
I would go with the built-in map and reduce methods for arrays which are extremely useful. map transforms an array into another array of the same length, whereas reduce can be used to do any aggregation on the array itself. And finding lowest/highest values is just a special type of aggregation.
That said, the following method will give you all indices that correspond to the largest value:
function iMax(array) {
return array.reduce((m, d, i) => {
return (m.length === 0 || d > m[0].d)
? [{d: d, i: i}]
: (d === m[0].d ? m.concat({d: d, i: i}) : m)
}, [])
.map(d => d.i);
}
// Run tests
console.log(JSON.stringify([1, 2, 3]) + " => " + JSON.stringify(iMax([1, 2, 3])));
console.log(JSON.stringify([6, 1, 2, 7]) + " => " + JSON.stringify(iMax([6, 1, 2, 7])));
console.log(JSON.stringify([5, 4, 3, 2, 1]) + " => " + JSON.stringify(iMax([5, 4, 3, 2, 1])));
console.log(JSON.stringify([5, 4, 3, 5, 2, 1]) + " => " + JSON.stringify(iMax([5, 4, 3, 5, 2, 1])));
console.log(JSON.stringify([]) + " => " + JSON.stringify(iMax([])));
I also added an example with multiple max values. Note that indices in Javascript start with 0, if you need the indices you mentioned in your example, you can add 1 to the results (but I would not recommend it). Finally, if you need any other value than an empty array if there is no max value in the input array, you can have an if before returning the result.
Try and go for something simpler like:
function findGreaterNumbers(array) {
let max = array[0]; // initialize the maximum to the first element
array.forEach((value) => { // fancier for loop that iterates through the
// array, **value** is the placeholder for the
// members
if (value > max) {
max = value;
}
}); //after the forEach, max will have the largest value
return array.indexOf(max); // returns the index of max
}
Some more explanations: forEach

JavaScript: Writing this solution using higher order functions

I worked on a problem where you are given an array of numbers and a target sum, and it's your job to find a pair of numbers that sum up to the target number. Here was my solution using simple nested for loops:
function findPairForSum(integers, target) {
var output = [];
for (var i = 0; i < integers.length; i++) {
for (var j = 0; j < integers.length; j++) {
if (i !== j && integers[i] + integers[j] === target) {
output.push(integers[i], integers[j]);
return output;
}
}
}
return 'not possible';
}
findPairForSum([3, 34, 4, 12, 5, 2], 9); // --> [4, 5]
My question is, is there a cleaner way to write this solution using higher order functions (perhaps forEach?)
Here was my attempt to use forEach:
function findPairForSum(integers, target) {
var output = [];
integers.forEach(function(firstNum) {
integers.forEach(function(secondNum) {
if (firstNum + secondNum === target) {
output.push(firstNum, secondNum);
}
})
})
if (output === []) {
return 'not possible';
}
return output;
}
findPairForSum([3, 34, 4, 12, 5, 2], 9); // --> [ 4, 5, 5, 4 ]
I tried putting a return after the two pushes, but it did not return anything. So instead, I put the return at the very end.
Why won't it return after the initial two pushes? I want it to stop right there, and only push the two numbers. Instead, by putting the return at the end, it pushed 4 numbers. It should be [4,5] but I got something like [4,5,5,4].
Any advice and help would be much appreciated!
Assume we have the following set of numbers, and we must find a subset of 2 numbers whose sum is 9:
Numbers: 4, 5, 6
Your current code iterates both with i and j from 0 to length. This means that the following iterations match the condition:
Indices: 0, 1, 2
Numbers: 4, 5, 6 // (i) (j)
---------------- // ↓ ↓
i j // Numbers[0] + Numbers[1] === 9
j i // Numbers[1] + Numbers[0] === 9
As you can see, the numbers 4 and 5 are matched twice, in 2 iterations:
i === 0 && j === 1
i === 1 && j === 0
You can avoid this by making sure one simple condition is met:
j must at all times be greater than i
This condition can be met met by initializing j with i + 1 in the inner for loop:
for (var i = 0; i < integers.length; i++) {
for (var j = i + 1; j < integers.length; j++) {
// ...
}
}
This way, j can never be 0 when i is 1, because the inner for-loop will run to completion before i is ever incremented once more. Once that happens, a brand new inner for-loop is created, in which j is again set to i + 1. The following diagram is the result:
Indices: 0, 1, 2
Numbers: 4, 5, 6
----------------
i j
X i // ← j can never be 0 if (i === 1),
// so the same set is never evaluated twice.
In other words, only the following combinations for i and j are checked at most:
Indices: 0, 1, 2
----------------
i j
i j
i j
is there a cleaner way to write this solution using higher order functions (perhaps forEach?)
A for loop is actually a fine solution for your use-case. They allow you to break early - after the first time you find a valid pair of numbers. forEach or other array iterator functions on the other hand will always continue until all set indices are visited.
You are actually breaking early in your first example with the statement return output;
When you use forEach on a set of numbers with multiple valid sets, you'll always get back all numbers involved:
Indices: 0, 1, 2, 3
Numbers: 4, 5, 6, 3 // (i) (j)
------------------- // ↓ ↓
i j // Numbers[0] + Numbers[1] === 4 + 5 === 9
i j // Numbers[2] + Numbers[3] === 6 + 3 === 9
forEach, map, reduce and the like do not allow you to break early. The following snippet demonstrates this issue of the diagram above:
function findPairForSum(integers, target) {
var output = [];
integers.forEach(function(firstNum, i) {
// slice(i + 1) has the same effect as for (var j = i + 1; ...)
integers.slice(i + 1).forEach(function(secondNum, j) {
if (firstNum + secondNum === target) {
// There is no way here to stop the iteration of either
// forEach call... T_T
output.push(firstNum, secondNum);
}
});
})
if (output.length) {
return output;
}
return 'not possible';
}
console.log(findPairForSum([4, 5, 6, 3], 9)); // --> [4, 5, 6, 3]
This is why I highly recommend sticking with the for loops for this specific use case. With for loop you can simply return as you already did as soon as you encounter a valid set of numbers:
function findPairForSum(integers, target) {
for (var i = 0; i < integers.length; i++) {
for (var j = i + 1; j < integers.length; j++) {
if (integers[i] + integers[j] === target) {
return [integers[i], integers[j]];
}
}
}
return 'not possible';
}
console.log(findPairForSum([4, 5, 6, 3], 9)); // --> [4, 5]
This could be your solution:
function findPairForSum(arr, sum) {
var pairs = [];
arr.forEach(n1 => {
var n2 = arr.find(n2 => n1 + n2 == sum)
if (n2) pairs.push([n1, n2]);
});
return pairs;
}
var sums = findPairForSum([3, 34, 4, 12, 6, 2], 9);
console.log(sums)
The problem is, you iterate from the start of the array for the inner loop. You could use a copy which starts at the index of the outer loop plus one and exit early on a found value.
But this does not solves the problem with multiple pairs. The result is simply wrong.
function findPairForSum(integers, target) {
var output = [];
integers.forEach(function(firstNum, i) {
integers.slice(i + 1).some(function(secondNum) {
if (firstNum + secondNum === target) {
output.push(firstNum, secondNum);
return true;
}
});
});
return output.length && output || 'not possible';
}
// console.log(findPairForSum([3, 34, 4, 12, 5, 2], 9));
console.log(findPairForSum([3, 34, 4, 4, 12, 5, 2, 4, 5], 9));
For a solution, you need to remember which pairs are used. This approach works with only one loop and a hash table for counting missing values.
If a pair is found, the counter is decremented and the two values are pushed to the result set.
function findPairForSum(integers, target) {
var hash = Object.create(null),
output = [];
integers.forEach(function(value) {
if (hash[value]) {
output.push(target - value, value);
hash[value]--;
return;
}
hash[target - value] = (hash[target - value] || 0) + 1;
});
return output.length && output || 'not possible';
}
console.log(findPairForSum([3, 34, 4, 4, 12, 5, 2, 4, 5], 9));
This is expected, since you didn't compare the indexes.
This inner array should only loop through the indexes which larger than the outer index.
You can achieve this by using the 2nd parameter, index, in forEach's callback function:
const ints = [3, 34, 4, 12, 5, 6, 2];
function findPairForSum(integers, target) {
let result;
integers.forEach((val1, idx1) => {
integers.forEach((val2, idx2) => {
if (idx1 < idx2 && val1 + val2 === target) {
result = [val1, val2];
}
})
})
return result;
}
console.log(findPairForSum(ints, 9));
Use can reduce your array into another which has sum equals target value:
const ints = [3, 34, 4, 12, 6, 2];
const value = 9;
const resp = ints.reduce((acc, ele, idx, self) => {
let found = self.find(x => x + ele == value)
return found ? [found, ele] : acc;
}, []);
console.log(resp); // [3, 6]
You can use Array.prototype.some which will stop execution as soon as the condition becomes true. See below code.
function findPairForSum(arr, sum) {
var pairs = [];
arr.some(n1 => {
var n2 = arr.find(n2 => n1 + n2 == sum)
if (n2) {
pairs.push(n1, n2); return true;
};
return false;
});
return pairs.length > 0 ? pairs : "not possible";
}
console.log(findPairForSum([3, 34, 4, 12, 7, 2], 9));

Finding a non-consecutive number pair in an array

Given an array with a minimum length of 3 and a maximum length of 5, which always contains uniquely occurring integers from 0 to 4 in ascending order, I need to pick out two non-consecutive numbers from it. Non-consecutive refers to their numeric value, not their position in the array.
To clarify, here are examples of valid arrays:
[ 1, 2, 3 ]
[ 0, 1, 2, 4 ]
[ 0, 3, 4 ]
For the arrays above, valid answers could be, respectively:
[ 1, 3 ]
[ 0, 2 ], [ 0, 4 ] or [ 1, 4 ]
[ 0, 3 ] or [ 0, 4 ]
Furthermore, in those cases where there is more than one valid answer, I need it to be selected at random, if at all possible (for instance I don't want to favor sequences that begin with the lowest number, which is what would occur if I always began checking from left to right and stopped checking as soon as I found one valid solution).
What would be the most efficient way of tackling this problem in Javascript?
You could use two nested iterations and build an new array for choosing as random result.
function getNonConsecutives(array) {
return array.reduce((r, a, i, aa) => r.concat(aa.slice(i + 2).map(b => [a, b])), []);
}
console.log(getNonConsecutives([ 0, 1, 2, 4 ]));
.as-console-wrapper { max-height: 100% !important; top: 0; }
According to Bee157's answer, you could use a random choice with a constraint, like length for the first index and add the needed space for the second index.
The problem is, due to the nature of choosing the first number first, the distribution of the result is not equal.
function getNonConsecutives(array) {
var i = Math.floor(Math.random() * (array.length - 2));
return [
array[i],
array[Math.floor(Math.random() * (array.length - 2 - i)) + 2 + i]
];
}
console.log(getNonConsecutives([ 0, 1, 2, 4 ]));
demoFn(array) {
var i,j, y =[];
for (i=0; i<=array.length;i++) {
for (j = i + 1; j <= array.length; j++) {
if (array[j] && array[i]) {
if (array[j] !== array[i] + 1) {
y.push([array[i], array[j]]);
}
}
}
}
}
Take a random array and check it.
You can create a function using recursion that will pick random number in each iteration and loop all other elements and if condition is met add to array.
function findN(data) {
data = data.slice();
var r = []
function repeat(data) {
if (data.length < 2) return r;
var n = parseInt(Math.random() * data.length);
data.forEach(function(e, i) {
if (i != n) {
var a = data[n];
if (Math.abs(a - e) != 1 && r.length < 2) r.push(n < i ? [a, e] : [e, a])
}
})
data.splice(n, 1);
repeat(data)
return r;
}
return repeat(data)
}
console.log(findN([1, 2, 3]))
console.log(findN([0, 1, 2, 4]))
console.log(findN([0, 3, 4]))
Something like this should do it:
const pick = nums => {
// Pick a random number
const val = nums[Math.floor(Math.random() * nums.length) + 0];
// Filter out any numbers that are numerically consecutive
const pool = nums.filter(n => Math.abs(n - val) > 1);
// Pick another random number from the remainer
const other = pool[Math.floor(Math.random() * pool.length) + 0];
// Sort + return them
return [val, other].sort();
};
console.log(pick([0, 1, 2, 4]));
since you state that the array ellemnts are all unique, and that they are sorted.
It should suffice to take an random element
var index1=Math.floor(Math.random()*arr.length)
now any other element (except maybe the elemnts on position (index1 +/- 1) are not consecutive
So a new random element can be chosen excluding the first index.
var index2=Math.floor(Math.random()*arr.length);
if(index2==index1){
index2+=((index2<arr.length-1)?1:-1);
}
if(Math.abs(arr[index1]-arr[index2])<=1){
if(index2==0 && arr.length<4){
//set index2 to arr.length-1 and do check again, if not ok=> no result
if(!(arr[index1]-arr[arr.length-1]>=-1)){
return [arr[arr.length-1],arr[index1]];
}
}
else if(index2==arr.length-1 && arr.length<4){
//set index2 to 0 and do check again, if not ok=> no result
if(!(arr[index1]-arr[0]<=1)){
return [arr[0],arr[index1]];
}
}
else{
//if index2>index1 index2++
//else index2--
//always OK so no further check needed
index2+=(index2>index1?1:-1);
return [arr[index1],arr[index2]];
}
}
else{
//ok
return [arr[index1,arr[index2]];
}
return false;
if speed is not important, you can use a filter on the array to calculate a new array with all elements differing more then 1 unit of arr[index1]. and randomly select a new number from this new array.
Other attempt
function getNonConsecutive(arr){
var index1,index2,arr2;
index1=Math.floor(Math.random()*arr.length);
arr2=[].concat(arr);
arr2.splice((index1!==0?index1-1:index1),(index!==0?3:2));
if(arr2.length){
index2=Math.floor(Math.random()*arr2.length);
return [arr[index1],arr2[index2]];
}
else{
//original array has length 3 or less
arr2=[].concat(arr);
arr2.splice(index1),1);
for (var j=0,len=arr.length;j<len;j++){
if(Math.abs(arr1[index1]-arr2[j])>1){
return [arr[index1],arr2[j]];
}
}
}
return false
}

Categories

Resources