# Array.shuffle/Array.shuffle!

**URL:** <https://www.ruby-forum.com/t/array-shuffle-array-shuffle/146683>\
**Category:** Ruby\
**Created:** [August 24, 2008, 2:45am UTC](https://www.ruby-forum.com/t/array-shuffle-array-shuffle/146683 "2008-08-24T02:45:16Z")\
**Posts on this page:** 8\
**Page:** 1

<div class="post-metadata">

**Author:** ![sithadmin](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/s/858c86/32.png) [@sithadmin](https://www.ruby-forum.com/u/sithadmin)\
**Post date:** [August 24, 2008, 2:45am UTC](https://www.ruby-forum.com/t/array-shuffle-array-shuffle/146683/1 "2008-08-24T02:45:16Z")

</div>

This works but I can’t escape the nagging sense that there’s a more  
concise approach (for one thing, it looks like there are way too  
transient objects to me).

Anyone have a better idea?

class Array

def shuffle  
t\_self = self.dup  
t\_size = self.size  
result=[]  
t\_size.times { result \<\< t\_self.slice!(rand(t\_self.size)) }  
result  
end

def shuffle!  
t\_self = self.dup  
t\_size = self.size  
self.clear  
t\_size.times { self \<\< t\_self.slice!(rand(t\_self.size)) }  
self  
end

end

Regards…

---

<div class="post-metadata">

**Author:** ![sithadmin](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/s/858c86/32.png) [@sithadmin](https://www.ruby-forum.com/u/sithadmin)\
**Post date:** [August 24, 2008, 2:49am UTC](https://www.ruby-forum.com/t/array-shuffle-array-shuffle/146683/2 "2008-08-24T02:49:54Z")

</div>

Jeff M. wrote:

> This works but I can’t escape the nagging sense that there’s a more  
> concise approach (for one thing, it looks like there are way too  
> transient objects to me).
> 
> Anyone have a better idea?

ary2 = ary.sort\_by { rand }

---

<div class="post-metadata">

**Author:** ![sithadmin](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/s/858c86/32.png) [@sithadmin](https://www.ruby-forum.com/u/sithadmin)\
**Post date:** [August 24, 2008, 2:54am UTC](https://www.ruby-forum.com/t/array-shuffle-array-shuffle/146683/3 "2008-08-24T02:54:45Z")

</div>

Tim H. wrote:

> Jeff M. wrote:
> 
> > This works but I can’t escape the nagging sense that there’s a more  
> > concise approach (for one thing, it looks like there are way too  
> > transient objects to me).
> > 
> > Anyone have a better idea?
> 
> ary2 = ary.sort\_by { rand }

“Gone in 60 seconds”…

Thanks

---

<div class="post-metadata">

**Author:** ![sithadmin](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/s/858c86/32.png) [@sithadmin](https://www.ruby-forum.com/u/sithadmin)\
**Post date:** [August 24, 2008, 12:21pm UTC](https://www.ruby-forum.com/t/array-shuffle-array-shuffle/146683/4 "2008-08-24T12:21:19Z")

</div>

Jeff M. wrote:

> This works but I can’t escape the nagging sense that there’s a more  
> concise approach (for one thing, it looks like there are way too  
> transient objects to me).
> 
> Anyone have a better idea?
> 
> class Array
> 
> def shuffle  
> t\_self = self.dup  
> t\_size = self.size  
> result=[]  
> t\_size.times { result \<\< t\_self.slice!(rand(t\_self.size)) }  
> result  
> end
> 
> def shuffle!  
> t\_self = self.dup  
> t\_size = self.size  
> self.clear  
> t\_size.times { self \<\< t\_self.slice!(rand(t\_self.size)) }  
> self  
> end
> 
> end
> 
> Regards…

If you need a less predictable one than the sort\_by { rand } then I  
suggest this:

class Array

# Shuffle the array

def shuffle!  
n = length  
for i in 0…n  
r = Kernel.rand(n-i)+i  
self[r], self[i] = self[i], self[r]  
end  
self  
end

# Return a shuffled copy of the array

def shuffle  
dup.shuffle!  
end  
end

This shuffle is known as fisher-yates/knuth shuffle and is afaik by  
current means considered impossible to predict. Also its complexity is  
O(n) compared to the O(nlogn) of sort\_by (which for many cases probably  
still is faster in ruby since it runs mainly in C, I didn’t bench it,  
though).

As of 1.8.7 you have those methods already natively provided by ruby.

Regards  
Stefan (apeiros)

---

<div class="post-metadata">

**Author:** ![sithadmin](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/s/858c86/32.png) [@sithadmin](https://www.ruby-forum.com/u/sithadmin)\
**Post date:** [August 24, 2008, 8:11pm UTC](https://www.ruby-forum.com/t/array-shuffle-array-shuffle/146683/5 "2008-08-24T20:11:37Z")

</div>

On Sun Aug 24 19:17:11 2008, Stefan R. wrote:

> which for many cases probably still is faster in ruby since it runs  
> mainly in C, I didn’t bench it, though

Seems youâ€™re right:

Rehearsal -------------------------------------------------------  
Knuth: 10.900000 0.000000 10.900000 ( 10.902161)  
Sort by #{rand}: 11.050000 0.000000 11.050000 ( 11.060635)  
--------------------------------------------- total: 21.950000sec

```
                      user system total real

```

Knuth: 10.930000 0.020000 10.950000 ( 10.946718)  
Sort by #{rand}: 11.020000 0.000000 11.020000 ( 11.020902)

require ‘benchmark’

class Array

# Shuffle the array

def shuffle!  
n = length  
for i in 0…n  
r = Kernel.rand(n-i)+i  
self[r], self[i] = self[i], self[r]  
end  
self  
end

# Return a shuffled copy of the array

def shuffle  
dup.shuffle!  
end  
end

n = 500

a = (1…10000).map { rand }  
Benchmark.bmbm(20) do |x|  
x.report(“Knuth:”) { n.times { a.shuffle } }  
x.report(‘Sort by #{rand}:’) { n.times { a.sort\_by { rand } } }  
end

---

<div class="post-metadata">

**Author:** ![sithadmin](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/s/858c86/32.png) [@sithadmin](https://www.ruby-forum.com/u/sithadmin)\
**Post date:** [August 26, 2008, 3:42pm UTC](https://www.ruby-forum.com/t/array-shuffle-array-shuffle/146683/6 "2008-08-26T15:42:10Z")

</div>

> As of 1.8.7 you have those methods already natively provided by ruby.
> 
> Regards  
> Stefan (apeiros)

Ah! If only the Ubuntu/Debian promotion cycle for Ruby out paced  
continental drift…

Thanks again…

I appreciate it.

---

<div class="post-metadata">

**Author:** ![sithadmin](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/s/858c86/32.png) [@sithadmin](https://www.ruby-forum.com/u/sithadmin)\
**Post date:** [October 9, 2008, 9:16pm UTC](https://www.ruby-forum.com/t/array-shuffle-array-shuffle/146683/7 "2008-10-09T21:16:25Z")

</div>

No, ‘I’ is next in line. “Irresponsible Irmin”

Joel VanderWerf wrote:

> Jeff M. wrote:
> 
> > Ah! If only the Ubuntu/Debian promotion cycle for Ruby out paced  
> > continental drift…
> 
> I heard the 9.04 release will be called Galloping Gondwanaland.

---

<div class="post-metadata">

**Author:** ![sithadmin](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/s/858c86/32.png) [@sithadmin](https://www.ruby-forum.com/u/sithadmin)\
**Post date:** [August 26, 2008, 8:25pm UTC](https://www.ruby-forum.com/t/array-shuffle-array-shuffle/146683/8 "2008-08-26T20:25:46Z")

</div>

Jeff M. wrote:

> Ah! If only the Ubuntu/Debian promotion cycle for Ruby out paced  
> continental drift…

I heard the 9.04 release will be called Galloping Gondwanaland.
