Process array from the middle out - javascript

I need to go through an array from the middle outwords.
var array = [a,b,c,d,e];
I would need to print in this order:
c,d,b,e,a
I have already split the array in half, first going forward and then going backwards which is already an improvement, but I really need to go one on each side till the end of the array on each side.
Say I want to start in the middle. I have the following before the loop statement, condition, and I can't seem to figure out the third part to switch one on each side incrementally.
for (var i = Math.floor(array.length/2); i >= 0 || i < array.length; i?){
//Do Something here.
}
Does anyone know how to do this?
Obviously I can't seem to test this in this condition.
Thanks
I modified the answer below (Thanks so much) to come up with this function. It allows to start from anywhere in the array and choose the direction to go. I am sure it could be written more elegantly. There is also a safety for wrong index numbers.
var array = ["a", "b", "c", "d", "e"];
function processArrayMiddleOut(array, startIndex, direction){
if (startIndex < 0){
startIndex = 0;
}
else if ( startIndex > array.length){
startIndex = array.lenght-1;
};
var newArray = [];
var i = startIndex;
if (direction === 'right'){
var j = i +1;
while (j < array.length || i >= 0 ){
if (i >= 0) newArray.push(array[i]);
if (j < array.length) newArray.push(array[j]);
i--;
j++;
};
}
else if(direction === 'left'){
var j = i - 1;
while (j >= 0 || i < array.length ){
if (i < array.length) newArray.push(array[i]);
if (j >= 0) newArray.push(array[j]);
i++;
j--;
};
};
return newArray;
}
var result = processArrayMiddleOut(array, 2, 'left');
alert(result.toString());
http://jsfiddle.net/amigoni/cqCuZ/

Two counters, one going up, other going down:
var array = ["a", "b", "c", "d", "e"];
var newArray = [];
var i = Math.ceil(array.length/2);
var j = i - 1;
while (j >= 0)
{
newArray.push(array[j--]);
if (i < array.length) newArray.push(array[i++]);
}
http://jsfiddle.net/X9cQL/

So I decided to revisit this, not feeling very satisfied with the first answer I gave. I was positive there would be some relationship between the index numbers when the data is successfully reordered; I found that pattern in the addition of the iteration number to the last item position.
For our initial array, we'll use the following: ['a', 'b', 'c', 'd', 'e'].
Our starting point is Math.floor( arr.length / 2 ), which gives us 2, corresponding to c in the array values. This is on iteration 0. The following instructions detail how we walk through an array with an odd number of values:
Position | Direction | Iteration | New Position | Value at Position
----------+-----------+-----------+--------------+-------------------
2 | - | 0 | 2 | c
2 | + | 1 | 3 | d
3 | - | 2 | 1 | b
1 | + | 3 | 4 | e
4 | - | 4 | 0 | a
You'll see a pattern developing, when our iteration is odd we add it to our location to find our new position. When the iteration is negative, we subtract it from our position to find the new location.
When dealing with an array that has an even number of values, the rules are flipped. When you have an even number of values, we subtract odd iterations from location to get the new position, and add even iterations to our location to find the next value.
To demonstrate how little code is needed to perform this sorting logic, below is a minified version of the above logic (the aforementioned link is far more readable):
// DON'T USE THIS IN PRODUCTION, OR YOUR TEAM MAY KILL YOU
function gut(a){
var o=[],s=a.length,l=Math.floor(s/2),c;
for(c=0;c<s;c++)o.push(a[l+=(s%2?c%2?+c:-c:c%2?-c:+c)]);
return o
}
Implementing the above logic in a more readable manner:
// Sort array from inside-out [a,b,c,d,e] -> [c,d,b,e,a]
function gut( arr ) {
// Resulting array, Counting variable, Number of items, initial Location
var out = [], cnt,
num = arr.length,
loc = Math.floor( num / 2 );
// Cycle through as many times as the array is long
for ( cnt = 0; cnt < num; cnt++ )
// Protecting our cnt variable
(function(){
// If our array has an odd number of entries
if ( num % 2 ) {
// If on an odd iteration
if ( cnt % 2 ) {
// Move location forward
loc = loc + (+cnt);
} else {
// Move location backwards
loc = loc + (-cnt);
}
// Our array has an even number of entries
} else {
// If on an odd iteration
if ( cnt % 2 ) {
// Move location backwards
loc = loc + (-cnt);
} else {
// Move location forwards
loc = loc + (+cnt);
}
}
// Push val at location to new array
out.push( arr[ loc ] );
})()
// Return new array
return out;
}

Okay, let's solve this problem step by step:
An array may either have an odd or an even number of elements:
If the array has an odd number of elements:
The middle element is at index (array.length - 1) / 2. Let this index be called mid.
There are mid number of elements to the left of the middle element. Obviously.
There are mid number of elements to the right of the middle element.
If the array has an even number of elements:
The middle element is at index array.length / 2. Let this index be called mid.
There are mid number of elements to the left of the middle element. Obviously.
There are mid - 1 number of elements to the right of the middle element.
Now let's create a function to tackle this problem using the above known data:
function processMidOut(array, callback) {
var length = array.length;
var odd = length % 2; // odd is 0 for an even number, 1 for odd
var mid = (length - odd) / 2; // succinct, isn't it?
callback(array[mid]); // process the middle element first
for (var i = 1; i <= mid; i++) { // process mid number of elements
if (odd || i < mid) // process one less element if even
callback(array[mid + i]); // process the right side element first
callback(array[mid - i]); // process the left side element next
}
}
That's all that there is to it. Now let's create some arrays and process them mid out:
var odd = ["a", "b", "c", "d", "e"];
var even = ["a", "b", "c", "d", "e", "f"];
var oddOrder = "";
var evenOrder = "";
processMidOut(odd, function (element) {
oddOrder += element;
});
processMidOut(even, function (element) {
evenOrder += element;
});
alert(oddOrder);
alert(evenOrder);
You can find a working demo here: http://jsfiddle.net/xy267/1/

Very interesting algorithm. Here is what I came with:
walkMidleOut = function(arr, callback) {
var mid = (arr.length - arr.length % 2) / 2;
for (var i = 0; i < arr.length; i++) {
var s = -1,
j = (i % 2 ? (s = 1, i + 1) : i) / 2,
index = mid + s * j == arr.length ? 0 : mid + s * j;
callback.call(arr, arr[index], index);
}
}
Usage:
walkMidleOut([1,2,3,4,5], function(el, index) {
console.log(el, index);
});
Will give you:
3 2
4 3
2 1
5 4
1 0
Function can be used with any number of elements, odd or even.

How about using concat() and slice()? You can just pass this the index of the middle element.
Array.prototype.eachFrom = function(index){
var index = index > this.length ? 0 : index;
return [].concat(this.slice(index), this.slice(0, index));
}
so for example:
var arr = ['a', 'b', 'c', 'd', 'e'], arr = arr.eachFrom(2);
for( var i = 0; i < arr.length; i++ ) { doFunThings(); }

Using underscore and _( Object ).Sort_Inside_Out():
_.mixin( {
Sort_Inside_Out: function ( Object ) {
Counter = 0
return (
_( Object ).sortBy( function ( Element ) {
Counter =
-Counter + (
( Math.sign( Counter ) == 1 ) ?
0 :
1 )
return ( Counter )
} ) )
},
} )

Here is a simple way to start at any index in an array and loop both forward and backward at the same time (i.e., iterate through all the items starting with items closest to the index and moving farther away).
let passing = 0;
function bothSides(arr, idx) {
newArr = [];
const shortLen = Math.min(idx, arr.length - idx);
for (let i = 0; i < shortLen; i++) {
newArr.push(arr[idx + i]); // add next
newArr.push(arr[idx - i - 1]); // add previous
}
for (let i = idx + shortLen; i < arr.length; i++) {
newArr.push(arr[i]); // add any remaining on right
}
for (let i = idx - shortLen - 1; i > -1; i--) {
newArr.push(arr[i]); // add any remaining on left
}
return newArr;
}
var arr = [...Array(10).keys()]; // 0,1,2,3,4,5,6,7,8,9
passing += bothSides(arr, 0) == '0,1,2,3,4,5,6,7,8,9' ? 1 : 0;
passing += bothSides(arr, 2) == '2,1,3,0,4,5,6,7,8,9' ? 1 : 0;
passing += bothSides(arr, 4) == '4,3,5,2,6,1,7,0,8,9' ? 1 : 0;
passing += bothSides(arr, 5) == '5,4,6,3,7,2,8,1,9,0' ? 1 : 0;
passing += bothSides(arr, 7) == '7,6,8,5,9,4,3,2,1,0' ? 1 : 0;
passing += bothSides(arr, 9) == '9,8,7,6,5,4,3,2,1,0' ? 1 : 0;
// same algorigthm but as generator
function* bothSidesG(arr, idx) {
const shortLen = Math.min(idx, arr.length - idx);
for (let i = 0; i < shortLen; i++) {
yield arr[idx + i]; // add next
yield arr[idx - i - 1]; // add previous
}
for (let i = idx + shortLen; i < arr.length; i++) {
yield arr[i]; // add any remaining on right
}
for (let i = idx - shortLen - 1; i > -1; i--) {
yield arr[i]; // add any remaining on left
}
}
var arr2 = [...Array(7).keys()]; // 0,1,2,3,4,5,6
passing += [...bothSidesG(arr2, 0)] == '0,1,2,3,4,5,6' ? 1 : 0;
passing += [...bothSidesG(arr2, 1)] == '1,0,2,3,4,5,6' ? 1 : 0;
passing += [...bothSidesG(arr2, 3)] == '3,2,4,1,5,0,6' ? 1 : 0;
passing += [...bothSidesG(arr2, 5)] == '5,4,6,3,2,1,0' ? 1 : 0;
passing += [...bothSidesG(arr2, 6)] == '6,5,4,3,2,1,0' ? 1 : 0;
console.log(`Passing ${passing} of 11 tests`);

Related

Loop the array, and add values to start Javascript

What i need to do - simple task - I am looping the array. When array[i] === 0;
i want to +1 to start, it will be the same for array[i] === 1.
But when array[i] will go back (be back where it was a moment ago) i don't want to +1 to start, and i did that code :
var start = 0;
var array = [0,1,0,0,1,0,0,1];
for (i=0; i < array.length; i ++) {
if (array[i] === 0) {
start += 1;
if (array[i + 1] === 1) {
start -= 1;
}
}
else if (array[i] === 1) {
start += 1;
if (array[i + 1] === 0) {
start -= 1;
}
}
}
console.log(start)
But what if array = [0,1,1,1,0,0,0,1,0,0,0,1]; , if array[i] will go back where it was a long time ago? I dont want then +1 to start.
Imagine 0 and 1 like -1 and +1 on chart, so console.log(start) from array = [0,1,1,1,0,0,0,1,0,0,0,1] should be 5.
My code is some kind of hard coding, have you any ideas how to fix that?
Thanks for answers in advance!
Example from comments
[0,1,1,1,0,0,0,1,0,0,0,1] should produce a result of 5; you need to imagine 0 == -1 and 1 == +1.
Then the array looks like [-1,+1,+1,+1,-1,-1,-1,+1,-1,-1,-1,+1] and begins this from 0 we have 5 positions where i was only 1 time.
As it looks like, you need to count the changes of the values in the array. You need to store the last value for checking the next value. If the last value and the actual value is different, you got a change and need to count.
function getChanges(array) {
var count = 0,
last = array[0],
i;
for (i = 1; i < array.length; i++) {
if (last !== array[i]) {
count++;
last = array[i];
}
}
return count;
}
console.log(getChanges([0, 1, 0, 0, 1, 0, 0, 1]));
console.log(getChanges([0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 1]));
As #nurdyguy has pointed out, your call for array[i+1] will be out of bounds for the last element. I have flipped the comparison to the previous element and started the loop on the second element to counter this.
You seem to be calculating +=1 regardless of the binary result then only -=1 when the next element in the array differs so essentially i think you have the opposite of what you are looking for :
var start = 0;
var array = [0,1,0,0,1,0,0,1];
for (i=1; i < array.length; i++) {
if (array[i] === array[i-1]) {
start++;
}
}
Now if you want to calculate the times the element changes from each step then you can just flip the logical:
var start = 0;
var array = [0,1,0,0,1,0,0,1];
for (i=1; i < array.length; i++) {
if (array[i] !== array[i-1]) {
start++;
}
}
console.log("The result is: " + start) // The result is: 5
I think this is what you are after, please elaborate if not.
Edit:
Apologies, I did test your other array and the result was also 5.
What you are looking for is this then:
var start = 0;
var array = [0,1,1,1,0,0,0,1,0,0,0,1];
for (i=0; i < array.length; i++) {
start += array[i];
}
console.log("The result is: " + start) // The result is: 5
If the array of 0 and 1 is only as an example then use a logical:
var start = 0;
var array = [0,1,1,1,0,0,0,1,0,0,0,1];
for (i=0; i < array.length; i++) {
array[i] == 1 ? ++start : +-start;
}
console.log("The result is: " + start) // The result is: 5
or:
var start = 0;
var array = [0,1,1,1,0,0,0,1,0,0,0,1];
for (i=0; i < array.length; i++) {
if (array[i] == 1) {
++start
}
}
console.log("The result is: " + start) // The result is: 5
If the array becomes [-1,1,1,1,-1,-1,-1,1,-1,-1,-1,1] like you said then the result is not 5, it's -3?

Find all permutations of smaller string s in string b (JavaScript)

I've been trying to find a O(n) solution to the following problem: Find the number of anagrams (permutations) of string s in string b, where s.length will always be smaller than b.length
I read that the optimal solution involves keeping track of the frequencies of the characters in the smaller string and doing the same for the sliding window as it moves across the larger string, but I'm not sure how that implementation actually works. Right now my solution doesn't work (see comments) but even if it did, it would take O(s + sn) time.
EDIT: Sample input: ('aba', 'abaab'). Output: 3, because 'aba' exists in b starting at index 0, and 'baa' at 1, and 'aab' at 2.
function anagramsInStr(s,b) {
//O(s)
let freq = s.split("").reduce((map, el) => {
map[el] = (map[el] + 1) || 1;
return map;
}, {});
let i = 0, j = s.length;
// O(n)
for (let char in b.split("")) {
// O(s)
if (b.length - char + 1 > s.length) {
let window = b.slice(i,j);
let windowFreq = window.split("").reduce((map, el) => {
map[el] = (map[el] + 1) || 1;
return map;
}, {});
// Somewhere about here compare the frequencies of chars found in the window to the frequencies hash defined in the outer scope.
i++;
j++;
}
}
}
Read through the comments and let me know if you have any questions:
function countAnagramOccurrences(s, b) {
var matchCount = 0;
var sCounts = {}; // counts for the letters in s
var bCounts = {}; // counts for the letters in b
// construct sCounts
for (var i = 0; i < s.length; i++) {
sCounts[s[i]] = (sCounts[s[i]] || 0) + 1;
}
// all letters that occur in sCounts
var letters = Object.keys(sCounts);
// for each letter in b
for (var i = 0; i < b.length; i++) {
// maintain a sliding window
// if we already have s.length items in the counts, remove the oldest one
if (i >= s.length) {
bCounts[b[i-s.length]] -= 1;
}
// increment the count for the letter we're currently looking at
bCounts[b[i]] = (bCounts[b[i]] || 0) + 1;
// test for a match (b counts == s counts)
var match = true;
for (var j = 0; j < letters.length; j++) {
if (sCounts[letters[j]] !== bCounts[letters[j]]) {
match = false;
break;
}
}
if (match) {
matchCount += 1;
}
}
return matchCount;
}
console.log(countAnagramOccurrences('aba', 'abaab')); // 3
EDIT
A note about the runtime: this is sort of O(nk + m), where n is the length of s, m is the length of b, and k is the number of unique characters in b. Since m is always less than n, we can reduce to O(nk), and since k is bounded by a fixed constant (the size of the alphabet), we can further reduce to O(n).

Find out which one of the given numbers differs from the others for Javascript

I'm trying to solve this exercise. There is a string of numbers and among the given numbers the program finds one that is different in evenness, and returns a position of this number. The element has to be returned by its index (with the number being the actual position the number is in). If its index 0, it has to be returned as 1. I have this so far but it's not passing one test. I'm not too sure why because it feels like it should. Is anyone able to see what the error is? Any help is appreciated!
function iqTest(numbers) {
var num = numbers.split(" ");
var odd = 0;
var even = 0;
var position = 0;
for(var i = 0; i < num.length; i++) {
if(num[i]%2!==0) {
odd++;
if(odd===1) {
position = num.indexOf(num[i]) + 1;
}
}
else if(num[i]%2===0) {
even++;
if(even===1) {
position = num.indexOf(num[i]) + 1;
}
}
}
return position;
}
iqTest("2 4 7 8 10") output 3
iqTest("2 1 2 2") output 2
iqTest("1 2 2") outputs 2 when it should be 1
The simplest way is to collect all even/odd positions in subarrays and check what array has the length 1 at the end:
function iqTest(numbers) {
numbers = numbers.split(' ');
var positions = [[], []];
for (var i = 0; i < numbers.length; i++) {
positions[numbers[i] % 2].push(i + 1);
}
if(positions[0].length === 1) return positions[0][0];
if(positions[1].length === 1) return positions[1][0];
return 0;
}
console.log(iqTest("2 4 7 8 10"))
console.log(iqTest("2 1 2 2"))
console.log(iqTest("1 2 2"))
console.log(iqTest("1 3 2 2"))
Your code is overly complex.
Since the first number determines whether you're looking for an even number or an odd one, calculate it separately. Then, find the first number that doesn't match it.
function iqTest(numbers) {
numbers = numbers.split(" ");
var parity = numbers.shift() % 2;
for( var i=0; i<numbers.length; i++) {
if( numbers[i] % 2 != parity) {
return i+2; // 1-based, but we've also skipped the first
}
}
return 0; // no number broke the pattern
}
That being said, iqTest("1 2 2") should return 2 because the number in position 2 (the first 2 in the string) is indeed the first number that breaks the parity pattern (which 1 has established to be odd)
You have to define which "evenness" is the different one. Use different counters for the two cases, and return -1 if you don't have a single different one. Something like this:
function iqTest(numbers) {
var num = numbers.split(" ");
var odd = 0;
var even = 0;
var positionOdd = 0;
var positionEven = 0;
for(var i = 0; i < num.length; i++) {
if(num[i]%2!==0) {
odd++;
if(odd===1) {
positionOdd = i + 1;
}
}
else if(num[i]%2===0) {
even++;
if(even===1) {
positionEven = i + 1;
}
}
}
if (odd == 1)
return positionOdd;
else if (even == 1)
return positionEven;
else
return -1;
}
Note that, if you have exactly a single even number and a single odd one, the latter will be returned with the method of mine. Adjust the logic as your will starting from my solution.
Since the first number determines whether you're looking for an even number or an odd one, calculate it separately.
Then, find the first number that doesn't match it.
function iqTest(numbers){
// ...
const numArr = numbers.split(' ');
const checkStatus = num => (parseInt(num) % 2) ? 'odd' : 'even';
const findUniqueStatus = array => {
let numEvens = 0;
array.forEach(function(value){
if (checkStatus(value) == 'even') { numEvens++; }
});
return (numEvens === 1) ? 'even' : 'odd'
}
let statuses = numArr.map(checkStatus),
uniqueStatus = findUniqueStatus(numArr);
return statuses.indexOf(uniqueStatus) + 1;
}
}
public static int Test(string numbers)
{
var ints = numbers.Split(' ');
var data = ints.Select(int.Parse).ToList();
var unique = data.GroupBy(n => n % 2).OrderBy(c =>
c.Count()).First().First();
return data.FindIndex(c => c == unique) + 1;
}

Find first missing number in a sequence of numbers

I am trying to figure out how to find the first missing number of a sequence of numbers like this (1,2,3,5,6,9,10,15)
I want to put the first missing number, #4, into an variable for later use but don't know how to do so?
I have tried this but this only gives me the last number:
var mynumbers=new Array(1,2,3,6,9,10);
for(var i = 1; i < 32; i++) {
if(mynumbers[i] - mynumbers[i-1] != 1) {
alert("First missing number id: "+mynumbers[i]);
break;
}
}
First of all it gives me the first number after an "hole" in the numbersequence, secondly it continues to alert all numbers comming after an "hole" if I don't insert an break. I only want the first missing number of an numbersequence from 1 - 32. How do i do so?
Hoping for help and thanks in advance ;-)
How about this
var mynumbers = new Array(1,2,3,6,9,10);
var missing;
for(var i=1;i<=32;i++)
{
if(mynumbers[i-1] != i){
missing = i;
alert(missing);
break;
}
}
The O(n) solutions are easy , but this is a common interview question and often we look for O(log n) time solution. Here is the javascript code. It's basically a modified binary search.
function misingNumInSeq(source, min = 0, max = source.length - 1){
if(min >= max){
return min + 1;
}
let pivot = Math.floor((min + max)/2);
// problem is in right side. Only look at right sub array
if(source[pivot] === pivot + 1){
return misingNumInSeq(source, pivot + 1, max);
} else {
return misingNumInSeq(source, min , pivot);
}
}
Output
misingNumInSeq([1,2,3,5,6,9,10,15])
4
By if(mynumbers[i] - mynumbers[i-1] != 1), you mean to say the series will always be incrementing by 1?
var missing = (function (arr) {
var i;
for (i = 0; i < arr.length; ++i) {
if (i + arr[0] !== arr[i]) return i + arr[0];
}
if (i < 32) // if none missing inside array and not yet 32nd
return i + arr[0]; // return next
}([1,2,3,6,9,10])); // 4
alert(missing);
You're going to need the break no matter what. That's what it's there for; to stop the loop from continuing on to the end. And you should use the length of the array instead of hardcoding 32 as the end condition, because your numbers only go up to 32, but there are possibly holes in the list so there will not be 32 elements in the array.
Since you know that each element should be 1 more than the previous element, then the number in the hole is clearly mynumbers[i - 1] + 1.
var mynumbers = new Array(1,2,3,6,9,10);
for(var i = 1; i < mynumbers.length; i++) {
if(mynumbers[i] - mynumbers[i-1] != 1) {
alert("First missing number id: " + (mynumbers[i - 1] + 1));
break;
}
}
EDIT: This only holds true for the missing number not being 1. To catch that, you will need to check if (mynumbers[0] != 1)
Edit:
function findFirstMissing(array) {
for (var i = 0; i < array.length; i++) {
if (i+1 !== array[i]) {
return i+1;
}
}
}
function findFirstMissing(array) {
for (var i = 0; i < array.length; i++) {
if (array[i+1] - array[i] !== 1) {
return array[i] + 1;
}
}
}
If you do it this way then storing it in a variable is easy:
var missing = findFirstMissing(array);
const firstNonConsecutive = arr => arr.find((el, i, arr) => (arr[i] - arr[i-1]) !== 1 && i !== 0)
this solution work for an array of positive numbers.
A solution using array.reduce to find the first positive missing integer.
function solution(A) {
return [...A].sort().reduce((acc, curr, i, arr) => {
if (acc > curr) {
arr.splice(1);
return acc;
}
else if (arr[i + 1] - curr > 1 || arr.length === i + 1) {
arr.splice(1);
return curr + 1;
}
return acc;
}, 1);
}
And here are few test cases:
console.log('solution([1, 3, 6, 4, 1, 2])', solution([1, 3, 6, 4, 1, 2]) === 5)
console.log('solution([1, 3, 2, 8, 4])', solution([1, 3, 2, 8, 4]) === 5)
console.log('solution([1])', solution([1]) === 2)
console.log('solution([-1])', solution([-1]) === 1)
console.log('solution([0])', solution([0]) === 1)
console.log('solution([-1, -4, -5, -6, -190343])', solution([-1, -4, -5, -6, -190343]) === 1)
Sometimes you just want simple if you know it's a small array:
let numbers = [1,2,3,6,9,10]
let m = 0
for (const i of numbers) if (i > ++m) break
console.log(m) // 4
Works if you remove 1 from start of array:
numbers = [2,3,6,9,10]
m = 0
for (const i of numbers) if (i > ++m) break
console.log(m) // 1
If the array can be contiguous, and if so you want the next highest number, then:
numbers = [1,2,3,4,5,6,7,8,9]
m = 0
for (const i of numbers) if (i > ++m) break
if (m == Math.max(...numbers)) m++
console.log(m) // 10
Short and sweet!
//Find the missing number in a series
//output must be 12 in a table of 3 given in below series
let abc = [3, 6, 9, 15, 18, 21, 24];
var def = [],
ghi = [];
for (var i = 1; i <= abc.length; i++) {
if (i !== abc.length) {
var diff = abc[i] - abc[i - 1];
if (def.includes(diff) === false) {
def.push(diff);
} else {
ghi.push(diff);
}
}
}
var finalArr = [];
if (ghi.length > def.length) finalArr = ghi;
else finalArr = def;
var finaldiff = finalArr[0];
var finalVal = abc.find((e, i) => {
if (e !== abc.length) {
var diff = abc[i] - abc[i - 1];
return diff > finaldiff;
}
})
console.log(finalVal - diff);
for(var i = 1; i < mynumbers.length; i++) {
if(mynumbers[i] - mynumbers[i-1] != 1) {
alert("First missing number id: "+mynumbers[i-1]+1);
i = mynumbers.length; // Replace the break
}
}
If you want you can add an initial check : if (mynumbers[0] != 1) { ... }
I think this is the simplest and optimum form of just a 2-step solution.
I think no better solution can be possible for this problem than this one.
This code uses minimum no. of variables, loops, conditionals, built-in functions and all the shitty, sloppy, unnecessary code.
This code can handle array of any length.
var mynumbers = new Array(76,77,78,79,80,81,82,83,84,125);
if(mynumbers.length > 1) {
for(var i=0; i<=mynumbers.length-1; i++) {
if(mynumbers[i+1] - 1 !== mynumbers[i]) {
alert("First Missing Term is : "+parseInt(mynumbers[i]+1));
break;
}
}
}

Map and match ranges in javascript

What is the most effective to map ranges using Arrays in JavaScript?
I have this:
var def = [70,200,1000];
And an array of possible numbers, say:
var n = [23,45,74,120,240,800,1204,2000];
Now, how can I extract the closest value from n that matches the values from def?
In the example above, I would get [74,240,800]. I hope I make myself clear...
Here is a try. Iterate over def and n just once:
var nIndex = 0,
nlen = n.length,
prev,
next;
for(var i = 0, ilen = def.length; i < ilen && nIndex < nlen; i++) {
var current = def[i];
while (n[nIndex] < current && nIndex < nlen - 1) nIndex++;
next = n[nIndex];
prev = nIndex == 0 ? next : n[nIndex - 1];
result[i] = current - prev < next - current ? prev : next;
}
// values in def are larger than the greatest value in n
while (result.length < def.length) result.push(n[nlen-1]);
fiddle
http://jsfiddle.net/8bY2M/
var def = [70,200,1000];
var n = [23,45,74,120,240,800,1204,2000];
var result = [];
for (var i = 0; i < def.length; i++){
var val = def[i];
for (var j = 0; j < n.length; j++){
var nVal = n[j];
if (nVal > val){
var closest = n[j-1] == undefined ? nVal :
nVal - val > val - n[j-1] ? n[j-1] : nVal;
result.push(closest);
break;
}
}
}
console.log(result); // outputs: [74, 240, 800]
Note that this will go with the larger value in the event of two matches. (i.e. if you are trying to match 70, and n contains 66 and 74, this will match it with 74)
Other solutions are pretty simple, but if you're looking for efficiency, your best bet is to pre-sort the initial list (if it's not sorted already) and then perform a binary search. Here's my solution:
var def = [70,200,1000];
var n = [23,45,74,120,240,800,1204,2000];
var findClosest = function(n, def) {
var i, result = [];
n = n.sort(function(a, b) { return a - b; }); //numeric sort
var closestN = (function(val) {
return (function search(r) {
var mid = r.low + (0 | ((r.high - r.low) / 2));
if(n[mid] === val) {
return n[mid];
}
if((r.high - r.low) === 1) {
return n[r[(Math.abs(n[r.low] - val) > Math.abs(n[r.high] - val)) ? "high" : "low"]];
}
r[(val < n[mid]) ? "high" : "low"] = mid;
return search(r);
}({low : 0, high: (n.length - 1)}));
});
for (i=0; i<def.length; i++) {
result.push(closestN(def[i]));
}
return result;
};
//The result can be obtained with findClosest(n, def)
Mind you, it's not very readable (if you're not familiar with binary search algorithms) and if you're looking for a simple solution where performance isn't important, a linear search would result in more maintainable code. But this solution runs in O(n log(n)) time, instead of O(n^2) time like a linear search would.
You can see it in action here:
http://jsfiddle.net/naYu6/
Note that in the case of a "tie" (where two values in the list are equidistant from the value in question, the lower of the two will be picked).

Categories