How to shuffle an array without moving FALSY elements? - javascript

Here is my attempt; a slightly-modified Fisher-Yates algorithm. I am not sure how to make sure it's random though.
const shuffleWithoutMovingFalsies = array => {
const newArray = [...array];
const getRandomValue = (i, N) => ~~(Math.random() * (N - i) + i);
newArray.forEach((elem, i, arr, j = getRandomValue(i, arr.length)) => arr[i] && arr[j] && ([arr[i], arr[j]] = [arr[j], arr[i]]));
return newArray;
}
const array = [1, 2, null, 3, null, null, 4, 5, 6, null];
const shuffledArray = shuffleWithoutMovingFalsies(array);
console.log(shuffledArray);
All I did was add arr[i] && arr[j] && as a check to make sure both elements about to be swapped are NOT falsy.

That stops it from being a fair shuffle. For example, with the array [1, null, 2], 1 should have a 50% chance of staying put and a 50% chance of swapping with 2, but instead, the split is ⅔–⅓.
As long as the auxiliary memory isn’t an issue, I’d recommend extracting the elements, shuffling them, and putting them back for simplicity:
const shuffle = arr => {
for (let i = 0; i < arr.length - 1; i++) {
const j = i + Math.floor(Math.random() * (arr.length - i));
[arr[i], arr[j]] = [arr[j], arr[i]];
}
};
const shuffleTruthy = arr => {
const truthy = arr.filter(Boolean);
shuffle(truthy);
let j = 0;
for (let i = 0; i < arr.length; i++) {
if (arr[i]) {
arr[i] = truthy[j++];
}
}
};

Related

Sum of to arrays with different array sizes

I'm trying to solve sum of to array problem:
//[1,2,3] + [1,2] should be [1,3,5]
I'm able to solve this if the array are the same size, but how can I deal with different array sizes?
Here is my code for now:
function sumOfArrays(a, b) {
let result = new Array(Math.max(a.length, b.length));
let carry = 0;
for (let i = result.length - 1; i >= 0; i--) {
const elementA = a[i];
const elementB = b[i];
const additionResult = elementA + elementB + carry;
result[i] = (additionResult % 10);
carry = Math.floor(additionResult / 10);
}
}
I'm basically getting null values into the result array If there is a difference in the size of the array
You could add a comparison if the 2 arrays are the same length.
If not, you can 'pad' it from the beginning with 0's until ther are the same length.
Then your code will work as expected (after adding return result ;) )
const pad = (arr, size, fill = 0) => [ ...Array(size - arr.length).fill(0), ...arr ];
let a = [1,2,3];
let b = [1,2];
if (a.length < b.length) {
a = pad(a, b.length);
} else if (b.length < a.length) {
b = pad(b, a.length);
}
function sumOfArrays(a, b) {
let result = new Array(Math.max(a.length, b.length));
let carry = 0;
for (let i = result.length - 1; i >= 0; i--) {
const elementA = a[i];
const elementB = b[i];
const additionResult = elementA + elementB + carry;
result[i] = (additionResult % 10);
carry = Math.floor(additionResult / 10);
}
return result;
}
const res = sumOfArrays(a, b);
console.log(res)
However, since the array's are now the same length, we can simplefy the code a lot by using map() and add (+) to current value of the other array on that index:
const pad = (arr, size, fill = 0) => [ ...Array(size - arr.length).fill(0), ...arr ];
let a = [1,2,3];
let b = [1,2];
if (a.length < b.length) {
a = pad(a, b.length);
} else if (b.length < a.length) {
b = pad(b, a.length);
}
function sumOfArrays(a, b) {
return a.map((n, i) => n + b[i]);
}
const res = sumOfArrays(a, b);
console.log(res)
// [
// 1,
// 3,
// 5
// ]
You could take an offset for the index to add.
function add(a, b) {
const
length = Math.max(a.length, b.length),
offsetA = a.length - length,
offsetB = b.length - length;
return Array.from(
{ length },
(_, i) => (a[i + offsetA] || 0) + (b[i + offsetB] || 0)
);
}
console.log(...add([1, 2, 3], [1, 2])); // [1, 3, 5]
console.log(...add([1, 2, 3], [4, 5, 6]));
console.log(...add([1, 2, 3, 4], [1])); // [1, 2, 3, 5]
console.log(...add([1], [1, 2, 3, 4])); // [1, 2, 3, 5]

Maintain the duplicates in the sum of array integers

I wrote a program to:
Print the new array of elements
Print the sum of all elements (or integers)
Actually, I got it right, however, the little problem is, I want to maintain all the duplicates (still within the range of four largest elements). Here's what I mean:
Take an array of numbers: [4,5,-2,3,1,2,6,6]
The four largest numbers are 4,5,6,6. And their sum is 4+5+6+6=21
What the code is doing (not good):
Instead of getting "6,6,5,4" as (described above), the code is printing "6,5,4,3" with the sum as 18.
ALSO, when there are only four elements [with or without duplicates] as in [1,1,1,-5],
let it just add ALL elements. You guessed it, the sum of all elements is -2
How do I order the program to print the necessary duplicate(s) to make the four largest integers?
Here's my code...
var arr = new Array(4,5,-2,3,1,2,6,6);
// var arr = new Array(1,1,1,-5);
// var largArr = new Array();
function largest() {
largArr = Array(0, 0, 0, 0)
for (i = 0; i < arr.length; i++) {
if (arr[i] > largArr[0]) {
largArr[0] = arr[i];
}
}
for (i = 0; i < arr.length; i++) {
if (arr[i] > largArr[1] && arr[i] < largArr[0]) {
largArr[1] = arr[i];
}
}
for (i = 0; i < arr.length; i++) {
if (arr[i] > largArr[2] && arr[i] < largArr[1]) {
largArr[2] = arr[i];
}
}
for (i = 0; i < arr.length; i++) {
if (arr[i] > largArr[3] && arr[i] < largArr[2]) {
largArr[3] = arr[i];
}
}
console.log(largArr[0], largArr[1], largArr[2], largArr[3]);
console.log(largArr[0] + largArr[1] + largArr[2] + largArr[3]);
}
largest();
I believe there is a genius out there who can help me solve this :)
You could get the top four and filter the original array.
function get4Largest(array) {
const top4 = [...array].sort((a, b) => b - a).slice(0, 4);
return array.filter(v => {
if (top4.includes(v)) {
top4.splice(top4.indexOf(v), 1);
return true;
}
});
}
console.log(get4Largest([4, 5, -2, 3, 1, 2, 6, 6]));
A different approach by keeping indices.
function get4Largest(array) {
return array
.map((v, i) => [v, i])
.sort(([a], [b]) => b - a)
.slice(0, 4)
.sort(([, a], [, b]) => a - b)
.map(([v]) => v);
}
console.log(get4Largest([4, 5, -2, 3, 1, 2, 6, 6]));
If you want sum of largest four numbers then you can easily do with sort, slice and reduce:
numbers.sort((a, b) => b - a).slice(0, 4).reduce((acc, curr) => acc + curr, 0)
const numbers = [4, 5, -2, 3, 1, 2, 6, 6];
const result = numbers
.sort((a, b) => b - a)
.slice(0, 4)
.reduce((acc, curr) => acc + curr, 0);
console.log(result);
You can use a reduce, sort and slice methods of an array like so:
function sumMaxValues (maxLength, values) {
return values
.sort((v1, v2) => v1 > v2 ? -1 : 1)
.slice(0, maxLength)
.reduce((sum, v) => sum + v, 0)
}
console.log(
sumMaxValues(4, [4, 5, -2, 3, 1, 2, 6, 6, 10]),
)
Edit: I fixed, a bug that #gog pointed out. The root cause of a problem was that sort when invoked without a compareFn then "the array elements are converted to strings, then sorted according to each character's Unicode code point value."(sort docs)
If for some reason you want to have a classical type of solution, that avoids modern javascript methods, here's one
const arr = Array(4, 5, -2, 3, 1, 2, 6, 6);
//const arr = Array(1, 1, 1, -5);
function largest(){
const largArr = Array(-1/0, -1/0, -1/0, -1/0);
for(let i = 0; i < arr.length; i++){
for(let j = 0; j < largArr.length; j++){
if(arr[i] > largArr[j]){
for(let k = largArr.length - 2; k >= j; k--){
largArr[k + 1] = largArr[k];
}
largArr[j] = arr[i];
break;
}
}
}
let sum = 0;
for(let j = 0; j < largArr.length; j++){
if(largArr[j] === -1/0){
largArr[j] = 0;
}
sum += largArr[j];
}
console.log(largArr, sum);
}
largest();
-1/0 stands for minus infinity (there can be no smaller number); you may also use Number.NEGATIVE_INFINITY for it. If it's too exotic for your needs, replace -1/0 with any number you are certain is less than any possible number in the array (that however, cannot be zero, since you allow negative numbers also).

JavaScript algorithm: is there a way to sort an already sorted array with the absolute values of its elements

I got this question during an interview.
I have an array that contains both negative and positive integers that are already sorted e.g.
const array = [-5, -3, 0, 2,7]
I am trying to write a function to sort the array using the absolute values of its elements. So the sorted array would be [ 0, 2, 3, 5, 7 ]
Here is my attempt
function sortArrayWithAbsoluteValue(array) {
const result = array.map(num => Math.abs(num)).sort((a,b) => a - b)
return result
}
Apparently, this works but it doesn't take advantage of the fact that the array is already sorted . Is there a better or more clever/efficient way to sort this?
the easiest solution is to introduce a new array and simply unshift it with elements from the first array
const array = [-9, -8, -5, -3, -2, 0, 2,7];
const newArray = [];
let i = 0, j = array.length - 1;
while(i <= j) {
const first = Math.abs(array[i]);
const last = Math.abs(array[j]);
if(first > last){
newArray.unshift(first)
i++;
}
else {
newArray.unshift(last)
j--;
}
}
console.log(newArray)
But this solution could be challenged by interviewers as unshift operator is slow o(n) so we can create newArray with the same size as array and then simply fill it in a similar way
const array = [-9, -8, -5, -3, -2, 0, 2,7];
const newArray = new Array(array.length);
let i = 0, j = array.length - 1, l = array.length - 1;
while(i <= j) {
const first = Math.abs(array[i]);
const last = Math.abs(array[j]);
if(first > last){
newArray[l] = first;
i++;
}
else {
newArray[l] = last;
j--;
}
l--;
}
console.log(newArray)
hope it helps!
You can let two indexes move towards eachother from either ends of the input array and based on how they compare, you copy the absolute value to the target array, filling it from end to front:
function absSorted(array) {
let result = Array(array.length);
for (let k = array.length - 1, i = 0, j = k; k >= 0; k--) {
result[k] = Math.abs(array[-array[i] < array[j] ? j-- : i++]);
}
return result;
}
const array = [-5, -3, 0, 2, 7];
console.log(absSorted(array));
You can use two iterators. One iterator starts from left and the other from right. Since the array is sorted one iterator points to the max absolute value. Store this value in a new array and iterate that iterator
const array = [-5, -3, 0, 2,7]
function f(array) {
let i = 0;
let j = array.length - 1;
const newArray = [];
while (i <= j) {
if (Math.abs(array[i]) < Math.abs(array[j])) {
newArray.push(Math.abs(array[j]));
--j;
} else {
newArray.push(Math.abs(array[i]));
++i;
}
}
return newArray;
}
console.log(f(array));
You can start at the min values with the inverted logic to get an increasing sort:
const array = [-5, -3, 0, 2, 7]
function g(array) {
let j = 0;
while (j < array.length && array[j] < 0) {
++j;
}
let i = j - 1;
const newArray = [];
while (i >= 0 && j < array.length) {
if (Math.abs(array[i]) < Math.abs(array[j])) {
newArray.push(Math.abs(array[i]));
--i;
} else {
newArray.push(Math.abs(array[j]));
++j;
}
}
if (i >= 0) {
newArray.push(...array.slice(0, i + 1).reverse().map(el => -el));
}
if (j < array.length) {
newArray.push(...array.slice(j));
}
return newArray;
}
console.log(g(array));
I converted all the numbers to the absolute value first using map
Then using a while loop, I used the indexOf and Math.min functions and the spread operator (...) to find the index of the minimum number of the array
Then I removed that from the array using splice
const array = [-5, -3, 0, 2,7];
function resort(array) {
const newArray = [];
array = array.map(i => Math.abs(i));
while (array.length) {
const minIndex = array.indexOf(Math.min(...array));
newArray.push(array.splice(minIndex, 1)[0]);
}
return newArray;
}
console.log(resort(array));

Sort Array to 1st min, 1st max, 2nd min, 2nd max, etc

Write a JS program to return an array in such a way that the first element is the first minimum and the second element is the first maximum and so on.
This program contains a function which takes one argument: an array. This function returns the array according to the requirement.
Sample Input: array=[2,4,7,1,3,8,9]. Expected Output: [1,9,2,8,3,7,4].
const arrsort=(arr)=>{
return arr.sort(function(a, b){return a - b});
}
const test=(arr)=>{
arr=arrsort(arr);
var arr2=[];
var j=0;
var k=arr.length-1;
for (var i=0;i<arr.length-1;i++){
if(i%2===0){
arr2.push(arr[j]);
j++;
}
else{
arr2.push(arr[k]);
k--;
}
}
return arr2;
}
Instead of using two indices, you could shift and pop the values of a copy of the sorted array.
var array = [2, 4, 7, 1, 3, 8, 9]
const arrsort = arr => arr.sort((a, b) => a - b);
const test = (arr) => {
var copy = arrsort(arr.slice()),
result = [],
fn = 'pop';
while (copy.length) {
fn = { pop: 'shift', shift: 'pop' }[fn];
result.push(copy[fn]());
}
return result;
}
console.log(test(array));
You can first sort() the array in ascending order and then loop through half of the array. And push() the values at corresponding indexes.
let arr = [2,4,7,1,3,8,9];
function order(arr){
let res = [];
arr = arr.slice().sort((a,b) => a-b);
for(let i = 0; i < Math.floor(arr.length/2); i++){
res.push(arr[i],arr[arr.length - 1 - i]);
}
return arr.length % 2 ? res.concat(arr[Math.floor((arr.length - 1)/2)]) : res;
}
console.log(order(arr))
You could sort the array, then copy and reverse and push to another array
const a = [2,4,7,1,3,8,9];
a.sort();
const b = a.slice().reverse();
const res = [];
for (let i = 0; i < a.length; i++) {
if (res.length < a.length) res.push(a[i]);
if (res.length < a.length) res.push(b[i]);
}
console.log(res);
Or use a Set
const a = [2,4,7,1,3,8,9];
a.sort();
const b = a.slice().reverse();
const res = new Set();
a.forEach((e, i) => (res.add(e), res.add(b[i])));
console.log(Array.from(res));
There are many ways are available to do this. And my solution is one of themm i hope.
Find max and min value, push them into another array. And delete max, min from actual array.
let array=[2,4,7,1,3,8,9];
let finalArray = [];
let max, min;
for(let i = 0; i < array.length; i++) {
max = Math.max(...array);
min = Math.min(...array);
finalArray.push(min);
finalArray.push(max);
array = array.filter(function(el) {
return el != max && el != min;
})
}
console.log(finalArray);
After sorting array this would work
myarr = [1,2,3,4,5,6];
let lastindex = myarr.length-1;
for(let i = 1 ; i <= myarr.length/ 2; i = i+2) {
ele = myarr[i];
myarr[i] = myarr[lastindex];
myarr[lastindex] = ele;
lastindex--;
}
Final Output will be: [1, 6, 3, 5, 4, 2]
You can use two iterators after sorting your array, one goes ascending and the other goes descending, until they cross each other.
Here's the code:
const array = [2, 4, 7, 1, 3, 8, 9];
const test = arr => {
const result = [];
const sortedArr = array.sort((a, b) => a - b);
for (let i = 0, j = sortedArr.length - 1; i <= j; i++, j--) {
result.push(sortedArr[i]);
i == j || result.push(sortedArr[j]);
}
return result;
};
console.log(test(array));
You can easily achieve the result using two pointer algorithm
function getValue(arr) {
const result = [];
let start = 0,
end = arr.length - 1;
while (start < end) result.push(arr[start++], arr[end--]);
if (start === end) result.push(arr[start]);
return result;
}
const array = [2, 4, 7, 1, 3, 8, 9];
const sorted = array.sort();
console.log(getValue(sorted));

Javascript: Bubble Sort

I have made a bubble sort algorithm (sorta) using JS. It works sometimes, but the problem is that it only iterates through the array once. Here is my code:
function bubble(arr) {
for (var i = 0; i < arr.length; i++) {
if (arr[i] > arr[i + 1]) {
var a = arr[i]
var b = arr[i + 1]
arr[i] = b
arr[i + 1] = a
}
}
return arr;
}
Another bubble sort implementation:
const bubbleSort = array => {
const arr = Array.from(array); // avoid side effects
for (let i = 1; i < arr.length; i++) {
for (let j = 0; j < arr.length - i; j++) {
if (arr[j] > arr[j + 1]) {
[arr[j], arr[j + 1]] = [arr[j + 1], arr[j]];
}
}
}
return arr;
};
You need an inner loop to complete the sort correctly:
function bubble(arr) {
var len = arr.length;
for (var i = 0; i < len ; i++) {
for(var j = 0 ; j < len - i - 1; j++){ // this was missing
if (arr[j] > arr[j + 1]) {
// swap
var temp = arr[j];
arr[j] = arr[j+1];
arr[j + 1] = temp;
}
}
}
return arr;
}
document.write(bubble([1,9,2,3,7,6,4,5,5]));
Please look at the following sequence:
[5, 4, 3, 2, 1]
Now lets say you need to sort this in the ascending order using bubble sort.
So, you iterate the array and swap adjacent elements which are ordered otherwise.
Here is what you will get after the completion of the iteration
[4, 3, 2, 1, 5]
Now if you do this another time, you will get this:
[3, 2, 1, 4, 5]
Likewise, you need to repeat the iteration enough times to get it sorted fully. This means you need 2 nested loops. The inner loop is to iterate the array and the outer loop is to repeat the iteration.
Please see the step-by-step example of this article.
const bubbleSort = (array)=>{
let sorted = false;
let counter =0;
while(!sorted){
sorted = true;
for(let i =0; i < array.length -1 -counter; i++){
if(array[i] > array[i+1]){
helper(i,i+1,array);
sorted = false;
}
}
counter++;
}
return array;
}
//swap function
function helper(i,j, array){
return [array[i],array[j]] = [array[j],array[i]]
}
let array=[8,5,2,9,5,6,3];
console.log(bubbleSort(array))
var array = [6,2,3,7,5,4,1];
function bubbleSort(arr) {
for(let j=0;j<arr.length;j++) {
for(let i = 0; i < arr.length; i++) {
if(arr[i]>arr[i+1] && (i+1 < arr.length)) {
var temp = arr[i];
arr[i] = arr[i+1];
arr[i+1] = temp;
}
}
}
return arr;
}
console.log(bubbleSort(array));
My bubble sort with just a while loop :
function bubbleSort(arr){
var sorted = false
while (!sorted){
sorted = true;
arr.forEach(function (element, index, array){
if (element > array[index+1]) {
array[index] = array[index+1];
array[index+1] = element;
sorted = false;
}
});
}
}
function bubble(arr) {//You need Two Loops for Bubble sort
for (var i = 0; i < arr.length; i++) {//Outer Loop
for(var j=0; j < arr.length - 1; j++){//Inner Loop
if (arr[j] > arr[j + 1]) {
var a = arr[j]
var b = arr[j + 1]
arr[j] = b
arr[j + 1] = a
}
}
}
return arr;
}
Another form of bubble sort includes starting at the end of the array and placing the smallest element first and going till the largest. This is the code:
function bubbleSort(items) {
var length = items.length;
for (var i = (length - 1); i >= 0; i--) {
//Number of passes
for (var j = (length - i); j > 0; j--) {
//Compare the adjacent positions
if (items[j] < items[j - 1]) {
//Swap the numbers
var tmp = items[j];
items[j] = items[j - 1];
items[j - 1] = tmp;
}
}
}
}
Note Bubble sort is one of the slowest sorting algorithms.
It works for me. I commented the code for more understanding
bubbleSort = (numbersArray) => {
const arrayLenght = numbersArray.length;
for (let i = 0; i < arrayLenght; i++) {
for(let j = 0; j < arrayLenght; j++) {
// Print only to debug
// console.log(`i: ${i} - j: ${j}`);
// console.log(`numbersArray[i]: ${numbersArray[i]} | numbersArray[j]: ${numbersArray[j]}`);
// Check if current number is greater than the next number
if (numbersArray[j] > numbersArray[j + 1]) {
// Store current value to generate swap
const currentNumber = numbersArray[j];
// Now the current position get value of the next position
// And de next position get value of the current position
numbersArray[j] = numbersArray[j + 1];
numbersArray[j + 1] = currentNumber;
}
}
}
// Debug: Print the sorted array
console.log(`sorted array: ${numbersArray.toString()}`);
}
const numbers = [
[3, 10, 5, 7],
[8, 5, 2, 9, 5, 6, 3],
[4, 50, 28, 47, 9, 2097, 30, 41, 11, 3, 68],
[3, 10, 5, 7, 8, 5, 2, 9, 5, 6, 3]
];
numbers.forEach(element => {
bubbleSort(element);
});
Output:
sorted array: 3,5,7,10
sorted array: 2,3,5,5,6,8,9
sorted array: 3,4,9,11,28,30,41,47,50,68,2097
sorted array: 2,3,3,5,5,5,6,7,8,9,10
var arr = [5, 3, 4, 1, 2, 6];
function sort (arr) {
for(let i=0; i < arr.length - 1; i++) {
if(arr[i] > arr[i+1]) {
let b = arr[i+1];
arr[i+1] = arr[i];
arr[i] = b;
i = -1; // Resets the loop
}
}
return arr;
}
console.log(sort(arr));
Try this (performance upgrade):
function bubbleSort(inputArr, reverse = false) {
const len = inputArr.length;
for (let i = 0; i < len; i++) {
for (let j = i + 1; j < len; j++) {
let a = inputArr[i];
let b = inputArr[j];
if (reverse ? a < b : a > b) {
const tmp = inputArr[j];
inputArr[j] = inputArr[i];
inputArr[i] = tmp;
}
}
}
return inputArr;
}
Use:
arr = [234,2,4,100, 1,12,5,23,12];
console.log(bubbleSort(arr)); // or console.log(bubbleSort(arr, true));
You need another loop:
var arr = [2, 1]
for(let i = 0;i<arr.length;i++){
for(let b = 0; b<arr.length;i++){
if(arr[b] > arr[b+1]){
var first = arr[b]
var second = arr[b + 1]
arr[b] = second
arr[b + 1] = first
}
}
}
Hope this helps I would recommend using quick sort if you want a high efficiency though.
const bubbleSort = (inputArr) => {
const len = inputArr.length;
for (let i = 0; i < len; i++) {
for (let j = 0; j < len; j++) {
if (inputArr[j] > inputArr[j + 1]) {
let tmp = inputArr[j];
inputArr[j] = inputArr[j + 1];
inputArr[j + 1] = tmp;
}
}
}
return inputArr;
};
const numbers = [50, 30, 10, 40, 60];
console.log(bubbleSort(numbers));
// Output: [ 10, 30, 40, 50, 60 ]
function bubbleSort(array) {
var done = false;
while (!done) {
//alert(1)
done = true;
for (var i = 1; i < array.length; i += 1) {
if (array[i - 1] > array[i]) {
//alert(2)
done = false;
var tmp = array[i - 1];
array[i - 1] = array[i];
array[i] = tmp;
}
}
}
return array;
}
Another way would be like this:
function bubbleSort(arr) {
let swapped;
do {
swapped = false;
for (var i = 0; i < arr.length; i++) {
if (arr[i] > arr[i + 1]) {
swapped = true;
var tmp = arr[i];
arr[i] = arr[i + 1];
arr[i + 1] = tmp;
}
}
} while (swapped);
return arr;
}
let myArray = [8, 1, 2, 5, 51, 13, 15, 33, 123, 100, 22];
console.log(bubbleSort(myArray));
Explanation:
In this function we are going to declare a swapped variable that is being set to false inside the DO WHILE loop, this is being done as a fail-safe not to end up with an infinite loop.
Inside the loop, we have another FOR loop which iterates through the given array and checks if the current value is greater than the next (which we don't want, we need ascending order).
When the IF the condition is true, we are going to swap the variables and assign true for the swapped variable, this is done because we want to keep on the DO WHILE loop untill everything is sorted.
package hasan;
public class hssd {
public static void main(String[] args) {
int t=9;
int g=20;
for (t=g;t>19;++t){
System.out.println(7);
int f=12;
int r=15;
for(r=f;r>5;++r)
System.out.println(r+1000000000+"*"+1000000000);
}
}
}

Categories