Bonfire Algorithm Challenge: Where Do I Belong on javascript - javascript

Hello guys I am currently stuck on this algorithm challenge on FCC. This is what the challenge is all about:
Return the lowest index at which a value (second argument) should be inserted into an array (first argument) once it has been sorted. The returned value should be a number.
For example, getIndexToIns([1,2,3,4], 1.5) should return 1 because it is greater than 1 (index 0), but less than 2 (index 1).
Likewise, getIndexToIns([20,3,5], 19) should return 2 because once the array has been sorted it will look like [3,5,20] and 19 is less than 20 (index 2) and greater than 5 (index 1).
This is my code here:
function getIndexToIns(arr, num) {
var getIndx;
var newArr = arr.sort(function (a, b) {
return (a - b);
});
for (i = 0; i < newArr.length; i++) {
if (num > newArr[i]) {
getIndx = newArr.indexOf(newArr[i]);
}
}
return getIndx;
}
getIndexToIns([10, 20, 30, 40, 50], 35);
when I ran the code it worked but it isn't passing the test. Guys I need your help. Thanks

The solutions proposed so far tend to follow literally the request of the problem: first sort the array, then find the index where to insert the number. That brings you to loop over the array twice. More if you have to clone the array. That is slow, even without considering all the garbage we end up creating ...
Can we do better? I think so.
How about "count how many numbers in the array are less or equal to the number to insert". This achieves the same goal but let's us do it looping only once over the array.
function getIndexToIns(arr, num) {
return arr.reduce(function (c, x) { return x <= num ? c+1 : c }, 0);
}
console.log(getIndexToIns([10, 20, 30, 40, 50], 35)); // 3
console.log(getIndexToIns([20,3,5], 19)); //2
console.log(getIndexToIns([1,2,3,4], 1.5)); //1
console.log(getIndexToIns([1,2,3,4], 1)); //1
console.log(getIndexToIns([1,2,3,4], 0)); //0
how about that?! twice as fast*, yay!
* it's probably not really twice as fast, if you have to be nitpicky about my claims...
EDIT
Actually I can do better. That ternary if introduces some branching in the code that bothers me. We could take advantage of javascript weirdness to avoid it
arr.reduce(function (c, x) { return c + (x <= num) }, 0)
why? because when combined with a numeric operation true is converted to 1 and false to 0
That removes the extra branching from the code so it's going to be slightly faster than the previous version ... And it would also be easier to unit test, if you care about that.

You could iterate and check if the actual value is greater then the number. Then retuen the actual index. If no value match, then return the length of the array as new input index.
function getIndexToIns(arr, num) {
var i;
arr.sort(function(a, b){
return a - b;
});
for (i = 0; i < arr.length; i++) {
if (arr[i] > num) {
return i;
}
}
return arr.length;
}
console.log(getIndexToIns([10, 20, 30, 40, 50], 35)); // 3
console.log(getIndexToIns([1, 2, 3, 4], 1.5)); // 1
console.log(getIndexToIns([20, 3, 5], 19)); // 2
console.log(getIndexToIns([4, 3, 2, 1], 5)); // 4
Alternative version without using a method from the Array API
function getIndexToIns(array, value) {
var i = array.length,
p = 0;
while (i--) {
p += array[i] <= value;
}
return p;
}
console.log(getIndexToIns([10, 20, 30, 40, 50], 35)); // 3
console.log(getIndexToIns([1, 2, 3, 4], 1.5)); // 1
console.log(getIndexToIns([20, 3, 5], 19)); // 2
console.log(getIndexToIns([4, 3, 2, 1], 5)); // 4

If I understand correctly I think you should look at the previous item from the list:
function getIndexToIns(arr, num) {
var getIndx = 0;
var newArr = arr.sort(function (a, b) { return (a - b); });
for (i = 1; i < newArr.length; i++) {
if (num >= newArr[i-1]) {
getIndx = i;
}
}
return getIndx;
}
console.log(getIndexToIns([10, 20, 30, 40, 50], 35)); // 3
console.log(getIndexToIns([20,3,5], 19)); //2
console.log(getIndexToIns([1,2,3,4], 1.5)); //1
console.log(getIndexToIns([1,2,3,4], 1)); //1
console.log(getIndexToIns([1,2,3,4], 0)); //0

Thanks Guys for all your assistance. I figured it out and this is the final code here
function getIndexToIns(arr, num) {
var getIndx;
var newArr = arr.sort(function(a, b){
return (a - b);
});
for (i = 0; i < newArr.length; i++) {
if (newArr[i] > num || newArr[i] === num) {
return i;
}
}
return newArr.length;
}

My solution to this problem.
const getIndexToIns = (arr, num) => {
let newArr = arr.concat(num);
newArr.sort(function(a, b) {
return a - b;
});
let index = newArr.indexOf(num);
return index;
}

Related

Get 5 closest elements to an element in array including that element

I am trying to get 5 closest elements to given element, including that element, in array. For example, if we have:
const arr = [1, 2, 3, 4, 7, 11, 12, 13, 15, 17]
and I want to get 5 closest elements to 11, it should return [4, 7, 11, 12, 13]. If i pass 1 it should return [1, 2, 3, 4, 7]. If I pass 15 it should return [11, 12, 13, 15, 17].
I'm not sure what you meant;
You might've meant a code to find the element and return the five nearest elements to it by place in the array;
Or you might've meant a code to find the 5 numbers closest to a number you say.
IF you meant the first case
There are two ways to do so,
A value as a parameter
Use this code:
function closestNByValue(arr, value, n) {
let ind = arr.indexOf(value);
let finalArr = [];
if (n > arr.length) {
finalArr = Array.from(arr);
} else if (ind == -1) {
finalArr = [];
} else if (ind <= n/2 - 0.5) {
finalArr = arr.slice(0, n);
} else if (ind >= (arr.length - n/2) - 0.5) {
finalArr = arr.slice(-n);
} else if (n%2 == 0) {
finalArr = arr.slice(ind-(n/2), ind+(n/2));
} else {
finalArr = arr.slice(ind-(n/2 - 0.5), ind+(n/2 + 0.5));
}
return finalArr;
}
console.log(closestNByValue([1, 2, 3, 4, 7, 11, 12, 13, 15, 17], 11, 5))
How does it do the job?
Okay first we need to find the index of the value and save it in ind (short form of 'index') and we check multiple different situations for what the ind is so we'd be able to output the best answer as finalArr.
There are two exceptions; what if there was no such value in our array? then ind = -1 and we'd return an empty array; or what if the number of elements nearby that we seek is larger than or equal to the arr.length? then we'd return all of the arr.
But if there were no exceptions, there are three different situations for the ind; first, ind is a number that makes us have all of the finalArr values from the first of arr, second, ind be a number that makes us have all of the finalArr values from the last of arr, and third, ind being a number that we have to select half from the indexes smaller than ind and half, larger.
If it is the third way, the way we select we'd be different depending on the oddity of the numbers we want to select.
And we'll have a conditional statement for each situation and return the finalArr.
An index as a parameter
function closestNByIndex(arr, ind, n) {
let finalArr = [];
if (n > arr.length) {
finalArr = Array.from(arr);
} else if (ind == -1) {
finalArr = [];
} else if (ind <= n/2 - 0.5) {
finalArr = arr.slice(0, n);
} else if (ind >= (arr.length - n/2) - 0.5) {
finalArr = arr.slice(-n);
} else if (n%2 == 0) {
finalArr = arr.slice(ind-(n/2), ind+(n/2));
} else {
finalArr = arr.slice(ind-(n/2 - 0.5), ind+(n/2 + 0.5));
}
return finalArr;
}
console.log(closestNByIndex([1, 2, 3, 4, 7, 11, 12, 13, 15, 17], 5, 5))
Similar to the first code it works, though we have the index and we don't search for it.
The point is, if you use the function with value, it'd do the nearest 5 elements of the first value that equals the entry but such confusion is not being tolerated in the second code.
IF you meant the second case
This is a code I coded:
const arr = [1, 2, 3, 4, 7, 11, 12, 13, 15, 17];
function allDiff(arr, num1, num2) {
const finalArr = [];
const x = Math.abs(num2 - num1);
for (let y = 0; y < arr.length; y++) {
if (Math.abs(arr[y] - num1) == x) {
finalArr.push(arr[y]);
}
}
return finalArr;
}
function deleteArr(arr, delet) {
for (let x = 0; x < arr.length; x++) {
if (delet.includes(arr[x])) {
delete arr[x];
}
}
return arr;
}
function closest(arr, num) {
const map = new Map()
arr2 = Array.from(arr);
let key, value;
for (let x = 0; x < arr2.length; x++) {
key = Math.abs(arr2[x] - num);
value = allDiff(arr2, num, arr2[x]);
arr2 = deleteArr(arr2, value);
map.set(key, value);
}
return map;
}
function closestN(arr, num, n) {
const map = closest(arr, num);
const mapKeys = Array.from(map.keys());
const mapKeysSorted = mapKeys.sort(function(a, b) {
return a - b
});
let finalArr = [];
let y;
for (let i = 0; i < mapKeysSorted.length; i++) {
if (n <= 0) {
break;
}
y = map.get(mapKeysSorted[i]);
if (n < y.length) {
finalArr = finalArr.concat(y.slice(0, n + 1));
break;
}
finalArr = finalArr.concat(y);
n -= y.length;
}
return finalArr;
}
console.log(closestN(arr, 11, 5));
It might be a little too long, but I have programmed it as you can give it any array (arr) with integer values, an integer (num) that you'd like it to be the base and another integer (n) for the number of the size of the output array, 5 in this case.
Explaining the code
The function closest would return a map of (the difference between the numbers, a list of the numbers in the arr that differs the number equal to their key).
The main function, closestN, calls the closest function and saves the map in the map variable.
Then it sorts the keys of the map in mapKeysSorted.
Now, a for loop loops through the mapKeySorted array and pushes new elements to the finalArr until the size of the finalArr reaches the number of elements we seek.
The main function is the closestN.
Here's a way to get to your goal:
To start, first thing to do is finding the index of the wanted number in the array. Example index of 1 in your array arr is 0. The index will help in extracting the numbers later on. The method findIndex will help us in finding the index.
Then, we need to find the position at which will start extaracting the closest numbers (in terms of position not value). As seen from the desired output you have provided, usually you want the returned array to be in the following structure:
output: [
2 nearest numbers (from N left),
the wanted number,
2 nearest numbers (from N right)
]
This can get tricky so we should make sure to deal with some edge case like when the wanted element is sitting at position 0.
Extract the numbers and return them as an array as described by your desired output. The use of slice method will come in handy here which allow us to extract the numbers just as we need.
Here's a live demo demonstrating solution:
const arr = [1, 2, 3, 4, 7, 11, 12, 13, 15, 17],
/** a function that returns an array containing the "5" (depending on "arr" length that could be less) nearest numbers (in terms of position) in "arr" array to the supplied number "n" */
findClosestNumbers = n => {
/** make sure we don't exceed the array length */
const toTake = 5 > arr.length ? arr.length : 5,
/** find the index of the wanted nulber "n", if "-1" is returned then "n" cannot be found ion the array "arr" */
idx = arr.findIndex(el => n == el),
/**
* from where we should start returning the nearest numbers (the position of the first number to extract from "arr"
* the below condition help deal with some edge cases like when "n" is the last element in "arr"
*/
startIdx = idx + toTake / 2 > arr.length ?
arr.length - 5 :
(idx - 2 >= 0 ?
idx - 2 :
0);
/** return the nearest numbers or return an empty array "[]" if the number "n" is not found on the array "arr" */
return idx == -1 ? [] : arr.slice(startIdx, startIdx + 5);
};
/** run for various scenarios */
console.log('For 1 =>', findClosestNumbers(1));
console.log('For 11 =>', findClosestNumbers(11));
console.log('For 15 =>', findClosestNumbers(15));
console.log('For 17 =>', findClosestNumbers(17));
.as-console-wrapper {
max-height: 100%!important;
}
The demo above is meant to help you understand how things could work and it is not the only way to get to your goal. Also, because I kept it as simple as possible, the above demo is wide open for improvements.

how to return the lowest index of the array?

For example, getIndexToIns([1,2,3,4], 1.5) should return 1 because it is greater than 1 (index 0), but less than 2 (index 1).
Likewise, getIndexToIns([20,3,5], 19) should return 2 because once the array has been sorted it will look like [3,5,20] and 19 is less than 20 (index 2) and greater than 5 (index 1).
this is my code
function getIndexToIns(arr, num) {
// Find my place in this sorted array.
arr = arr.sort();
num = Math.floor(num);
for(let i=0;i<arr.length;i++){
}
return num;
}
getIndexToIns([690, 60], 59);
You can use .findIndex() to find the first element in your sorted array which is larger than your passed num element:
const getIndexToIns = (arr, num) => {
const res = arr.sort((a, b) => a-b).findIndex(n => n > num);
return res === -1 ? arr.length : res;
}
console.log(getIndexToIns([1,2,3,4], 1.5));
console.log(getIndexToIns([20,3,5], 19));
console.log(getIndexToIns([20,3,5], 100)); // 3 (array length)
Here the solution
function getIndexToIns(arr, num) {
var counter = 0;
// Find my place in this sorted array.
arr = arr.sort();
num = Math.floor(num);
for (let i = 0; i < arr.length; i++) {
if (num > arr[i]) {
counter++
} else {
break;
}
}
return counter;
}
var count = getIndexToIns([690, 60, 55, 2], 59);
console.log(count);
This is like one small part of insertion sort (which you can read about here).
What you are trying to do is to just compare the num with each element of sorted array arr, until you find a number which is greater than num.
So it'd look something like this:
for(let i=0;i<arr.length;i++){
if(num <= arr[i])
return i;
}
function getIndexToIns(arr, num) {
var return_val;
// Find my place in this sorted array.
arr = arr.sort();
num = Math.floor(num);
for(let i=0;i<arr.length;i++){
if(arr[i]>num){
return_val = arr[i-1];
}
}
return return_val;
}
var return_value = getIndexToIns([690, 60], 59);
console.log(return_value);
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
Try this
function getIndexToIns(arr, num) {
// Find my place in this sorted array.
var index = 0
arr.sort((a, b) => a - b)
for (let i = 0; i < arr.length; i++) {
if (num > arr[i]) {
} else {
index = i
break
}
}
return index;
}
console.log(
getIndexToIns([1, 2, 3, 4], 1.5)
)
here is a code you may try
function getIndexToIns(a, b) {
let ind = 0;
for (var i = 0; i < a.length; i++) {
if (b < a[i]) {
ind++;
}
}
return ind
}
console.log(getIndexToIns([20, 3, 5], 19));
Because arr.sort() sorting does not sort the array accurately, check this: Array.sort() doesn't sort numbers correctly
This code is working fine
function getIndexToIns(arr, num) {
// Find my place in this sorted array.
arr.sort(function(a, b) { return a - b; });
num = Math.floor(num);
//console.log(arr)
var found = arr.findIndex(function(e) {
return e > num;
});
return found;
}
console.log(
getIndexToIns([1, 2, 3, 4], 1.5),
getIndexToIns([20, 3, 5], 19),
getIndexToIns([20, 3, 5], 19)
)

JavaScript codewars task

For the past few hours I have been trying to solve one of the CodeWars challenge - but without any luck - so that is the Task -
https://www.codewars.com/kata/554ca54ffa7d91b236000023/train/javascript - link to the task
Task
Given a list lst and a number N, create a new list that contains each number of lst at most N times without reordering. For example if N = 2, and the input is [1,2,3,1,2,1,2,3], you take [1,2,3,1,2], drop the next [1,2] since this would lead to 1 and 2 being in the result 3 times, and then take 3, which leads to [1,2,3,1,2,3].
and that is an example --
Example
deleteNth ([1,1,1,1],2) // return [1,1]
deleteNth ([20,37,20,21],1) // return [20,37,21]
function deleteNth(arr,x){
for (var i = 0; i<arr.length; i++){
for(var j = i+1; j<arr.length; j++){
var crr = 1;
if(arr[i]===arr[j])
crr =+ 1;
while(crr>=x){
arr.splice(arr[j], 1);
crr--;
}
}
return arr;
}
That is my code and idea - As I am a beginner in JS can you give me suggestions and tell me if my idea is good or not. Also I know that i have made some mistakes - so if possible - point them out
totals object will keep a counter for each value of the array.
function deleteNth(arr, x) {
let totals = {};
return arr.filter(o => (totals[o] = ++totals[o] || 0) < x);
}
console.log(deleteNth([1, 1, 1, 1], 2));
console.log(deleteNth([20, 37, 20, 21], 1));
A simple approach will be:
const deleteNth = (lst, N) => {
const res = [];
const countNums = {};
lst.forEach((el, idx) => {
countNums[el] = countNums[el] ? countNums[el] + 1 : 1;
if(countNums[el] <= N) {
res.push(el);
}
})
return res;
}
console.log(deleteNth([1,2,1, 3,1,2,3,3, 5], 2))
result => [ 1, 2, 1, 3, 2, 3, 5 ]

How do I get the first two closest numbers to a target from an array using lodash?

I'm new to lodash and just getting the feel for functional programming with javascript. I'm using lodash 3.0.0-pre.
I have an array of numbers that are in order and a target number.
I need an array with the first and second closest numbers unless it was the last number then I just need it. How do I get that using lodash?
I found:
function getClosest(array, target) {
var tuples = _.map(array, function(val) {
return [val, Math.abs(val - target)];
});
return _.reduce(tuples, function(memo, val) {
return (memo[1] < val[1]) ? memo : val;
}, [-1, 999])[0];
}
I could change it to give me the closest two instead of one but I believe it will sequence through the entire array instead of just stopping once it has the two numbers it needs since it can stop when the difference in numbers starts to increase.
I would recommend not to use lodash looping functions here if you care about performance.
As soon as you array is ordered - it's good to use a modified version of Binary search to find index of the closest value:
function closestIndex(arr, target) {
var i = 0, j = arr.length - 1, k;
while (i <= j) {
k = Math.floor((i+j) / 2);
if (target === arr[k] || Math.abs(i - j) <= 1 ) {
return k;
} else if (target < arr[k]) {
j = k-1;
} else {
i = k+1;
}
}
return -1;
}
and then simply compare adjacent elements in the array:
if (_.isNumber(arr[closestIndex - 1]) && _.isNumber(arr[closestIndex + 1])) {
if (Math.abs(target - arr[closestIndex - 1]) < Math.abs(target - arr[closestIndex + 1])) {
result.push(arr[closestIndex - 1]);
} else {
result.push(arr[closestIndex + 1]);
}
}
See full example here.
Not really a lodash task because it's not an easy n -> n or n -> 1 transformation. Additionally lodash doesn't allow you to cancel a statement early.
Anyway here's a solution:
var array= [2, 3, 5, 25, 135, 250, 300];
function getClosest(array, target) {
var tuples = _.map(array, function(val) {
return [val, Math.abs(val - target)];
});
var prev= [0, Number.MAX_VALUE];
for(var i=0; i<tuples.length; i++){
if(tuples[i][1] < prev[1]){
prev= tuples[i];
}else{
if(i<2 || tuples[i][1] < tuples[i-2][1]){
return [prev[0], tuples[i][0]];
}else{
return [prev[0], tuples[i-2][0]];
}
}
}
return [prev[0]];
}
console.log(getClosest(array, 3));
Could be optimized by finding the nearest element with Newton's method and then looking at elements before and after that. (If you have like 50000 numbers in your array ^^)
Assuming that your array is sorted and arr[0] ≤ target:
var getClosests = function (arr, target) {
var last = _.last(arr)
if (target > last) {
return [last];
}
var index = _.findIndex(arr, function(a) { return target - a <= 0 });
neighbours = [arr[index-1], arr[index], arr[index+1]]
return _.chain(neighbours).sortBy(function(a) {
return Math.abs( a - target) })
.take(2).value()
}
getClosests([2, 3, 5, 25, 135, 250, 300], 100);
getClosests([2, 3, 5, 25, 135, 250, 300], 25);
getClosests([2, 3, 5, 25, 135, 250, 300], 400);
Find two Closet to given Goal in Array: (without Lodash)
function findCloset(givenList, goal) {
var first;
var second;
var finalCollection = [givenList[0], givenList[1]];
givenList.forEach((item, firtIndex) => {
first = item;
for (let i = firtIndex + 1; i < givenList.length; i++) {
second = givenList[i];
if (first + second < goal) {
if (first + second > finalCollection[0] + finalCollection[1]) {
finalCollection = [first, second];
}
}
}
});
return finalCollection;
}
var counts = [2, 42, 82, 329, 122, 40, 162, 202, 3, 5, 242, 282, 322, 35, 362];
var goal = 80;
console.log(findCloset(counts, goal));

Processing an array by sub arrays

Suppose we have an array of variable length, and I want to process it by chunks that are of a maximum length of 100, and do it in the minimum number of chunks. So for an array of length 241, it would be 3 sub arrays of sizes 41, 100, 100 (or 100, 100, 41).
curr_len = arr.length;
offset = curr_len%100;
doSomethingWithSubArray(arr.slice(offset))
for(j = offset; j <= curr_len; j = j+100){
doSomethingWithSubArray(arr.slice(j,j+100))
}
I'm sure there are more elegant ways of doing this, possibly without the special case before the for loop. Any ideas?
I'd expect the last chunk to be of smaller size. The code then would be:
for (var i=0; i<arr.length; i+=100)
doSomethingWithSubArray(arr.slice(i, 100));
This is exactly what my splitBy function does:
Array.prototype.splitBy = function(n) {
/* get: number of items per array
return: array of n-sized arrays with the items (last array may contain less then n) */
for (var r=[], i=0; i<this.length; i+=n)
r.push(this.slice(i, i+n));
return r;
}
Then write only:
arr.splitBy(100).forEach(doSomethingWithSubArray);
use chunk function~
function chunk(a, s){
for(var x, i = 0, c = -1, l = a.length, n = []; i < l; i++)
(x = i % s) ? n[c][x] = a[i] : n[++c] = [a[i]];
return n;
}
console.log(chunk([1,2,3,4,5,6,7,8,9,10], 3));
it's functional style recursive solutions.
no var, no loop, no count, because it's more cleary
var chunk = function(arr, n){
if (arr.length == 0) return [];
var head = arr.slice(0, n), rest = arr.slice(n);
return [head].concat( chunk(rest, n) );
};
console.log(chunk([1,2,3,4,5,6,7,8,9,10], 3));​
Not really, using reduce looks like this:
var array = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11];
var splitArrays = array.reduce(function(arr, cur, i) {
if (i % 3 === 0) arr.push([]);
arr[i / 3 | 0].push(cur);
return arr;
}, []);
//splitArrays looks like:
//[[1,2,3],[4,5,6],[7,8,9],[10,11]]
More generic function
function splitArray(array, num) {
return array.reduce(function(arr, cur, i) {
if (i % num === 0) arr.push([]);
arr[i / num | 0].push(cur);
return arr;
}, []);
}
Make your doSomethingWithSubArray function accept a starting index and return a next unprocessed index or null if there's no more work. Put this "iterator" in a while loop. Do rest of work that you want to do between chunks (update UI?) right after calling this "iterator" in a while condition.

Categories