How to randomize subset of array in Javascript? - javascript

What is the best way to randomize part of the array in Javascript
For example, if I have 100 items in the array, what is the fast and efficient way of randomizing set of every 10 times. Items between 0 and 9 is randomize within data items[0] to items[9]. Items between 10 to 19 are randomize within data items[10] to items[19] and so on..

You can adjust the array shuffle method that is described here: http://jsfromhell.com/array/shuffle
It is based on Fisher-Yates (Knuth) algorithm (http://en.wikipedia.org/wiki/Fisher–Yates_shuffle).

I would just use the built in slice, concat and sort methods. Something like this.
function shuffle(arr, start, end) {
return arr.slice(start, end).sort(function() { return .5 - Math.random(); }).concat(arr.slice(end));
};
That's the basic idea, you probably want to make an algorithm to slice every 10 elements, sort and rejoin the sets.
EDIT: Read comments below for why this solution may not be suitable for your needs.

I would split the 1 array into 10 subsets, then perform a shuffle algorithm of your choice on those subsets, and then recombine in the correct order.

The following shuffles the specified chunk of an array in place, as randomly as the environment's random number generator will allow:
function shuffleSubarray(arr, start, length) {
var i = length, temp, index;
while (i--) {
index = start + Math.floor(i * Math.random());
temp = arr[index];
arr[index] = arr[start + i];
arr[start + i] = temp;
}
return arr;
}
var a = [1, 2, 3, 4, 5, 6, 7, 8, 9];
alert( shuffleSubarray(a, 2, 5) );

Related

How to add every combination of numbers in an array

I'm taking in an array of numbers [4, 6, 23, 10, 1, 3] I need to return true if any combinations of numbers in the array add up to the largest number in the array. So the example above should return true because 3 + 4 + 6 + 10 = 23
My thought behind this problem is I should first put the array in numerical order then make a new array with just the numbers I'm adding because I'm not adding the largest number. Then I need some method that says "If any combination of adding these numbers together equals the largest number in the original array return true". This is the code I've written so far, but I'm stuck on the for loop.. Any help would be very much appreciated!
function ArrayChallenge(arr){
let order = arr.sort(function(a, b){return a-b})
let addThese = order.slice(0,order.length-1)
for(i = 0; i < addThese.length-1; i++){
return true
}
}
console.log(ArrayChallenge([3,5,-1,8,12]))
It seems like a trick question. Here's the answer:
function ArrayChallenge(arr){
return true
}
Because the sum of just the largest number is always equal to the largest number.
If this solution is somehow not allowed, see subset sum problem:
there is a multiset S of integers and a target-sum T, and the question is to decide whether any subset of the integers sum to precisely T.
The most straightforward solution to that problem is with recursion; something like this:
function subsetSum(arr, sum) {
if (arr.length == 0) {
// No numbers left in the array. The only sum we can make is 0.
// If that is the sum we are seeking, great!
return sum == 0
} else {
// We will try both using and not using the first number in the array.
// The rest is passed to the recursive call.
const [current, ...remaining] = arr
return (
// Exclude current number, and recurse. We have to make the full
// sum with the remaining numbers.
subsetSum(remaining, sum) ||
// Include current number, meaning we have sum - current left
// to make with the remaining numbers.
subsetSum(remaining, sum - current)
)
}
}

How to insert value in sorted array and keep array sorted? [duplicate]

This question already has answers here:
Efficient way to insert a number into a sorted array of numbers?
(18 answers)
Closed 2 years ago.
What is the best way to insert value in an array and keep the array sorted?
for example here is an array
const arr = [1, 4, 23, 45];
I can add a new value using method push or splice, for example 16, and I'll get modified array:
[1, 4, 23, 45, 16]
But I need to keep array sorted:
[1, 4, 16, 23, 45]
What is the better way to keep array sorted? Should I sort every time when add a new value, or detect necessary index for inserting a new value?
Just look at the complexities:
SORTING: O(nlogn) in the best scenario
INDEX INSERT: O(n) in the worst scenario
SORTING SMART: O(n) in the best scenario, using algorithms like insertionSort, that work very well when the array is almost already sorted
BINARY INSERTION: O(logn) this is the preferred way
function binaryInsertion(arr, element) {
return binaryHelper(arr, element, 0, arr.length - 1);
}
function binaryHelper(arr, element, lBound, uBound) {
if (uBound - lBound === 1) {
// binary search ends, we need to insert the element around here
if (element < arr[lBound]) arr.splice(lBound, 0, element);
else if (element > arr[uBound]) arr.splice(uBound+1, 0, element);
else arr.splice(uBound, 0, element);
} else {
// we look for the middle point
const midPoint = Math.floor((uBound - lBound) / 2) + lBound;
// depending on the value in the middle, we repeat the operation only on one slice of the array, halving it each time
element < arr[midPoint]
? binaryHelper(arr, element, lBound, midPoint)
: binaryHelper(arr, element, midPoint, uBound);
}
}
console.log("even array test");
var array = [1,3,4,5,9];
binaryInsertion(array, 2);
console.log(array);
console.log("odd array test");
var array = [1,3,5,7,9,11,13,15];
binaryInsertion(array, 10);
console.log(array);
console.log("beginning and end test");
var array = [2,3,4,5,9];
binaryInsertion(array, 0);
binaryInsertion(array, 10);
console.log(array);

Shuffle an Array coding challenge. trouble understanding one part

Question:
Shuffle a set of numbers without duplicates.
Example:
// Init an array with set 1, 2, and 3.
int[] nums = {1,2,3};
Solution solution = new Solution(nums);
// Shuffle the array [1,2,3] and return its result. Any permutation of [1,2,3] must equally likely to be returned.
solution.shuffle();
// Resets the array back to its original configuration [1,2,3].
solution.reset();
// Returns the random shuffling of array [1,2,3].
solution.shuffle();
Answer:
var Solution = function(nums) {
// hold nums in Solution
this.nums = nums;
};
Solution.prototype.reset = function() {
return this.nums;
};
Solution.prototype.shuffle = function() {
// create a copy of this.nums, shuffle it, and return it0
const shuffled = this.nums.slice();
const n = shuffled.length;
const swap = (arr, i, j) => {
let tmp = arr[i];
arr[i] = arr[j];
arr[j] = tmp;
}
// swap elements with random elements
for (let i = 0; i < n; i++)
swap(shuffled, i, Math.floor(Math.random() * n));
return shuffled;
};
My question:
The Math.floor(Math.random() * n ) you are getting a random index out of the length of the array. I do not understand, can't this code make duplicates? Say if the length is 3. Cant the formula get the index of 2 and another index of 2, thus making duplicate indexes. Can anyone clarify something I am misunderstanding. Thanks. Does Math.random automatically withdraw indexes that have been used?
Yes, the Math.floor(Math.random() * n) expression can evaluate to the same number multiple times, but that's OK, because the random number is being used in swap, which switches the number at index i with the number at the chosen random index.
If the random index was taken from the original array and added to the array to be returned, eg
const randIndex = Math.floor(Math.random() * n);
arrToBeReturned.push(arr[randIndex]);
you'd be right, but that's not what the algorithm is doing. Imagine randomly sorting an array of [1, 2, 3]:
First iteration of loop: i is 0, random index chosen is 2. Swap indicies 0 and 2:
[3, 2, 1]
Second iteration: i is 1, random index chosen is 2. Swap indicies 1 and 2:
[3, 1, 2]
Third iteration: i is 2, random index chosen is 2. Swap indicies 2 and 2:
[3, 1, 2]
With this code, every index is randomly swapped with another index at least one time, ensuring that by the end, the array is randomized without bias (assuming Math.random is trustworthy).
Math.floor(Math.random() * n) Yes it can eve-valuate to same index but here you're using the number to swap element so this is ok.
Does Math.random automatically withdraw indexes that have been used?
No it doesn't you need to keep track of previously generated values
What you can do it is have a variable a object or Map to keep track of previously add index if the random generated index is not already included in that variable than add it to final output else again generate a new index,
But in this case it is not needed.

Preventing a loop within a loop. How to reduce complexity

You have 2 arrays.
arrA is empty.
arrB is full of stuff (what it's full of doesnt matter, but assume it's huge).
When a user does a thing, an item is removed from arrB and that item is placed in arrA.
When a user does a different thing, it pulls items from arrA and puts it in arrB.
Is it possible to do this without having a loop within a loop?
Or to put it in computer science terminology:
Is it possible to do this with linear ( ϴ(n) ) time/space complexity?
Right now I have something that is at least ϴ(n*k)
(where n is the length of arrB, and k is the number of items passed to applyItems):
var arrA = [], arrB = [1, 2, 3, 4, 5, 6, 7, 8, 9, 0];
function addToArray(arrayToAddTo, item){
if(arrayToAddTo.indexOf(item) === -1){
arrayToAddTo.push(item);
}
}
function removeFromArray(arrayToRemoveFrom, item){
var i = arrayToRemoveFrom.length;
var temp = [];
while(i--){
if(arrayToRemoveFrom[i] !== item){
temp.push(arrayToRemoveFrom[i]);
}
}
return temp;
}
function applyItems(arrayOfItems){
var i = arrayOfItems.length;
while(i--){
var current = arrayOfItems[i]
addToArray(arrA, current);
arrB = removeFromArray(arrB, current);
}
}
applyItems([0, 5, 3]);
console.log(arrA);
console.log(arrB);
applyItems works, but is not efficient.
Is it possible to decrease the time/space complexity here?
Based on my comment:
You can use native tools that will be way faster than manually looping. removeFromArray can use indexOf to get the position of the one to remove and then uses splice to remove it. Also you can work with reference instead of recreating the array every time.
with some other optimizations...
var arrA = [], arrB = [1, 2, 3, 4, 5, 6, 7, 8, 9, 0];
function addToArray(item){
if(arrA.indexOf(item) === -1){
arrA.push(item);
}
}
function removeFromArray(item){
var index = arrB.indexOf(item);
if (index > -1) {
arrB.splice(index, 1);
}
}
function applyItems(arrayOfItems){
arrayOfItems.map(function(item) {
addToArray(item);
removeFromArray(item);
});
}
applyItems([0, 5, 3]);
console.log(arrA);
console.log(arrB);
Right now I have something that is at least ϴ(n*k)
You can make it O(n+k) by using an efficient lookup structure for arrayOfItems that does not require looping, but allows you to determine in O(1) whether an item should be swapped into the other array. With that, a single pass over arrB is enough.
Or if you sort your array and use binary search for the lookup, you will have O(log k * (n+k)). However if your array is finite and very small anyway, that hardly matters.
Also you should omit that indexOf test in addToArray. It seems to be established that no items are in both arrA and arrB (and your algorithm maintains that invariant), so you will not have to check for duplicates before pushing an item to the array.
Yes. Instead of making your own remove function, you can use splice().
So, instead of removeFromArray(arrB, current) you can just do arrB.splice(i, 1);. That will remove 1 element from index i.
You don't need to loop over every element to check if it matches the one you want - just use indexOf(). So you can do something like
var i = arrA.indexOf(item)

How to split an specified number of elements from an array?

I have an array below:
var arr = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20];
and the length of the array is 20 and i am spliting it with 5
When i specify 1, it should return [1,2,3,4,5] and if i specify 2, it should return [6,7,8,9,10]
How can i get it through scripting?
Thanks for the help
You can use the .slice() method to return a segment from an array.
MDN documentation
For your case, you'd do something like this.
arr.slice(5 * n, 5 * n + 5)

Categories