Related
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.
I'm trying to create a function that groups an array of numbers based on a length parameter. The length represents the max length of each sub-array. The code works as it is meant to for getting the sub arrays, but what I'd like to do is make it sort by odd and even.
function myFunctionA(myArr1, myVal) {
newArr = [];
for ( x = 0; x < myArr1.length; x += myVal) {
newArr.push(myArr1.slice(x, x + myVal));
}
return newArr;
}
Console.log(myfunction([1,2,3,4,5,6,7,8,9,10],3))
This returns [[1,2,3],[4,5,6],[7,8,9],[10]]
What I'd like to do is go through each sub array at a time until the sub arrays are the correct length and add any leftover values to a sub array/s
This would look like
[[1,3,5][2,4,6][7,9][8,10]]
Since arr 0 and arr 1 are the correct length that we have stated in the console.log statement, 7 8 9 and 10 are left over. But since the can't create a full sub array and they are odds and even, they form two sub arrays with a side of 2.
Other examples:
myfunction([1,2,3,4,5,6,7],2)
Should return [[1,3],[2,4],[5,7],[6]]
myfunction([1,2,3,4,5,6,7,8],1)
Should return [[1][2][3][4][5][6][7][8]]
You could take an array for collecting all odd and even values and then push the group if it has zero items. By having the wanted size, create a new array.
function chunkenator(array, size, fn) {
let groups = [],
result = [];
for (let value of array) {
const group = fn(value);
if (!groups[group]) groups[group] = [];
if (!groups[group].length) result.push(groups[group]);
groups[group].push(value);
if (groups[group].length === size) groups[group] = [];
}
return result;
}
console.log(chunkenator([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], 3, x => x % 2));
console.log(chunkenator([1, 3, 5, 7, 8, 9, 11, 13, 15], 3, x => x % 2));
One possibility would be to first seperate the numbers into even and odd numbers and then just loop over it, pushing the numbers into a new array switching between even and odd numbers.
It's not the cleanest piece of code, but it works.
function myfunction(arr, n) {
const evenOdd = arr.reduce((acc, e) => {
const ind = +(e % 2 === 0);
acc[ind] = acc[ind] || [];
acc[ind].push(e);
return acc;
}, []);
let ind = 0, res = [[]];
while (evenOdd[0].length || evenOdd[1].length) {
for (let i = n; i--;) {
const val = evenOdd[ind].shift();
if (val) res[res.length - 1].push(val)
}
ind = (ind + 1) % 2
res.push([])
}
res.pop()
return res;
}
for (const n of [1, 2, 3]) {
console.log(n,
myfunction([1, 2, 3, 4, 5, 6, 7, 8], n)
)
}
My goal here is to find the prime numbers:
let arr = [2, 3, 4, 6, 9, 10, 11, 15];
let ret = [];
arr.filter((z, ind) => {
if (ind > 0) {
ret.every(x => {
!Number.isInteger(z / x) ? ret.push(z) : false;
});
} else {
ret.push(z);
}
});
console.log(ret); // should be: [2,3,11]
It works for even numbers, but it doesn't work for the odd.
Fixed your code:
let arr = [2,3,4,6,9,10,11,15]
let ret = [];
arr.filter((z, ind) => {
if(ind > 0){
if(ret.every( x => !Number.isInteger(z/x)) ){
ret.push(z)
}
} else { ret.push(z) }
})
console.log(ret)
The Array.filter() method returns an array, so no need to generate the array by pushing the elements to an external array.
The prime check is easier with a for loop. Check that the number doesn't produce an integer if divided by all the numbers between 2 and half its size (rounded down). We need to check all half way, because every number that is greater than half the number we are checking, would produce a result that is less than 2, and 2 is the smallest integer divisor of a number.
const arr = [2, 3, 4, 6, 9, 10, 11, 15];
const isPrime = num => {
if(num < 4) return true; // 1, 2, 3 are prime numbers
const div = Math.floor(num / 2); // the max number to use as divider
for(let i = 2; i <= div; i++) {
if(Number.isInteger(num / i)) return false; // if the result is an integer, it's not a prime number
}
return true; // it's a prime number
};
const result = arr.filter(isPrime);
console.log(result); // should be: [2,3,11]
I'm trying to find the second largest number in an array of numbers, but the greatest number appears twice, so I can't just remove it from the array and select the new highest number.
array = [0, 3, 2, 5, 5] (therefore 3 is the 2nd largest value)
I have this code where I can explicitly return 3, but it wouldn't work on other arrays:
function getSecondLargest(nums) {
var sorted_array = nums.sort(function (a,b) {return a - b;});
var unique_sorted_array = sorted_array.filter(function(elem, index, self) {
return index === self.indexOf(elem);
})
return unique_sorted_array[unique_sorted_array.length - 2];
}
return unique_sorted_array[unique_sorted_array.length - 2];
If I wanted to make it more dynamic, is there a way that I could identify the greatest value of the array, then compare that against each iteration of the array?
I was thinking that something along the lines of:
var greatestNum = sortedArray[-1]
while(greatestNum != i) do {
//check for the first number that doesn't equal greatestNum
}
Any help would be appreciated.
You can simply create a Set first and than sort in descending and take the 1st index element
let array = [0, 3, 2, 5, 5]
let op = [...new Set(array)].sort((a,b) => b-a)[1]
console.log(op)
For those who thinks in terms of efficiency. this is the best way IMO
let array = [0, 3, 2, 5, 5]
let max = -Infinity
let secondMax = -Infinity
for(let i=0; i<array.length; i++){
if(array[i] > max){
secondMax = max
max = array[i]
}
}
console.log(secondMax)
I’d recommend doing something more like
const nums = [0, 3, 2, 5, 5];
nums.sort(function (a,b) {return b - a;})
for (let i = 1; i < nums.length; i++) {
if (nums[0] !== nums[i]) {
return nums[i];
}
}
which should be a lot more efficient (especially in terms of memory) than converting to a set and back...
Try this:
var intArray = stringArray.map(nums); // now let's sort and take the second element :
var second = intArray.sort(function(a,b){return b-a})[1];
};
For those who wants to do this using Math.max(). Here's the simplest way to do this.
const getSecondLargest = function (arr) {
const largest = Math.max.apply(null, arr);
for (let i = 0; i < arr.length; i++) {
if (largest === arr[i]) {
arr[i] = -Infinity;
}
}
return Math.max.apply(null, arr);
};
console.log(getSecondLargest([3, 5, 9, 9, 9])); //5
Side note: Math.max() don't take an array, so we have to use Math.max.apply() to pass the array in the function. -Infinity is smaller than any negative finite number.
I have a number array [2, 1, 3, 4, 5, 1] and want to remove the smallest number in the list. But somehow my IF statement gets skipped.
I checked and by itself "numbers[i + 1]" and "numbers[i]" do work, but "numbers[i + 1] < numbers[i]" doesn't...
function removeSmallest(numbers) {
var smallestNumberKEY = 0;
for (i = 0; i <= numbers.lenths; i++) {
if (numbers[i + 1] < numbers[i]) {
smallestNumberKEY = i + 1;
}
}
numbers.splice(smallestNumberKEY, 1);
return numbers;
}
document.write(removeSmallest([2, 1, 3, 4, 5, 1]));
You have a typo in your code, array doesn't have lenths property
function removeSmallest(numbers) {
var smallestNumberKEY = 0;
for (var i = 0; i < numbers.length - 1; i++) {
if (numbers[i + 1] < numbers[i]) {
smallestNumberKEY = i + 1;
numbers.splice(smallestNumberKEY, 1);
}
}
return numbers;
}
document.write(removeSmallest([2, 1, 3, 4, 5, 1]));
But your algorithm wont work for another array, e.g [5, 3, 1, 4, 1], it will remove a value 3 too.
You can find the min value with Math.min function and then filter an array
function removeSmallest(arr) {
var min = Math.min(...arr);
return arr.filter(e => e != min);
}
You can use Array#filter instead
function removeSmallest(arr) {
var min = Math.min.apply(null, arr);
return arr.filter((e) => {return e != min});
}
console.log(removeSmallest([2, 1, 3, 4, 5, 1]))
Short one liner. If the smallest value exist multiple times it will only remove ONE. This may or may not be what you want.
const result = [6,1,3,1].sort().filter((_,i) => i) // result = [1,3,6]
It works by sorting and then creating a new array from the items where indeces are truthy(anything but 0)
another solution with splice and indexOf:
array = [2, 1, 3, 4, 5, 1];
function replace(arr){
arr = arr.slice(); //copy the array
arr.splice( arr.indexOf(Math.min.apply(null, arr)),1)
return arr;
}
document.write( replace(array) ,'<br> original array : ', array)
edit : making a copy of the array will avoid the original array from being modified
"Short" solution using Array.forEach and Array.splice methods:
function removeSmallest(numbers) {
var min = Math.min.apply(null, numbers);
numbers.forEach((v, k, arr) => v !== min || arr.splice(k,1));
return numbers;
}
console.log(removeSmallest([2, 1, 3, 4, 5, 1])); // [2, 3, 4, 5]
This is a proposal with a single loop of Array#reduce and without Math.min.
The algorithm sets in the first loop min with the value of the element and returns an empty array, because the actual element is the smallest value and the result set should not contain the smallest value.
The next loop can have
a value smaller than min, then assign a to min and return a copy of the original array until the previous element, because a new minimum is found and all other previous elements are greater than the actual value and belongs to the result array.
a value greater then min, then the actual value is pushed to the result set.
a value equal to min, then the vaue is skipped.
'use strict';
var removeSmallest = function () {
var min;
return function (r, a, i, aa) {
if (!i || a < min) {
min = a;
return aa.slice(0, i);
}
if (a > min) {
r.push(a);
}
return r;
}
}();
document.write('<pre>' + JSON.stringify([2, 1, 3, 2, 4, 5, 1].reduce(removeSmallest, []), 0, 4) + '</pre>');
I like this oneliner: list.filter(function(n) { return n != Math.min.apply( Math, list ) })
check it out here: https://jsfiddle.net/rz2n4rsd/1/
function remove_smallest(list) {
return list.filter(function(n) { return n != Math.min.apply( Math, list ) })
}
var list = [2, 1, 0, 4, 5, 1]
console.log(list) // [2, 1, 0, 4, 5, 1]
list = remove_smallest(list)
console.log(list) // [2, 1, 4, 5, 1]
list = remove_smallest(list)
console.log(list) // [2, 4, 5]
I had to do this but I needed a solution that did not mutate the input array numbers and ran in O(n) time. If that's what you're looking for, try this one:
const removeSmallest = (numbers) => {
const minValIndex = numbers.reduce((finalIndex, currentVal, currentIndex, array) => {
return array[currentIndex] <= array[finalIndex] ? currentIndex : finalIndex
}, 0)
return numbers.slice(0, minValIndex).concat(numbers.slice(minValIndex + 1))
}
function sumOfPaiars(ints){
var array = [];
var min = Math.min(...ints)
console.log(min)
for(var i=0;i<ints.length;i++){
if(ints[i]>min){
array.push(ints[i])
}
}
return array
}
If you only wish to remove a single instance of the smallest value (which was my use-case, not clear from the op).
arr.sort().shift()
Here is a piece of code that is work properly but is not accepted from codewars:
let numbers = [5, 3, 2, 1, 4];
numbers.sort(function numbers(a, b) {
return a - b;
});
const firstElement = numbers.shift();