JavaScript codewars task - javascript

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 ]

Related

Can someone explain me how does this javascript code works please?

Given a JavaScript function that takes in an array of numbers as the first and the only argument.
The function then removes one element from the array, upon removal, the sum of elements at odd indices is equal to the sum of elements at even indices. The function should count all the possible unique ways in which we can remove one element at a time to achieve balance between odd sum and even sum.
Example var arr = [2, 6, 4, 2];
Then the output should be 2 because, there are two elements 6 and 2 at indices 1 and 3 respectively that makes the combinations table.
When we remove 6 from the array
[2, 4, 2] the sum at odd indexes = sum at even indexes = 4
if we remove 2
[2, 6, 4] the sum at odd indices = sum at even indices = 6
The code below works perfectly. There might be other solutions but I want to understand this one, because I feel there is a concept I have to learn here. Can someone explain the logic of this algorithm please?
const arr = [2, 6, 4, 2];
const check = (arr = []) => {
var oddTotal = 0;
var evenTotal = 0;
var result = 0;
const arraySum = []
for (var i = 0; i < arr.length; ++i) {
if (i % 2 === 0) {
evenTotal += arr[i];
arraySum[i] = evenTotal
}
else {
oddTotal += arr[i];
arraySum[i] = oddTotal
}
}
for (var i = 0; i < arr.length; ++i) {
if (i % 2 === 0) {
if (arraySum[i]*2 - arr[i] + oddTotal === (arraySum[i - 1] || 0)*2 + evenTotal) {
result = result +1
};
} else if (arraySum[i]*2 - arr[i] + evenTotal === (arraySum[i - 1] || 0)*2 + oddTotal) {
result = result +1
}
}
return result;
};

How to merge an array with another one

I have a challenge to complete where I'm given an array [-1,4,-3,5,6,9,-2] and I need to get a new array that sorts the numbers in this order: [firstGreatest, firstLowest, secondGreatest, secondLowest ...and so on]. The negative and positive numbers may be different amount, as in 4 positive, 2 negative.
This is what I tried so far, but cannot think of a better solution.
let arr = [-1, 2, -5, 3, 4, -2, 6];
function someArray(ary) {
const sorted = ary.sort((a, b) => a - b)
const highest = sorted.filter(num => num > 0).sort((a, b) => b - a)
const lowest = sorted.filter(num => num < 0).sort((a, b) => b - a)
let copy = highest
for (let i = 0; i < highest.length; i++) {
for (let j = i; j < lowest.length; j++) {
if ([i] % 2 !== 0) {
copy.splice(1, 0, lowest[j])
}
}
}
}
console.log(arr)
someArray(arr)
console.log(arr)
You can easily solve this problem with two pointers algorithm.
O(n log n) for sorting
O(n) for add the value in result.
Take two-variable i and j,
i points to the beginning of the sorted array
j points to the end of the sorted array
Now just add the value of the sorted array alternatively in final result
let arr = [-1, 2, -5, 3, 4, -2, 6];
function someArray(ary) {
const sorted = arr.sort((a, b) => b - a);
// declaration
const result = [];
let i = 0,
j = sorted.length - 1,
temp = true;
// Algorithm
while (i <= j) {
if (temp) {
result.push(sorted[i]);
i++;
} else {
result.push(sorted[j]);
j--;
}
temp = !temp;
}
return result;
}
console.log(someArray(arr));
.as-console-wrapper { max-height: 100% !important; top: 0; }
You could sort the array and pop or shift until you have no more items.
function greatestLowest(array) {
let temp = [...array].sort((a, b) => a - b),
m = 'shift',
result = [];
while (temp.length) result.push(temp[m = { pop: 'shift', shift: 'pop' }[m]]());
return result;
}
console.log(...greatestLowest([-1, 2, -5, 3, 4, -2, 6]));
The general idea is to sort the array (highest to lowest) then pick the first and the last element until the array is empty. One way of doing it could be:
const input = [-1, 2, -5, 3, 4, -2, 6];
function someArray(arr) {
// sort the original array from highest to lowest
const sorted = arr.sort((a, b) => b - a);
const output = []
while (sorted.length > 0) {
// remove the first element of the sorted array and push it into the output
output.push(...sorted.splice(0, 1));
// [check to handle arrays with an odd number of items]
// if the sorted array still contains items
// remove also the last element of the sorted array and push it into the output
if (sorted.length > 0) output.push(...sorted.splice(sorted.length - 1, 1))
}
return output;
}
// test
console.log(`input: [${input.join(',')}]`);
console.log(`input (sorted desc): [${input.sort((a, b) => b - a).join(',')}]`)
console.log(`output: [${someArray(input).join(',')}]`);
This is a simple and a shorter method:
function makearray(ar) {
ar = points.sort(function(a, b) {
return b - a
})
let newarray = []
let length = ar.length
for (let i = 0; i < length; i++) {
if (i % 2 == 0) {
newarray.push(ar[0])
ar.splice(0, 1)
} else {
newarray.push(ar[ar.length - 1])
ar.splice(ar.length - 1, 1)
}
}
return newarray
}
const points = [-1, 2, -5, 3, 4, -2, 6]
console.log(makearray(points))

JS: restart loop with a updated index number

Is there a possibility to restart this loop with a new index number:
let ar = [1, 1, 2, 1, 2, 1, 3, 2, 3, 1];
let sortedArray = ar.sort();
let sameNumbersArray = [];
let numberOfSameNumbers = 0;
let lastIndexNumber = 0;
for (i = lastIndexNumber; i < sortedArray.length; i++) {
if (sortedArray[i] == sortedArray[i + 1]) {
const sameNumber = sortedArray[i];
sameNumbersArray.push(sameNumber);
} else {
break;
}
let lastIndexFromNumberArray = [];
lastIndexFromNumberArray.push(sameNumbersArray.length);
lastIndexFromNumberArray.push(3);
lastIndexFromNumberArray.push(2);
lastIndexNumber = lastIndexFromNumberArray.reduce(function (a, b) {
return a + b;
}, 0);
So basically that the loop (lastIndexNumber) starts with index[0], but then restarts with index[5] and index[7].
How would one add this extra loop?
I'm not 100% clear on the aim here. Are you able to elaborate on the desired result of the above?
It looks like you want to get an array of the unique numbers and perhaps the number of unique numbers from the source array?
If so, here's another way which might be cleaner:
let ar = [1, 1, 2, 1, 2, 1, 3, 2, 3, 1];
let sortedArray = ar.sort();
let newSameNumbersArray = unique(sortedArray);
//array of unique numbers:
console.log(newSameNumbersArray);
//count of unique numbers:
console.log(newSameNumbersArray.length);
function unique(array) {
return Array.from(new Set(array));
}
This is based on this answer: https://stackoverflow.com/a/44405494/4801692
That said, you can directly set the value of i and use continue to move to the 'next' iteration.
i = 5;
continue;
This is bad though as you are in danger of feeding i a lower number and getting stuck in an infinite loop. If you can explain the requirement a little more I might be able to suggest something better.
you can do such thing to find the pairs
let ar = [10, 10, 10, 20, 20, 10 ,30, 20 ,30]
function findPair(ar) {
let counts = {};
let count = [];
let sum = 0;
for(let i = 0; i < ar.length; i++){
let item = ar[i]
counts[item] = counts[item] >= 1 ? counts[item] + 1 : 1;
}
count = Object.values(counts);
for(let i = 0; i < count.length; i++){
if(count[i] >= 2){
sum += Math.floor(count[i]/2)
}
}
console.log(sum)
}
findPair(ar)

Algorithm to return all combinations of 3 combinations from a array of length 6 without the number appearing with the same set of numbers

I was trying to write a algorithm in javascript that returns all the possible 3 digit numbers numbers from a given array of length 6
For Example
var arr = [1, 2, 3, 4, 5, 6];
I have already got the combinations with the same sets of numbers in different positions in the 2D array.
(The code which I took the help of)
If I have the same numbers in different combinations then I would like to remove them form the array. like I have [1, 2, 3] at index i in the array comtaining all the possible combinations then I would like to remove other combination with the same numbers like [2, 1, 3], [1, 3, 2] and so on..
Note the array also contains numbers repeated like [3, 3, 3], [2, 2, 2], [3, 2, 3] and so on
I expect an 2d array which has the values : [[1,2,3],[1,2,4],[1,2,5],[1,2,6],[1,3,4]] and so on (24 possibilities)
Is there any way to do this?
Extending the answer you linked, just filter out the results with the help of a Set.
Sort an individual result, convert them into a String using join(), check if it's present in set or not, and if not, then store them in the final result.
function cartesian_product(xs, ys) {
var result = [];
for (var i = 0; i < xs.length; i++) {
for (var j = 0; j < ys.length; j++) {
// transform [ [1, 2], 3 ] => [ 1, 2, 3 ] and append it to result []
result.push([].concat.apply([], [xs[i], ys[j]]));
}
}
return result;
}
function cartesian_power(xs, n) {
var result = xs;
for (var i = 1; i < n; i++) {
result = cartesian_product(result, xs)
}
return result;
}
function unique_cartesian_power(xs, n) {
var result = cartesian_power(xs, n);
var unique_result = [];
const set = new Set();
result.forEach(function(value) {
var representation = value.sort().join(' ');
if (!set.has(representation)) {
set.add(representation);
unique_result.push(value);
}
});
return unique_result;
}
console.log(unique_cartesian_power([1, 2, 3, 4, 5, 6], 3));
const arr = [1, 2, 3, 4, 5, 6];
const result = arr.reduce((a, v) => arr.reduce((a, v2) => {
arr.reduce((a, v3) => {
const current = [v, v2, v3].sort().join(",");
!a.find(_ => _.sort().join() === current) && a.push([v, v2, v3]);
return a;
}, a);
return a;
}, a), []);
console.log(result.length);
console.log(...result.map(JSON.stringify));
You could take an iterative and recursive approach by sorting the index and a temporary array for the collected values.
Because of the nature of going upwards with the index, no duplicate set is created.
function getCombination(array, length) {
function iter(index, right) {
if (right.length === length) return result.push(right);
if (index === array.length) return;
for (let i = index, l = array.length - length + right.length + 1; i < l; i++) {
iter(i + 1, [...right, array[i]]);
}
}
var result = [];
iter(0, []);
return result;
}
var array = [1, 2, 3, 4, 5, 6],
result = getCombination(array, 3);
console.log(result.length);
result.forEach(a => console.log(...a));
.as-console-wrapper { max-height: 100% !important; top: 0; }
This is a good example, that it is usually worthwhile not asking for a specific answer for a generic problem shown with a specific question; however as you've requested - if you really have the above constraints which kind of don't make much sense to me, you could do it like that:
function combine(firstDigits, secondDigits, thirdDigits) {
let result = [];
firstDigits.forEach(firstDigit => {
// combine with all secondDigitPermutations
secondDigits.forEach(secondDigit => {
// combine with all thirdDigitPermutations
thirdDigits.forEach(thirdDigit => {
result.push([firstDigit, secondDigit, thirdDigit])
})
})
});
// now we have all permutations and simply need to filter them
// [1,2,3] is the same as [2,3,1]; so we need to sort them
// and check them for equality (by using a hash) and memoize them
// [1,2,3] => '123'
function hashCombination(combination) {
return combination.join('ಠ_ಠ');
}
return result
// sort individual combinations to make them equal
.map(combination => combination.sort())
.reduce((acc, currentCombination) => {
// transform the currentCombination into a "hash"
let hash = hashCombination(currentCombination);
// and look it up; if it is not there, add it to cache and result
if (!(hash in acc.cache)) {
acc.cache[hash] = true;
acc.result.push(currentCombination);
}
return acc;
}, {result: [], cache: {}})
.result;
}
console.log(combine([1,2,3,4,5,6],[1,2,3,4,5,6],[1,2,3,4,5,6]).length);
console.log(...combine([1,2,3,4,5,6],[1,2,3,4,5,6],[1,2,3,4,5,6]).map(JSON.stringify));
This does not include some super-clever assumptions about some index, but it does abuse the fact, that it's all about numbers. It is deliberately using no recursion, because this would easily explode, if the amount of combinations is going to be bigger and because recursion in itself is not very readable.
For a real world problem™ - you'd employ a somewhat similar strategy though; generating all combinations and then filter them. Doing both at the same time, is an exercise left for the astute reader. For finding combinations, that look different, but are considered to be the same you'd also use some kind of hashing and memoizing.
let arr1 = [1,2,3,4,5,6];
function getCombination(arr){
let arr2 = [];
for(let i=0; i<arr.length; i++){
for(let j=i; j<arr.length; j++){
for(let k=j; k<arr.length; k++){
arr2.push([arr[i],arr[j],arr[k]]);
}
}
}
return arr2;
}
console.log(getCombination(arr1));

Bonfire Algorithm Challenge: Where Do I Belong on 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;
}

Categories