Related
I am solving a problem which asks me to return the number with the highest frequency(mode). For example, if arr contains [3, 9, 3, 1, 6] the output should be 3. If there is more than one mode, I want to return the one that appeared first. [6, 6, 3, 3, 5, 5] should return 6 because it appeared first. If there is no mode, I want to return 0. The array will not be empty. I am new to algorithms, please suggest a simpler solution for me.
function Mode(arr) {
const arrayObject = {};
arr.forEach(arr => {
if(!arrayObject[arr]) {
arrayObject[arr] = 1
// console.log(arrayObject)
} else if(arrayObject[arr]){
arrayObject[arr] += 1
// console.log(arrayObject)
}
})
console.log(arrayObject) // { '3': 2, '5': 2, '6': 2 } array keys are automatically sorted in ascending other.This could be the problem but I don't know how to unsort the arrays//
let highestValueKey = 0;
let highestValue = 0
for(let key in arrayObject) {
const value = arrayObject[key]
if(value > highestValue) {
highestValue = value
highestValueKey = key
}
}
return Number(highestValueKey)
}
console.log(Mode([6, 6, 3, 3, 5, 5])) // 3 instead of 6
Just keep track of both count AND when it was first seen.
function mode (arr) {
const countSeen = {};
const firstSeen = {};
for (let i = 0; i < arr.length; i++) {
let elem = arr[i];
if (! countSeen[elem]) {
countSeen[elem] = 1;
firstSeen[elem] = i;
}
else {
countSeen[elem]++;
}
}
let mostSeenCount = 0;
let mostSeenValue = null;
for (let elem of Object.keys(countSeen)) {
if (mostSeenCount < countSeen[elem] ||
(mostSeenCount == countSeen[elem] && firstSeen[elem] < firstSeen[mostSeenValue])
) {
mostSeenCount = countSeen[elem];
mostSeenValue = elem;
}
}
return mostSeenValue;
}
console.log(mode([5, 6, 6, 6, 3, 3, 5, 5]))
You could use a Map whose keys are the array values, and the corresponding Map value is the frequency count:
Create the map and initialise the counts with 0
Increment the count as each input value is visited.
Use Math.max to get the greatest count from that map
Iterate the map to find the first count that matches that maximum
As Map entries are iterated in insertion order, the correct key will be identified in the last step.
function mode(arr) {
const counts = new Map(arr.map(i => [i, 0]));
for (const i of arr) counts.set(i, counts.get(i) + 1);
const maxCount = Math.max(...counts.values());
for (const [i, count] of counts) {
if (count == maxCount) return i;
}
}
console.log(mode([3, 9, 3, 1, 6])); // 3
console.log(mode([6, 6, 3, 3, 5, 5])); // 6
console.log(mode([3, 9, 3, 6, 1, 9, 9])); // 9
console.log(mode([5, 6, 6, 6, 3, 3, 5, 5])); // 5
You could use reduce to count the number of occurrences, then choose the max from there.
function mode(arr) {
const counts = arr.reduce((result, value, index) => {
// result is the object we're building up.
// value is the current item from the array.
// index is value's position within the array
// if result[value] doesn't already exist, create it
result[value] = (result[value] || { index, value, count: 0 });
// increment the 'count' for this value
result[value].count++;
// return the updated result
return result;
}, {});
// sort the entries by count in descending order, then by index
// ascending such that sorted[0] will be the entry with the highest
// count, and lowest index if more that one element has the same count
const sorted = Object.values(counts)
.sort((
{count: ca, index: ia},
{count: cz, index: iz}
) => (cz - ca) || (ia - iz));
// then return that entry's value
return sorted[0].value;
}
console.log(mode([6, 6, 3, 3, 5, 5])) // 6
console.log(mode([3, 9, 3, 1, 6])) // 3
console.log(mode([3, 9, 3, 6, 1, 9, 9])) // 9
I'm solving the following kata:
Given an input of an array of digits, return the array with each digit incremented by its position in the array: the first digit will be incremented by 1, the second digit by 2, etc. Make sure to start counting your positions from 1 (and not 0).
Your result can only contain single digit numbers, so if adding a digit with it's position gives you a multiple-digit number, only the last digit of the number should be returned.
Notes:
return an empty array if your array is empty
arrays will only contain numbers so don't worry about checking that
Examples
[1, 2, 3] --> [2, 4, 6] # [1+1, 2+2, 3+3]
[4, 6, 9, 1, 3] --> [5, 8, 2, 5, 8] # [4+1, 6+2, 9+3, 1+4, 3+5]
# 9+3 = 12 --> 2
My code:
const incrementer = (arr) => {
if (arr === []) {
return []
}
let newArr = []
for (let i = 0; i <= arr.length; i++) {
let result = arr[i] + (i + 1)
newArr.push(result)
if (newArr[i] > 9 ) {
let singleDigit = Number(newArr[i].toString().split('')[1])
newArr.push(singleDigit)
}
}
const filteredArr = newArr.filter(el => el >= 0 && el <= 9)
return filteredArr
}
I can't seem to pass the latest test case, which is the following:
[1, 2, 3, 4, 5, 6, 7, 8, 9, 9, 9, 9, 9, 8]), [2, 4, 6, 8, 0, 2, 4, 6, 8, 9, 0, 1, 2, 2]
I keep getting back the whole correct array up until the second 0, after which the other numbers, 1,2,2 are missing from the solution. What am I doing wrong?
The problem in your code is that the filter only runs at the end, and so when you have done a double push in one iteration (once with the value that has more than one digit, and once with just the last digit), the next iteration will no longer have a correct index for the next value that is being pushed: newArr[i] will not be that value.
It is better to correct the value to one digit before pushing it to your new array.
Moreover, you can make better use of the power of JavaScript:
It has a nice map method for arrays, which is ideal for this purpose
Use modulo arithmetic to get the last digit without having to create a string first
Here is the proposed function:
const incrementer = (arr) => arr.map((val, i) => (val + i + 1) % 10);
console.log(incrementer([1, 2, 3, 4, 5, 6, 7, 8, 9, 9, 9, 9, 9, 8]));
... so if adding a digit with it's position gives you a multiple-digit number, only the last digit of the number should be returned.
So if the number is 12, it expects only 2 to be added to the array.
So your code should be:
if (newArr[i] > 9)
{
newArr[i] = newArr[i] % 10; // remainder of newArr[i] / 10
}
const incrementer = (arr) => {
if (arr.length === 0) { // CHANGE HERE
return [];
}
let newArr = []
for (let i = 0; i <= arr.length; i++) {
let result = arr[i] + (i + 1)
newArr.push(result)
if (newArr[i] > 9 ) {
newArr[i] = newArr[i] % 10; // CHANGE HERE
}
}
const filteredArr = newArr.filter(el => el >= 0 && el <= 9)
return filteredArr
}
console.log(incrementer([2, 4, 6, 8, 0, 2, 4, 6, 8, 9, 0, 1, 2, 2]));
console.log(incrementer([1, 2, 3, 4, 5, 6, 7, 8, 9, 9, 9, 9, 9, 8]));
Please see below code.
const incrementer = arr => {
if (arr === []) {
return [];
}
let newArr = [];
for (let i = 0; i < arr.length; i++) {
let result = arr[i] + (i + 1);
// newArr.push(result);
if (result > 9) {
let singleDigit = Number(result.toString().split("")[1]);
newArr.push(singleDigit);
} else {
newArr.push(result);
}
}
// const filteredArr = newArr.filter(el => el >= 0 && el <= 9);
return newArr;
};
console.log(incrementer([1, 2, 3, 4, 5, 6, 7, 8, 9, 9, 9, 9, 9, 8]))
const incrementer = (arr) => {
if (arr === []) {
return []
}
return arr.map((number, index) => (number + index + 1) % 10);
}
Doing the needed additions in (number + index + 1) and % 10 operation will get the last digit.
I did this module on functions and execution context - all questions have gone well but there is one challenge I have spent a lot of time on and still can't figure it out. Any help will be greatly appreciated. Thank you
Challenge question says:
Write a function addingAllTheWeirdStuff which adds the sum of all the odd numbers in array2 to each element under 10 in array1.
Similarly, addingAllTheWeirdStuff should also add the sum of all the even numbers in array2 to those elements over 10 in array1.
BONUS: If any element in array2 is greater than 20, add 1 to every element in array1.
// Uncomment these to check your work!
// console.log(addingAllTheWeirdStuff([1, 3, 5, 17, 15], [1, 2, 3, 4, 5])); // expected log [10, 12, 14, 23, 21]
// console.log(addingAllTheWeirdStuff([1, 3, 5, 17, 15, 1], [1, 2, 3, 4, 5, 22])); // expected log [11, 13, 15, 46, 44, 11]
// my attempt so far:
function addingAllTheWeirdStuff(array1, array2) {
// ADD CODE HERE
let result = []
for (let i = 0; i < array2.length; i++) {
if (array2[i] > 20) {
result = array1[i] += 1
}
}
for (let i = 0; i < array2.length; i++) {
if (array2[i] % 2 === 0 && array1[i] > 10) {
result = array1[i] + array2[i]
}
}
for (let i = 0; i < array2.length; i++) {
if (array2[i] % 2 !== 0 && array1[i] < 10) {
result = array1[i] + array2[i]
}
}
return result
}
You can easily achieve this using reduce and map array method, with the ternary operator:
const array1 = [1, 3, 5, 17, 15];
const array2 = [1, 2, 3, 4, 5];
function addingAllTheWeirdStuff(array1, array2) {
const oddSum = array2.reduce((sum, current) => current % 2 ? current + sum : 0 + sum, 0)
const oddEven = array2.reduce((sum, current) => current % 2 == 0 ? current + sum : 0 + sum, 0)
return array1.map(num => num < 10 ? num + oddSum : num + oddEven)
}
console.log(addingAllTheWeirdStuff(array1, array2))
If you break the challenge into smaller pieces, you can deconstruct it better and come up with your solutions.
This is what I did... I will be adding more comments shortly with more explanations
I chose to keep using loops as I assumed this was the point of the challenges (to practice for loops, multiple conditions, etc) - In other words, I chose to not use map / reduce on purpose but if that's allowed, use the answer by #charmful0x as it results in less code :)
// function to get sum of all odd numbers in array
function getSumOfAllOddNumbersInArray( elementArray ){
var sumOfOddNumbers = 0;
for (let i = 0; i < elementArray.length; i++) {
// use remainder operator to find out if element is odd or not
if (elementArray[i] % 2 !== 0 ) {
sumOfOddNumbers += elementArray[i];
}
}
return sumOfOddNumbers;
}
// function to get sum of all EVEN numbers in array
function getSumOfAllEvenNumbersInArray( elementArray ){
var sumOfEvenNumbers = 0;
for (let i = 0; i < elementArray.length; i++) {
// use remainder operator to find out if element is odd or not
if (elementArray[i] % 2 === 0 ) {
sumOfEvenNumbers += elementArray[i];
}
}
return sumOfEvenNumbers;
}
// Return true if there is at least one element in array that is greater than 20
function hasElementOverTwenty( elementArray ){
for (let i = 0; i < elementArray.length; i++) {
if (elementArray[i] > 20 ) {
// no need to keep looping, we found one - exit function
return true;
}
}
return false;
}
function addingAllTheWeirdStuff( firstArray, secondArray ){
var sumOfOddNumbersInArray = getSumOfAllOddNumbersInArray( secondArray );
var sumOfEvenNumbersInArray = getSumOfAllEvenNumbersInArray( secondArray );
var needToAddOne = hasElementOverTwenty( secondArray );
for (let i = 0; i < firstArray.length; i++) {
// Challenge One
if (firstArray[i] < 10) {
firstArray[i] = firstArray[i] + sumOfOddNumbersInArray;
} else if (firstArray[i] > 10) {
// Challenge Two
firstArray[i] = firstArray[i] + sumOfEvenNumbersInArray;
}
// bonus
if( needToAddOne ){
firstArray[i]++;
}
}
return firstArray;
}
// Uncomment these to check your work!
console.log(addingAllTheWeirdStuff([1, 3, 5, 17, 15], [1, 2, 3, 4, 5]));
console.log('expected:' + [10, 12, 14, 23, 21] );
console.log(addingAllTheWeirdStuff([1, 3, 5, 17, 15, 1], [1, 2, 3, 4, 5, 22]));
console.log('expected:' + [11, 13, 15, 46, 44, 11] );
Challenge question says: Write a function addingAllTheWeirdStuff which adds the sum of all the odd numbers in array2 to each element under 10 in array1.
Similarly, addingAllTheWeirdStuff should also add the sum of all the even numbers in array2 to those elements over 10 in array1.
BONUS: If any element in array2 is greater than 20, add 1 to every element in array1.
I have an array with numbers in the range of 0 - 100. I need to find all the same numbers and add 1 to them.
my code worked well with arrays like [100, 2, 1, 1, 0]
const findAndChangeDuplicates = (arr: any) => {
for (let i = arr.length - 1; i >= 0; i--) {
if (arr[i + 1] === arr[i] && arr[i] <= 5) {
arr[i] += 1;
} else if (arr[i - 1] === arr[i] && arr[i] >= 5) {
arr[i] -= 1;
findAndChangeDuplicates(arr);
}
}
return arr;
};
but when I came across this
[100, 6, 6, 6, 5, 5, 5, 5, 5, 4, 4, 4, 3, 3, 2, 2, 2, 2, 1, 1, 0, 0]
my code let me down.
Expected Result:
[100, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0]
Have any ideas?
An approach by using at least one loop from the end to adjust the values and if necessary another loop from the beginning to set the largest value to 100.
Both loops feature a value variable v. In the first loop, it starts with the last value of the array and increments its value and check is the item is smaller than this value.
If smaller, then the value is assigned, otherwise the actual value is taken for the next item.
if necessary, the other loop works in opposite direction and with a start value of 100 and checks if the item is greater than wanted and takes the smaller value, or the value is taken from the item.
The result is an array which has a gereatest value of 100 at start and goes until zero or greater to the end of the array.
function update(array) {
var i = array.length,
v = array[--i];
while (i--) if (array[i] < ++v) array[i] = v; else v = array[i];
if (array[0] > 100) {
v = 100;
for (i = 0; i < array.length; i++) {
if (array[i] > v) array[i] = v; else v = array[i];
v--;
}
}
return array;
}
console.log(update([100, 2, 1, 1, 0]));
console.log(update( [100, 100, 99, 86, 6, 5, 5, 5, 5, 5, 4, 4, 4, 3, 3, 2, 2, 2, 2, 1, 1, 0, 0]))
.as-console-wrapper { max-height: 100% !important; top: 0; }
The following assumes you want them ordered from highest to lowest, if not this might ba as well as useless to you.
The idea is to first create an Object to keep track of how many of each number exist. We then map each value by first checking whether it's unique and if not increasing it until we can't find any value inside the Object anymore. This will not neatly order the numbers by itself so we will have to sort afterwards.
let arr1 = [100, 6, 6, 6, 5, 5, 5, 5, 5, 4, 4, 4, 3, 3, 2, 2, 2, 2, 1, 1, 0, 0],
arr2 = [100, 2, 1, 1, 0];
const f = (arr) => arr.reduce((a,c) => (a[c] = (a[c] || 0) + 1, a),{}),
g = (arr, obj) => arr.map(v => {
if (obj[v] > 1) {
let i = 1;
obj[v] = obj[v] - 1;
while (obj[v + i]) {
i++;
}
obj[v + i] = (obj[v + i] || 0) + 1;
return v + i;
} else {
return v;
}
}).sort((a,b) => +b - +a);
console.log(g(arr1, f(arr1)))
console.log(g(arr2, f(arr2)))
Here is a verbose solution that will work with unordered arrays as well.
It's not efficient, neither brilliant, but it takes care of unordered arrays as well.
Basically, it takes advantage of reduce to collect all the occurrences of each element. Each time it finds more than one, it increases all the occurrences by 1 except the last one.
Next, it checks whether there still are duplicates. If there are, it repeats the process until none is found. Of course, it's not the cleverest approach, but it works.
// Increases all duplicates until there are no more duplicates.
const increaseDuplicates = (arr, index) => {
// Repeat the code until no duplicate is found
while (!noDuplicates(arr)) {
// Acquire all the occurrences of each item, keeping track of the index.
Object.entries(arr.reduce((acc, next, i) => {
acc[next] = acc[next] || [];
return acc[next].push(i), acc;
}, {})).forEach(([n, indexes]) => {
// for each value found, check whether it appears at least twice.
if (indexes.length > 1) {
// if it does, increase the value of every item but the last one.
for (var i = 0; i < indexes.length - 1; i++) {
arr[indexes[i]]++;
}
}
});
}
return arr;
};
// Asserts an array has no duplicates.
const noDuplicates = (arr) => [...new Set(arr)].length === arr.length;
const input = [100, 6, 6, 6, 5, 5, 5, 5, 5, 4, 4, 4, 3, 3, 2, 2, 2, 2, 1, 1, 0, 0];
console.log(increaseDuplicates(input));
const unorderedInput = [6,4,5,6,6,6,6,5,6,3,1,2,3,99,403,100, 6, 6, 6, 5, 5, 5, 5, 5, 4, 4, 4, 3, 3, 2, 2, 2, 2, 1, 1, 0, 0];
console.log(increaseDuplicates(unorderedInput));
You can use a forEach on your array to do this, using the 3rd parameter of the callback, the array itself, and a bit of recursivity
const increment_to_unicity = (value, index, self) => {
if (self.indexOf(value) !== index) {
self[index]++
increment_to_unicity(self[index], index, self)
}
return self[index];
}
arr = arr.map(increment_to_unicity).sort((a, b) => b - a);
I have array:
arr = [1,2,3,4,5,6,7,8,9,10,11,12,13,14];
Then I want to make group of 4 elements.
Every iteration, this array must be modified until it get's final face.
Step 1:
arr = [[1,2,3,4],5,6,7,8,9,10,11,12,13,14];
Step 2:
arr = [[1,2,3,4],[5,6,7,8],9,10,11,12,13,14];
Step 3:
arr = [[1,2,3,4],[5,6,7,8],[9,10,11,12],13,14];
Step 3:
arr = [[1,2,3,4],[5,6,7,8],[9,10,11,12],[13,14]];
How is this possible?
I tried this:
var array = [1,2,3,4,5,6,7,8,9,10,11,12,13,14]
var i,j,temparray,chunk = 4;
for (i=0,j=array.length; i<j; i+=chunk) {
temparray = array.slice(i,i+chunk);
console.log(temparray);
}
But I don't know then how to save this chunk into own array and not in the new array.
Using Array#reduce method.
const arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14],
newArr = arr.reduce((acc, item, index) => {
if ((index) % 4 === 0) {
acc.push([item]);
} else {
acc[acc.length - 1].push(item);
}
return acc;
}, []);
console.log(newArr); // [ [ 1, 2, 3, 4 ], [ 5, 6, 7, 8 ], [ 9, 10, 11, 12 ], [ 13, 14 ] ]
You could splice the array until the length is smaller than the index of the last insertation.
var array = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14],
i = 0;
while (i < array.length) {
array.splice(i, 0, array.splice(i, 4));
console.log(JSON.stringify(array));
i++;
}
lodash probably has better performances than my implementation, but if you are looking to do so with vanilla javascript then you can like this (though many other ways are possible):
var arr = [1,2,3,4,5,6,7,8,9,10,11,12,13,14];
var newArr = arr.reduce((acc, val, idx)=>{
if(idx % 4 === 0){
acc.push([]);
}
acc[acc.length-1].push(val)
return acc
}, [])
console.log(newArr);
The lodash method chunk will do this for you.
result = _.chunk(arr, 4);
function chunkArray(myArray, chunk_size){
var index = 0;
var arrayLength = myArray.length;
var tempArray = [];
for (index = 0; index < arrayLength; index += chunk_size) {
myChunk = myArray.slice(index, index+chunk_size);
// Do something if you want with the group
tempArray.push(myChunk);
}
return tempArray;
}
// Split in group of 3 items
var result = chunkArray([1,2,3,4,5,6,7,8], 3);
// Outputs : [ [1,2,3] , [4,5,6] ,[7,8] ]
console.log(result);
Just push it to the resulting array:
const chunk = 4, result = []
for (var i = 0, j = array.length; i < j; i += chunk) {
result.push(array.slice(i,i + chunk));
}
I thought it would be fun too if I add one more solution using recursive calls, Happy coding!
Test it here
function split(arr, offset, res){
//stop condition (offset exceeds len of array)
if(offset>arr.length)
return res;
//slice 4 elms
res.push(arr.slice(offset,offset+4));
//recursion
return split(arr, offset+4, res);
}
var res = split([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14], 0, []);
console.log(res);