Related
I am trying to make a program that returns ["1-5"] if I give [1,2,3,4,5].
I have made it but I can't filter it. So I want a code that will filter my output code. Or any code that is better than mine.
let array = [1,2,3,5,6,7,8,10,11, 34, 56,57,];
let x = [];
for(let i = 0; i < array.length; i++){
for(let j = 0; j < array.length; j++){
if(array[i] + j == array[j]){
x.push(array[i] + "-" + array[j]);
}
if(array[j] > array[i] + j && array[j + 1]){
let y = array.slice(j, array.length)
array = y;
i, j = 0;
}
if(array[i] - array[i + 1] != -1 && array[i + 1] - array[i] != 1 && array[i + 1] != undefined){
x.push(array[i]);
}
}
}
console.log(x);
The phrasing of the question makes this somewhat difficult to answer, but based on your code snippet I can gather that you are either:
Attempting to find the range of the entire array OR
Attempting to find contiguous ranges within the array
Based on these interpretations, you could answer this question as follows:
function detectRange(a) {
// clone a
const b = [...a]
// remove first value
const min = max = b.splice(0, 1)[0]
// compute range
const range = b.reduce(({min, max}, i) => {
if(i < min) min = i
if(i > max) max = i
return { min, max }
}, {min, max})
return range
}
function detectRanges(a) {
// clone a
const b = [...a]
// remove first value
const min = max = b.splice(0, 1)[0]
// init ranges array
const ranges = [ ]
// compute ranges
const range = b.reduce(({min, max}, i) => {
if(i === max + 1) {
return {min , max: i}
} else {
ranges.push({min, max})
return {min: i, max: i}
}
}, {min, max})
// push the remaining range onto the array
ranges.push(range)
return ranges
}
function printRange(r) {
console.log(`["${r.min}-${r.max}"]`)
}
function printRanges(r) {
r.forEach(i => {
printRange(i)
})
}
// detect and print range of whole array
printRange(detectRange([1, 2, 3, 5, 6, 7, 8, 10, 11, 34, 56, 57]))
// detect and print only contiguous ranges within array
printRanges(detectRanges([1, 2, 3, 5, 6, 7, 8, 10, 11, 34, 56, 57]))
If you assume that the list is sorted, we only need to traverse the list sequentially. There's no need to have double-nested loops. If you maintain sufficient states, you can determine whether you are in a group and you merely manage the start versus the last element in the group.
To simplify things I made use of ES6 string interpolation ${start}-${last}.
let array = [1,2,3,5,6,7,8,10,11, 34, 56,57];
let result = [ ];
let hasStart = false;
let start = 0;
let last = 0;
for (let num of array) {
if (!hasStart) {
hasStart = true;
last = start = num;
continue;
}
if (num === last + 1) {
last = num;
continue;
}
result.push( start === last ? start : `${start}-${last}` );
last = start = num;
}
if (hasStart) {
result.push( start === last ? start : `${start}-${last}` );
}
console.log(result);
Input: [1,2,3,4,5]
Output: ["1-5"]
So I assume you want to get string in format:
["smallestelement-largestelement"]
var input1 = [1,2,3,4,5]
console.log( "["+'"'+Math.min(...input1)+"-"+Math.max(...input1)+'"'+"]")
If what you want is string in format:
["firstelement-lastelement"]
var input1 = [1,2,3,4,5]
console.log( "["+'"'+input1[0]+"-"+input1.pop()+'"'+"]")
If you have an integer array, and if you want to output the range, you could natively sort() it (you can also provide rules for sorting) and use shift() for the first element and slice(-1) for the last:
let arr = [4,1,5,3].sort();
console.log(arr.shift()+'-'+arr.slice(-1));
As said in the comments, you should clarify if you wish "1-57" for the snippet array, or describe your use case more broadly.
const array = [1, 2, 3, 5, 6, 7, 8, 10, 11, 34, 56, 57];
let s = null;
const result = array.sort((a, b) => a - b).reduce((p, c, i, arr) => {
if (!s) s = c;
if (c + 1 !== arr[i + 1]) {
p.push(s === c ? s : `${s}-${c}`);
s = null;
}
return p
}, [])
console.log(result);
I am attempting to add the results of doubling every other number in an array to a new array. However the code only seems to be pushing the first index that is doubled. I assume the problem is with the .push line but I am not sure. Thanks for any help!
Here is the code I have:
const addTwoDigits = n => {
return n % 10 + Math.floor(n / 10);
}
const validateCred = array => {
let sumNums = []
let i = array.length - 2
while (i > 0) {
let doubleNum = (array[i] * 2)
if (doubleNum > 9) {
let addedNum = addTwoDigits(doubleNum)
sumNums.push(addedNum)
} else {
sumNums.push(doubleNum)
}
i--;
return sumNums;
}
}
const testArray = [4, 2, 1, 6, 5, 7, 5]
console.log(validateCred(testArray));
I was hoping the sumNums array would contain every other digit doubled (starting with '' in the test array and moving left) but it only returns [ 5 ].
You returned the value in the loop. When the compiler comes in loop then first time it returns the value and break the loop.
const addTwoDigits = n => {
return n % 10 + Math.floor(n / 10);
}
const validateCred = array => {
let sumNums = []
let i = array.length - 2
while (i > 0) {
let doubleNum = (array[i] * 2)
if (doubleNum > 9) {
let addedNum = addTwoDigits(doubleNum)
sumNums.push(addedNum)
} else {
sumNums.push(doubleNum)
}
i--;
}
return sumNums;
}
const testArray = [4, 2, 1, 6, 5, 7, 5]
console.log(validateCred(testArray));
Your can try this code.
I am doing some coding practice and found some questions online.
I keep getting 1 integer lower than expected when looking to return the number of consecutive numbers inside an array.
function LongestConsecutive(arr) {
arr.sort((a,b) => {return a-b});
let highest = 0;
let counter = 0;
let prevNum;
arr.forEach((num,index,arr) => {
if (prevNum === undefined) {
prevNum = num
} else {
if (num + 1 == arr[index + 1]) {
counter += 1;
highest = Math.max(highest,counter)
} else {
counter = 0;
}
}
})
return highest;
}
for example, the input [5, 6, 1, 2, 8, 9, 7], should return 5 -- because when sorted, there are 5 consecutive numbers. I keep getting one lower than I should so for this example, I get 4. The only way to get the correct answer is when I return 'highest + 1', which obviously is avoiding the problem.
The first iteration will hit
if (prevNum === undefined) {
prevNum = num;
}
But isn’t that already the first consecutive number? So counter = 1; and highest = 1; should be here.
Next, you reset counter = 0; in an else case. Why? There’s at least one number that is consecutive, so reset it to 1 instead.
Then, you’re not really using prevNum for anything. if (prevNum === undefined) can be replaced by if (index === 1).
You then check if the current number (num) precedes the next number (arr[index + 1]), but you skip this check for the first index. How about checking if the current number succeeds the previous?
This code uses the above changes plus some code quality changes:
function longestConsecutive(arr) { // Non-constructor functions start with a lower-case letter
arr.sort((a, b) => a - b); // Use expression form
let highest = 0;
let counter = 0;
arr.forEach((num, index, arr) => {
if (index === 0) {
highest = 1;
counter = 1;
} else if (num - 1 === arr[index - 1]) { // Merge `else if`, use strict equal
counter += 1;
highest = Math.max(highest, counter);
} else {
counter = 1;
}
});
return highest;
}
Well, by the definition of consecutive, you'll always have 1 consecutive number. So you need to start the counter from 1.
I tried this code (its different than the one posted in the question) which gives the expected result. In addition, if there are two sets of consecutive numbers of same (and largest) length, both are printed,
var arr = [5, 6, 1, 2, 8, 9, 7, 99, 98];
arr.sort((a, b) => a - b);
var prevNum = arr[0];
var consecutiveNumbersArr = [prevNum];
// Map of consecutiveNumbersArr array as key and
// the array length as values
var arrMap = new Map();
for (let i = 1; i < arr.length; i++) {
let num = arr[i];
if (num === prevNum+1) {
prevNum = num;
consecutiveNumbersArr.push(num);
continue;
}
arrMap.set(consecutiveNumbersArr, consecutiveNumbersArr.length);
consecutiveNumbersArr = [];
consecutiveNumbersArr.push(num);
prevNum = num;
}
arrMap.set(consecutiveNumbersArr, consecutiveNumbersArr.length);
// the largest length of all the consecutive numbers array
var largest = 0;
for (let value of arrMap.values()) {
if (value > largest) {
largest = value;
}
}
// print the result - the largest consecutive array
for (let [key, value] of arrMap) {
if (value === largest) {
console.log("RESULT: " + key);
}
}
Can also be achieved with array:reduce
function longestRun(array) {
const { streak } = array
.sort((a, b) => a - b) // sort into ascending order
.reduce(({ count, streak }, current, index, arr) => {
if (current === arr[index - 1] + 1) {
count++; // increment if 1 more than previous
} else {
count = 1; // else reset to 1
}
return {count, streak: Math.max(streak, count)};
}, { count: 0, streak: 0 }); // initial value is 0,0 in case of empty array
return streak;
}
console.log(longestRun([])); // 0
console.log(longestRun([0])); // 1
console.log(longestRun([0, 1])); // 2
console.log(longestRun([0, 1, 0])); // 2
console.log(longestRun([0, 0, 0])); // 1
console.log(longestRun([2, 0, 1, 0, 3, 0])); // 4
If you are able to split arrays into subarrays via a condition, you can do it by splitting the array at non consecutive points.
const arr = [5, 6, 1, 2, 8, 9, 7, 11, 12, 13, 14]
// utility for splitting array at condition points
const splitBy = (arr, cond) => arr.reduce((a, cur, i, src) => {
if(cond(cur, i, src)){
a.push([])
}
a[a.length - 1].push(cur)
return a
}, [])
const consecutives = splitBy(
arr.sort((a, b) => a - b),
(cur, i, src) => cur !== src[i-1] + 1
).sort((a, b) => b.length - a.length)
// largest consecutive list will be the first array
console.log(consecutives[0].length)
My function should return the missing element in a given array range.
So i first sorted the array and checked if the difference between i and i+1 is not equal to 1, i'm returning the missing element.
// Given an array A such that:
// A[0] = 2
// A[1] = 3
// A[2] = 1
// A[3] = 5
// the function should return 4, as it is the missing element.
function solution(A) {
A.sort((a,b) => {
return b<a;
})
var len = A.length;
var missing;
for( var i = 0; i< len; i++){
if( A[i+1] - A[i] >1){
missing = A[i]+1;
}
}
return missing;
}
I did like above, but how to write it more efficiently??
You could use a single loop approach by using a set for missing values.
In the loop, delete each number from the missing set.
If a new minimum value is found, all numbers who are missing are added to the set of missing numbers, except the minimum, as well as for a new maximum numbers.
The missing numbers set contains at the end the result.
function getMissing(array) {
var min = array[0],
max = array[0],
missing = new Set;
array.forEach(v => {
if (missing.delete(v)) return; // if value found for delete return
if (v < min) while (v < --min) missing.add(min); // add missing min values
if (v > max) while (v > ++max) missing.add(max); // add missing max values
});
return missing.values().next().value; // take the first missing value
}
console.log(getMissing([2, 3, 1, 5]));
console.log(getMissing([2, 3, 1, 5, 4, 6, 7, 9, 10]));
console.log(getMissing([3, 4, 5, 6, 8]));
Well, from the question (as it's supposed to return a single number) and all the existing solution (examples at least), it looks like list is unique. For that case I think we can sumthe entire array and then subtracting with the expected sum between those numbers will generate the output.
sum of the N natural numbers
1 + 2 + ....... + i + ... + n we can evaluate by n * (n+1) / 2
now assume, in our array min is i and max is n
so to evaluate i + (i+1) + ..... + n we can
A = 1 + 2 + ..... + (i-1) + i + (i+1) + .... n (i.e. n*(n+1)/2)
B = 1 + 2 + ..... + (i-1)
and
C = A - B will give us the sum of (i + (i+1) + ... + n)
Now, we can iterate the array once and evaluate the actual sum (assume D), and C - D will give us the missing number.
Let's create the same with each step at first (not optimal for performance, but more readable) then we will try to do in a single iteration
let input1 = [2, 3, 1, 5],
input2 = [2, 3, 1, 5, 4, 6, 7, 9, 10],
input3 = [3, 4, 5, 6, 8];
let sumNatural = n => n * (n + 1) / 2;
function findMissing(array) {
let min = Math.min(...array),
max = Math.max(...array),
sum = array.reduce((a,b) => a+b),
expectedSum = sumNatural(max) - sumNatural(min - 1);
return expectedSum - sum;
}
console.log('Missing in Input1: ', findMissing(input1));
console.log('Missing in Input2: ', findMissing(input2));
console.log('Missing in Input3: ', findMissing(input3));
Now, lets try doing all in a single iteration (as we were iterating 3 times for max, min and sum)
let input1 = [2, 3, 1, 5],
input2 = [2, 3, 1, 5, 4, 6, 7, 9, 10],
input3 = [3, 4, 5, 6, 8];
let sumNatural = n => n * (n + 1) / 2;
function findMissing(array) {
let min = array[0],
max = min,
sum = min,
expectedSum;
// assuming the array length will be minimum 2
// in order to have a missing number
for(let idx = 1;idx < array.length; idx++) {
let each = array[idx];
min = Math.min(each, min); // or each < min ? each : min;
max = Math.max(each, max); // or each > max ? each : max;
sum+=each;
}
expectedSum = sumNatural(max) - sumNatural(min - 1);
return expectedSum - sum;
}
console.log('Missing in Input1: ', findMissing(input1));
console.log('Missing in Input2: ', findMissing(input2));
console.log('Missing in Input3: ', findMissing(input3));
Instead of sorting, you could put each value into a Set, find the minimum, and then iterate starting from the minimum, checking if the set has the number in question, O(N). (Sets have guaranteed O(1) lookup time)
const input1 = [2, 3, 1, 5];
const input2 = [2, 3, 1, 5, 4, 6, 7, 9, 10];
const input3 = [3, 4, 5, 6, 8];
function findMissing(arr) {
const min = Math.min(...arr);
const set = new Set(arr);
return Array.from(
{ length: set.size },
(_, i) => i + min
).find(numToFind => !set.has(numToFind));
}
console.log(findMissing(input1));
console.log(findMissing(input2));
console.log(findMissing(input3));
If the array is items and the difference between missing and present diff is 1:
const missingItem = items => [Math.min(...items)].map(min => items.filter(x =>
items.indexOf(x-diff) === -1 && x !== min)[0]-diff)[0]
would give complexity of O(n^2).
It translates to: find the minimum value and check if there isn't a n-diff value member for every value n in the array, which is also not the minimum value. It should be true for any missing items of size diff.
To find more than 1 missing element:
([Math.min(...items)].map(min => items.filter(x =>
items.indexOf(x-diff) === -1 && x !== min))[0]).map(x => x-diff)
would give O((m^2)(n^2)) where m is the number of missing members.
Found this old question and wanted to take a stab at it. I had a similar thought to https://stackoverflow.com/users/2398764/koushik-chatterjee in that I think you can optimize this by knowing that there's always only going to be one missing element. Using similar methodology but not using a max will result in this:
function getMissing(arr) {
var sum = arr.reduce((a, b) => a + b, 0);
var lowest = Math.min(...arr);
var realSum = (arr.length) * (arr.length + 1) / 2 + lowest * arr.length;
return realSum - sum + lowest;
}
With the same inputs as above. I ran it in jsperf on a few browsers and it is faster then the other answers.
https://jsperf.com/do-calculation-instead-of-adding-or-removing.
First sum everything, then calculate the lowest and calculate what the sum would be for integers if that happened to be the lowest. So for instance if we have 2,3,4,5 and want to sum them that's the same as summing 0,1,2,3 and then adding the lowest number + the amount of numbers in this case 2 * 4 since (0+2),(1+2),(2+2),(3+2) turns it back into the original. After that we can calculate the difference but then have to increase it once again by the lowest. To offset the shift we did.
You can use while loop as well, like below -
function getMissing(array) {
var tempMin = Math.min(...array);
var tempMax = tempMin + array.length;
var missingNumber = 0;
while(tempMin <= tempMax){
if(array.indexOf(tempMin) === -1) {
missingNumber = tempMin;
}
tempMin++;
}
return missingNumber;
}
console.log(getMissing([2, 3, 1, 5]));
console.log(getMissing([2, 3, 1, 5, 4, 6, 7, 9, 10]));
console.log(getMissing([3, 4, 5, 6, 8]));
My approach is based on in place sorting of the array which is O(N) and without using any other data structure.
Find the min element in the array.
Sort in place.
Again loop the array and check if any element is misplaced, that is the answer!
function getMissing(ar) {
var mn = Math.min(...ar);
var size = ar.length;
for(let i=0;i<size;i++){
let cur = ar[i];
// this ensures each element is in its right place
while(cur != mn +i && (cur - mn < size) && cur != ar[cur- mn]) {
// swap
var tmp = cur;
ar[i] = ar[cur-mn];
ar[cur-mn] = tmp;
}
}
for(let i=0; i<size; i++) {
if(ar[i] != i+mn) return i+mn;
}
}
console.log(getMissing([2, 3, 1, 5]));
console.log(getMissing([2, 3, 1, 5, 4, 6, 7, 9, 10]));
console.log(getMissing([3, 4, 5, 6, 8]));
var o = [1,2,3,5,6,7,8]
var res = o.reduce(function(x,y){
return !((y-x)===1)?y-1:'Nothing'
})
console.log(res)//7
Output should be 4, want to know if it is possible using reduce or functionally (Not through loops)? it only works if the missing value is before the last value of an array.
You can use reduce to compute the actual sum of all elements and then subtract it from the target sum (n(a0+an)/2). This gives you the missing number.
var o = [1,2,3,5,6,7,8];
var len = o.length;
var sum = (len + 1) * (o[0] + o[len - 1]) / 2;
var res = sum - o.reduce((x,y) => x + y);
console.log(res);
Note that this works with any starting value and any step, e.g. for [3,5,7,11] it will correctly print 9. The only requirement is that o should be an arithmetic progression.
You could use a start value and check the previous element and the actual element.
var o = [1, 2, 3, 5, 6, 7, 8],
res = o.reduce(function(r, a, i, aa) {
return !i || r !== undefined || aa[i - 1] + 1 === a ? r : aa[i - 1] + 1;
}, undefined);
console.log(res);
Instead of reduce you could use find, which will not look any further once it finds a missing value:
const o = [1,2,3,5,6,7,8];
const res = o.find( (x,i) => o[i+1]-x > 1 ) + 1;
console.log(res)//4
It's always good to generalize these jobs. So you should provide a series descriptor function for the algorithm to find which item is missing in the series. Let's do it;
function findMissingItem(a,s){
return s(a[a.findIndex((f,i,a) => i ? f !== s(a[i-1]) : false)-1]);
}
var data1 = [1,2,3,5,6,7,8],
data2 = [1,4,9,16,36,49,64,81],
series1 = n => n+1,
series2 = n => Math.pow(Math.sqrt(n)+1,2);
res1 = findMissingItem(data1,series1),
res2 = findMissingItem(data2,series2);
console.log(res1);
console.log(res2);
Here's a simple solution using Array.reduce and the ES6 arrow function for brevity.
const array = [1, 2, 3, 5, 6, 7, 8];
const result = array.reduce((result, x) => x > result ? result : x + 1, 1)
console.log(result); // 4
With a little refactoring, we can start to make the solution more generic.
const sequence = [1, 2, 3, 5, 6, 7, 8];
const result = sequence.reduce(missingLinkReducer, sequence[0])
function missingLinkReducer(expected, actual) {
return expected === actual ? nextValue(expected) : expected;
}
function nextValue(value) {
return value + 1;
}
console.log(result);
Going a little bit further, we can make it so that different functions can be plugged in for calculating the next value.
const sequence = [1, 2, 3, 5, 6, 7, 8];
const result = sequence.reduce(createMissingLinkReducer(increment), sequence[0]);
console.log(result + ' is missing from ' + sequence);
const sequenceB = [1, 2, 4, 8, 16, 64, 128];
const resultB = sequenceB.reduce(createMissingLinkReducer(double), sequenceB[0]);
console.log(resultB + ' is missing from ' + sequenceB);
function createMissingLinkReducer(nextValue) {
return function missingLinkReducer(expected, actual) {
return expected === actual ? nextValue(expected) : expected;
}
}
function increment(value) {
return value + 1;
}
function double(value) {
return value * 2;
}
You can use every for this, below will work for any sequence interval you specify - it will return -1 if all elements are in sequence, or the element that doesn't fit:
var o = [1, 4, 7, 10, 11]
var seqInterval = 3;
function getMissing(arr, interval) {
var hit = -1;
var res = arr.every(function(e, i) {
hit = i === 0 ? hit : ((e - interval) === arr[i - 1] ? -1 : e);
return hit === -1;
});
return hit;
}
console.log(getMissing(o, seqInterval));
var o1 = [1,2,3,5,6,7,8];
var seqInterval1 = 1;
console.log(getMissing(o1, seqInterval1));