how to sort array by last digit? - javascript

I am required to write a function that receives an array of numbers and
should return the array sorted using for the comparison of their last digit, if their last digit is the same you should check the second to last and so on.
Example:
Input: [1, 10, 20, 33, 13, 60, 92, 100, 21]
Output: [100, 10, 20, 60, 1, 21, 92, 13, 33]
but I get
Output: [ 10, 20, 60, 100, 1, 21, 92, 33, 13 ]
my code:
/**I guess the input numbers are only integers*/
input = [1, 10, 20, 33, 13, 60, 92, 100, 21];
const reverseString = (string) => {
const stringToArray = string.split("");
const reversedArray = stringToArray.reverse();
const reversedString = reversedArray.join("");
return reversedString;
};
let sortedInput = input.sort((firstNumber, secondNumber) => {
const firstNumberReversed = reverseString(firstNumber.toString());
const secondNumberReversed = reverseString(secondNumber.toString());
const largerOne = Math.max(
firstNumberReversed,
secondNumberReversed
).toString;
for (let i = 0; i < largerOne.length; i++) {
if (firstNumberReversed[i] != secondNumberReversed[i]) {
if(firstNumberReversed[i] > secondNumberReversed[i]){
return 1
}
if(secondNumberReversed[i] > firstNumberReversed[i]){
return -1
}
}
}
});
console.log(sortedInput);

You can achieve this result if you sort it after reversing the number
const arr = [1, 10, 20, 33, 13, 60, 92, 100, 21];
const result = arr
.map((n) => [n, n.toString().split("").reverse().join("")])
.sort((a, b) => a[1].localeCompare(b[1]))
.map((a) => a[0]);
console.log(result);

You can do this using the Remainder Operator:
Demo:
const data = [1, 10, 20, 33, 13, 60, 92, 100, 21];
data.sort((a, b) => {
for (let i = 1, sum = a + b; ; i *= 10) {
const diff = (a % i) - (b % i);
if (diff === 0 && i < sum) continue;
return diff;
}
});
console.log(data);

Related

Find duplicates of an array and replace it with its number

Say I have an array:
arr = [25, 25, 25, 20, 15, 10, 10, 5];
and I want to count up the number of duplicates (ie. three 25s and 2 10s) and make a new array that becomes:
newArr = ['25 * 3', 20, 15, '10 * 2', 5];
How should I go about doing this? Thanks!
It can be solved using Set and filter
let arr = [25, 25, 25, 20, 15, 10, 10, 5];
const newArr = [...new Set(arr)].map((x) => {
const count = arr.filter(y => y == x).length
return count > 1 ? x + " * " + count: x;
})
console.log(newArr) //  ["25 * 3", 20, 15, "10 * 2", 5]
or if you want the numeric value you can do that
let arr = [25, 25, 25, 20, 15, 10, 10, 5];
const newArr = [...new Set(arr)].map((x) => arr.filter(y => y == x).length * x)
console.log(newArr) // [75, 20, 15, 20, 5]
You can use a Array#forEach loop to iterate through each item of the array, keeping track of how many times each item has been seen before.
Demo:
let arr = [25, 25, 25, 20, 15, 10, 10, 5];
let result = [], seenBefore = [];
arr.forEach((item) => {
let seen = seenBefore.indexOf(item);
if (seen !== -1) return result[seen].count++;
result.push({ name: item, count: 1 });
seenBefore.push(item);
});
result = result.map(({ name, count }) =>
count > 1 ? `${name} * ${count}` : name
);
console.log(result);
The same technique but smaller using Array#reduce:
let arr = [25, 25, 25, 20, 15, 10, 10, 5];
let result = arr
.reduce(
(acc, item) => {
acc[1].indexOf(item) !== -1 ? acc[0][acc[1].indexOf(item)].count++ : (acc[0].push({ name: item, count: 1 }), acc[1].push(item));
return acc;
},
[[], []]
)[0]
.map(({ name, count }) => (count > 1 ? `${name} * ${count}` : name));
console.log(result);
You could use reduce and check if the current element in the iteration is equal to the previous element and then also what is the type of last element added to the accumulator.
const arr = [25, 25, 25, 20, 15, 10, 10, 5];
const result = arr.reduce((r, e, i, arr) => {
if (i && e === arr[i - 1]) {
if (typeof r[r.length - 1] === 'number') {
r[r.length - 1] = `${e} * 2`;
} else {
const [key, value] = r[r.length - 1].split(' * ')
r[r.length - 1] = `${key} * ${+value + 1}`
}
} else {
r.push(e)
}
return r;
}, [])
console.log(result)

How do I replace unique values from another array, by replacing the original array

So I have two sets of Array, one of them is an object (arrA). And another one is just a set of primitive values arrB.
let a = "100229265852737908723455202093346882084130103685642861644052656467061936958706";
let arrA = [];
let arrB = [];
for (let i = 1; i <= 28; i++) {
arrA.push({index: i, pos: i, unique: false});
arrB.push(i);
}
let b = a.split(/(?=(?:..)*$)/).slice(0, 28);
b.forEach((val, index) => {
let c = Math.floor((+val / 100) * 28 ) + 1;
if (arrB.indexOf(c) !== -1) {
arrB.splice(arrB.indexOf(c), 1);
arrA[index].unique = true;
}
arrA[index].pos = c;
});
arrB.forEach((val, index) => {
arrA.forEach((valA, indexA) => {
if (!valA.unique) {
if (arrB[index] > valA.pos) {
arrA[indexA].pos = arrB[index];
arrA[indexA].unique = true;
arrB.splice(arrB.indexOf(arrB[index]));
}
}
})
});
My expected result is, arrA.pos is:
3, 1, 9, 8, 17, 15, 21, 4, 22, 10, 16, 6, 7, 27, 13, 20, 25, 5, 12, 14, 19, 11, 24, 18, 26, 28, 2
 
However I got:
3, 1, 9, 8, 17, 15, 21, 4, 21, 10, 16, 6, 6, 27, 10, 20, 23, 3, 12, 9, 3, 11, 24, 18, 8, 18, 18
If your goal is to take the string, split it into an array of elements of an arbitrary length, each being a 2-digit number, then output an Array that contains only the original Array's unique values, then you can do this:
const MAGIC_NUMBER = 28;
const a = "100229265852737908723455202093346882084130103685642861644052656467061936958706";
const b = a.split(/(?=(?:..)*$)/).slice(0, MAGIC_NUMBER );
const unique = Array.from( new Set( b ));
Set at MDN

How to implement insertion sort for two arrays in ES6

Let's say that I have two arrays:
arr1 - [90, 44, 64, 16, 24, 20, 64, 86, 20, 64, 56, 72, 16]
and
arr2 - [21, 13, 9, 13, 15, 7, 17, 15, 9, 19, 7, 15, 9]
I want to implement insertion sort for two arrays and receive the sorted result array:
[
90, 86, 72, 64, 64, 64, 56, 44,
24, 21, 20, 20, 19, 17, 16, 16,
15, 15, 15, 13, 13, 9, 9, 9,
7, 7
]
I know that I can achieve it indirectly with:
resultArray = arr1.concat(arr2).sort(function(a, b) {return b - a});
but it's not the best solution when it comes to performance.
I will be grateful for suggestions on how to achieve the above assumption with ES6 usage.
Use spread operator to concatenate, then arrow function to sort:
let arr1 = [90, 44, 64, 16, 24, 20, 64, 86, 20, 64, 56, 72, 16];
let arr2 = [21, 13, 9, 13, 15, 7, 17, 15, 9, 19, 7, 15, 9];
let resultArray = [...arr1, ...arr2].sort((a, b) => b - a);
console.log("arr1:");
console.log("["+arr1.join(", ")+"]");
console.log("arr2:");
console.log("["+arr2.join(", ")+"]");
console.log("resultArray:");
console.log("["+resultArray.join(", ")+"]");
.as-console-wrapper { max-height: 100% !important; top: 0; }
Testing for larger Arrays:
let arr1 = [90, 44, 64, 16, 24, 20, 64, 86, 20, 64, 56, 72, 16];
let arr2 = [21, 13, 9, 13, 15, 7, 17, 15, 9, 19, 7, 15, 9];
for(let i=0; i<10; i++) {
arr1 = arr1.concat(arr1);
arr2 = arr2.concat(arr2);
};
let start = null;
let resultArray = null;
start=new Date();
resultArray = [...arr1, ...arr2].sort((a, b) => b - a);
console.log("First resultArray took " + (Date.now() - start) + "ms");
start = null;
resultArray = null;
start=new Date();
resultArray = arr1.concat(arr2).sort(function(a, b) {return b - a});
console.log("Second resultArray took " + (Date.now() - start) + "ms");
.as-console-wrapper { max-height: 100% !important; top: 0; }
Seems like let resultArray = [...arr1, ...arr2].sort((a, b) => b - a); takes longer than what resultArray = arr1.concat(arr2).sort(function(a, b) {return b - a}); takes...
You can sort the arrays separately then merge them:
const sarr1 = arr1.sort((a, b) => b - a);
const sarr2 = arr2.sort((a, b) => b - a);
const tot = [];
let arr1i = 0;
let arr2i = 0;
while (arr1i < sarr1.length && arr2i < sarr2.length) {
if (sarr1[arr1i] >= sarr2[arr2i]) {
tot.push(sarr1[arr1i]);
arr1i++;
} else {
tot.push(sarr2[arr2i]);
arr2i++;
}
}
while (arr1i < sarr1.length) {
tot.push(sarr1[arr1i ++]);
}
while (arr2i < sarr2.length) {
tot.push(sarr2[arr2i ++]);
}
// tot now contains the fully sorted array

Spiral Matrix: Inner Functions Work But Throw Error When Used In While Loop

A Spiral Matrix coding challenge in JavaScript; of particular importance are the four inner functions leftToRight, topToBottom, rightToLeft, and bottomToTop. Commenting out the while loop and invoking the four functions within the scope of spiralCopy like so:
leftToRight(iLeftRightStart, iLeftRightEnd, leftRightPosition);
topToBottom(iTopBottomStart, iTopBottomEnd, topBottomPosition);
rightToLeft(iRightLeftStart, iRightLeftEnd, rightLeftPosition);
bottomToTop(iBottomTopStart, iBottomTopEnd, bottomTopPosition);
Returns [ 1, 2, 3, 4, 5, 6, 12, 18, 24, 30, 36, 35, 34, 33, 32, 31, 25, 19, 13, 7 ], as expected.
However, when used in the while loop in the code below the program crashes with the following error:
spiral.push(matrix[position][i]);
^
TypeError: Cannot read property '1' of undefined
Here is the entire program:
inputMatrix = [
[1, 2, 3, 4, 5, 6],
[7, 8, 9, 10, 11, 12],
[13, 14, 15, 16, 17, 18],
[19, 20, 21, 22, 23, 24],
[25, 26, 27, 28, 29, 30],
[31, 32, 33, 34, 35, 36]
]
const spiralCopy = (matrix) => {
const spiralLength = matrix.length * matrix[0].length;
const spiral = [];
let iLeftRightStart = 0; // +1
let iLeftRightEnd = matrix[0].length; // -1
let leftRightPosition = 0; // +1
let iTopBottomStart = 1; // +1
let iTopBottomEnd = matrix.length; // -1
let topBottomPosition = matrix[0].length - 1; // -1
let iRightLeftStart = matrix[0].length - 2; // -1
let iRightLeftEnd = 0; // +1
let rightLeftPosition = matrix.length - 1; // -1
let iBottomTopStart = matrix.length - 2; // -1
let iBottomTopEnd = 1; // +1
let bottomTopPosition = 0; // +1
const leftToRight = (iStart, iEnd, position) => {
console.log(iStart, iEnd, position);
for (let i = iStart; i < iEnd; i++) {
spiral.push(matrix[position][i]);
}
}
const topToBottom = (iStart, iEnd, position) => {
for (let i = iStart; i < iEnd; i++) {
spiral.push(matrix[i][position]);
}
}
const rightToLeft = (iStart, iEnd, position) => {
for (let i = iStart; i >= iEnd; i--) {
spiral.push(matrix[position][i]);
}
}
const bottomToTop = (iStart, iEnd, position) => {
for (let i = iStart; i >= iEnd; i--) {
spiral.push(matrix[i][position]);
}
}
while (spiral.length < spiralLength) {
leftToRight(iLeftRightStart, iLeftRightEnd, leftRightPosition);
topToBottom(iTopBottomStart, iTopBottomEnd, topBottomPosition);
rightToLeft(iRightLeftStart, iRightLeftEnd, rightLeftPosition);
bottomToTop(iBottomTopStart, iBottomTopEnd, bottomTopPosition);
iLeftRightStart++;
iLeftRightEnd--;
leftRightPosition--;
iTopBottomStart++;
iTopBottomEnd--;
topBottomPosition--;
iRightLeftStart--;
iRightLeftEnd++;
rightLeftPosition--;
iBottomTopStart--;
iBottomTopEnd++;
bottomTopPosition++;
}
return spiral;
}
console.log(spiralCopy(inputMatrix));
// should print [1, 2, 3, 4, 5, 6, 12, 18, 24, 30, 36, 35, 34, 33, 32, 31, 25, 19, 13, 7, 8, 9, 10, 11, 17, 23, 29, 28, 27, 26, 20, 14, 15, 16, 22, 21]
Why are the functions not working in the while loop?
The problem was decrementing leftRightPosition instead of incrementing it.
I changed the
leftRightPosition--;
To
leftRightPosition++;
And it works.

Wrap items in an array with a character

I have an array [1, 5, 20, 17, 6, 12, 13, 20, 1, 14, 20].
Whenever the element of the array is equal to 20 I would like to wrap it with an asterisk on either side like this [1, 5, *20*, 17, 6, 12, 13, *20*, 1 , 14, *20*].
How can I achieve this?
You can use map
let arr = [1, 5, 20, 17, 6, 12, 13, 20, 1, 14, 20]
let result = arr.map(o => o === 20 ? '*20*' : o);
console.log(result);
Doc: map()
You can use Arrays forEach to modify the elements of the array. elem is each element and i is the respective index. We are using forEach to modify the existing array. Since this is what you desired..
let arr = [1, 5, 20, 17, 6, 12, 13, 20, 1, 14, 20]
arr.forEach((elem, i) => {
if (elem === 20) {
arr[i] = "*20*"
}
})
console.log(arr)
function rollDice(max, times, bonus) {
var rolls = [1, 5, 20, 17, 6, 12, 13, 20, 1, 14, 20];
rolls.forEach((elem, i) => { if (elem === 20) { rolls[i] = "twenty" } });
for (var i = 0; times > i; i++)
{
max = Math.floor(max);
rolls.push(Math.floor(Math.random() * max) + 1 | + parseInt(bonus));
}
console.log(rolls);
}
rollDice(20, 5);
The problem you are experiencing is that you need to convert the integer number into strings. JavaScript has several ways to cleverly do this behind-the-scenes, but if you are still gaining an understanding of that, it's better to be explicit about what data types you start with (integers), and what data types you expect to end with (strings).
You transform the array, "mapping" over each item, transforming it to a string, and then if the string matches "20", you add the asterisks.
const start_array = [1, 5, 20, 17, 6, 12, 13, 20, 1, 14, 20];
const new_array = start_array.map((integer) => {
let number_string = integer.toString();
if (number_string === "20") {
number_string = "*" + number_string + "*";
}
return number_string;
})
console.log(new_array);

Categories

Resources