Ruby. Shuffle the array so that there are no adjacent elements with the same value
The simple and maybe the less effective way could be the brute force.
So on a simplified version of the array, one can do:
ary = %w(a a c c b a s)
loop do
break if ary.shuffle!.slice_when { |a, b| a == b }.to_a.size == 1
end
Some check should be added to assure that a solution exists, to avoid infinite loop.
Other (better?) way is to shuffle then find the permutation (no infinite loop) which satisfy the condition:
ary.shuffle!
ary.permutation.find { |a| a.slice_when { |a, b| a == b }.to_a.size == 1 }
If a solution does not exist, it returns nil
.
Run the the benchmark:
def looping
ary = %w(a a c c b a s)
loop do
break if ary.shuffle!.slice_when { |a, b| a == b }.to_a.size == 1
end
ary
end
def shuffle_permute
ary = %w(a a c c b a s)
ary.shuffle!
ary.permutation.lazy.find { |a| a.slice_when { |a, b| a == b }.to_a.size == 1 }
end
require 'benchmark'
n = 500
Benchmark.bm do |x|
x.report { looping }
x.report { shuffle_permute }
end
Is there any difference between the following algorithms for shuffling arrays?
Yes, they are in fact different.
The first algorithm is a variant of the classic Knuth Shuffle.
For this algorithm, we can prove (e.g., by induction) that, if our random number generator (Math.random()
) was an ideal one, it would generate every one of the n! (n factorial) possible permutations with equal probability.
The second algorithm does not have this property.
For example, when n = 3, there are 33 = 27 possible outcomes, and that does not divide evenly by 3! = 6, the number of possible permutations.
Indeed, here are the probabilities of outcomes (programs generating statistics: 1 2):
[0, 1, 2] 4/27
[0, 2, 1] 5/27
[1, 0, 2] 5/27
[1, 2, 0] 5/27
[2, 0, 1] 4/27
[2, 1, 0] 4/27
For n = 4, the results are even more uneven, for example (programs generating statistics: 3 4):
[1, 0, 3, 2] has probability 15/256
[3, 0, 1, 2] has probability 8/256
As you can imagine, this is an undesired property if your permutation is supposed to be uniformly random.
Lastly, the fact that we usually use a pseudorandom number generator instead of a true random source does not invalidate any of the above.
The defects of our random number generator, if any, are obviously unable to repair the damage at the later step - if we choose a non-uniform algorithm, that is.
Shuffle an Array coding challenge. trouble understanding one part
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).
How to shuffle an array so that all elements change their place
For each element e
If there is an element to the left of e
Select a random element r to the left of e
swap r and e
This guarantees that each value isn't in the position that it started, but doesn't guarantee that each value changes if there's duplicates.
BeeOnRope notes that though simple, this is flawed. Given the list [0,1,2,3], this algorithm cannot produce the output [1,0,3,2].
Shuffle arrays of strings in JavaScript with repeated elements that are at least two elements apart
The easiest would probably be doing it in two steps.
- Shuffle
array1
with a standard fisher-yates algorithm. - Insert the elements at random positions satisfying the conditions.
Ie something like the following (I assume, you can implement fisher yates, thus I didn't include it here and just made an (unshuffled) copy of the array)
let array1 = [1,2,3,4,5,6,7]
let array2 = [8,9]
let rand = (n) => Math.floor(Math.random()*n);
//let shuffled = fisheryates(array1);
let shuffled = array1.slice(); //just make a copy of the array
while (array2.length) {
let e = array2.splice(rand(array2.length), 1)[0];
let i1 = shuffled.length == 2
? 0
: rand(shuffled.length + 1);
let i2 = 0;
do {
i2 = shuffled.length == 2
? 2
: rand(shuffled.length + 1);
}
while (Math.abs(i1 - i2) < 2)
if (i1 < i2) {
shuffled.splice(i2, 0, e);
shuffled.splice(i1, 0, e);
} else {
shuffled.splice(i1, 0, e);
shuffled.splice(i2, 0, e);
}
}
console.log(shuffled)
Shuffle element such that, no element should come at its original index
This works for me:
var SourceList = new List<string>()
{
"Obj_A", "Obj_B", "Obj_C", "Obj_D", "Obj_E", "Obj_F", "Obj_G",
};
var rnd = new Random();
var ResultList =
Enumerable
// create an exceedingly long sequence for retries
.Repeat(0, int.MaxValue)
// select and randomly order all of the indices of `SourceList`
.Select(_ => Enumerable.Range(0, SourceList.Count)
.OrderBy(x => rnd.Next())
.ToArray())
// Discard the indices if they have any matching positions
.Where(x => !x.Where((y, i) => y == i).Any())
// only take one successful set of indices
.Take(1)
// flatten the list of lists to a list
.SelectMany(x => x)
// select the elements from `SourceList` from their index positions
.Select(x => SourceList[x])
// convert to list
.ToList();
The use of .OrderBy(x => rnd.Next())
produces a uniform ordering (no bias) - I have confirmed this in the past.
How to randomize (shuffle) a JavaScript array?
The de-facto unbiased shuffle algorithm is the Fisher-Yates (aka Knuth) Shuffle.
You can see a great visualization here (and the original post linked to this)
function shuffle(array) {
let currentIndex = array.length, randomIndex;
// While there remain elements to shuffle.
while (currentIndex != 0) {
// Pick a remaining element.
randomIndex = Math.floor(Math.random() * currentIndex);
currentIndex--;
// And swap it with the current element.
[array[currentIndex], array[randomIndex]] = [
array[randomIndex], array[currentIndex]];
}
return array;
}
// Used like so
var arr = [2, 11, 37, 42];
shuffle(arr);
console.log(arr);
Related Topics
Swift Pattern Matching with Enum and Optional Tuple Associated Values
How to Declare Protocol Property as Private
Nested Tabview - Remove Inner Tab Bar iOS 13, Swift Ui
How to Trim a String in Swift Based on a Character
How to Check If Cmtime Is Valid in Swift
How to Convert Curl Command to Swift
Require Associatedtype to Be Representable in a @Convention(C) Block
Using Xcode to Cross-Compile Swift to Linux
Nskeyedunarchiver Fails to Decode a Custom Object in Swift
How to Use a Completion Handler to Put an Image in a Swiftui View
Different Portrait/Landscape Views in Storyboard and Swift
Uiswipegesturerecognizer Doesn't Recognize Swipe Gesture Initiated Outside the View
Swift Client and Root Ssl Certificate Authentication
Swift: Copy Information Selected by User in Abpersonviewcontroller to Dictionary