How to randomly sort (scramble) an array in Ruby? - ruby

I'd like to have my array items scrambled.
Something like this:
[1,2,3,4].scramble => [2,1,3,4]
[1,2,3,4].scramble => [3,1,2,4]
[1,2,3,4].scramble => [4,2,3,1]
and so on, randomly

Built in now:
[1,2,3,4].shuffle => [2, 1, 3, 4]
[1,2,3,4].shuffle => [1, 3, 2, 4]

For ruby 1.8.6 (which does not have shuffle built in):
array.sort_by { rand }

For ruby 1.8.6 as sepp2k's example, but you still want use "shuffle" method.
class Array
def shuffle
sort_by { rand }
end
end
[1,2,3,4].shuffle #=> [2,4,3,1]
[1,2,3,4].shuffle #=> [4,2,1,3]
cheers

Code from the Backports Gem for just the Array for Ruby 1.8.6. Ruby 1.8.7 or higher is built in.
class Array
# Standard in Ruby 1.8.7+. See official documentation[http://ruby-doc.org/core-1.9/classes/Array.html]
def shuffle
dup.shuffle!
end unless method_defined? :shuffle
# Standard in Ruby 1.8.7+. See official documentation[http://ruby-doc.org/core-1.9/classes/Array.html]
def shuffle!
size.times do |i|
r = i + Kernel.rand(size - i)
self[i], self[r] = self[r], self[i]
end
self
end unless method_defined? :shuffle!
end

The Ruby Facets library of extensions has a Random module which provides useful methods including shuffle and shuffle! to a bunch of core classes including Array, Hash and String.
Just be careful if you're using Rails as I experienced some nasty clashes in the way its monkeypatching clashed with Rails'...

Related

Ruby 1.8.7 Array of symbols raising TypeError: Symbol as array index

I recently created a pull request for a gem which is building on travis against quite old ruby versions for backward compatibility.
In my commit I wanted to introduce a whitelist on some method options passed as an hash parameter.
In Rails with a recent ruby version it would look like:
MY_WHITELIST = %i(a b c)
def my_method(options={})
#options = options.slice(*MY_WHITELIST)
end
In order to grant backward compatibility in a standalone gem, I provided a solution like:
MY_WHITELIST = [:a, :b, :c]
def my_method(options={})
#options = options.select { |k, _| MY_WHITELIST.include?(k) }
end
This pass for ruby 1.9.3 but raise the following exception for 1.8.7:
TypeError: Symbol as array index
According to the documentation, this way to initialise an array should be accepted.
Have you ever experienced with use? What would you suggest?
As suggested in a comment by #mr_sudaca, the solution was to make the selection on an array:
Hash[options.to_a.select { |k, _| MY_WHITELIST.include?(k) }]

Ruby - Using syntactic sugar bracket method to return a value in 2-D array

A basic example of what is confusing me:
def [](row, col)
self[row][col]
end
x = [[1,3], [4,5]]
x[0][0] #normal
x[0, 0] #syntactic sugar?
I have been told that these are equivalent statements, but when I run the sugar one, I get a different answer. How am I supposed to write it in syntactic sugar?
You need to put your def [](row, col) method in a class that contains your data. So something like:
$ irb
2.3.0 :001 > class MyData
2.3.0 :002?> attr_accessor :my_array
2.3.0 :003?> def [](row, col)
2.3.0 :004?> my_array[row][col]
2.3.0 :005?> end
2.3.0 :006?> end
=> :[]
2.3.0 :007 > x = MyData.new
=> #<MyData:0x007f96dc8024b8>
2.3.0 :008 > x.my_array = [[1, 3], [4, 5]]
=> [[1, 3], [4, 5]]
2.3.0 :009 > x[1,1]
=> 5
2.3.0 :010 >
There are two problems with this:
You are adding your method to the Object class. But Array has its own [] which overrides the one in Object, so your method never gets called …
… which is a good thing, because it doesn't work anyway: all the method does is call itself, that would lead to a stackoverflow because of runaway recursion, but thankfully, the method calls itself with one argument, but is defined to take two parameters, and thus all you get is an ArgumentError.
Now, forgetting for a moment that monkey patching a core class is a terrible idea, you could to this:
module TwoDArrayExtension
def [](x, y)
super(x).method(__callee__).super_method.(y)
end
end
class Array
prepend TwoDArrayExtension
end
x = [[1, 3], [4, 5]]
x[0][0] #normal
# in `[]': wrong number of arguments (given 1, expected 2) (ArgumentError)
# Hey, we just re-defined [] to take two arguments, so obviously this cannot work!
x[0, 0] #syntactic sugar?
#=> 1
This "works" in the sense that it gets your syntactic sugar example to pass. But your "normal" example now breaks: you have re-defined how arrays work, so you can no longer use it like an array. Tinkering with core classes like this has serious ramifications. For example:
Irb is written in Ruby, and uses arrays internally, among other things. You cannot test your code in Irb, because it will just crash.
The same applies to Pry.
The same applies to any and all existing code that uses arrays … which is pretty much all Ruby code ever written. You cannot use any gems. You cannot use and standard libraries.
In fact, in an implementation like Rubinius, where pretty much everything, including large parts of the core libraries themselves, and even the compiler are written in Ruby and thus use arrays internally, you probably won't even be able to get your code to run at all.
In short: yes, you can do this, but you really, really, really, REALLY don't want to.

Array#uniq with block equivalent in Ruby 1.8.7

Array#uniq has this behaviour in Ruby 1.9
c = [ "a:def", "a:xyz", "b:abc", "b:xyz", "c:jkl" ]
c.uniq {|s| s[/^\w+/]} #=> [ "a:def", "b:abc", "c:jkl" ]
It can take a block and give unique value with respect to what we give. But, this wont work in Ruby 1.8. How can I create this functionality in ruby 1.8?
Install Marc-André LaFortune's backports gem:
https://github.com/marcandre/backports
That has the block versions of 1.9.2's Array#uniq and Array#uniq!. Or if you don't want or need the whole thing, the parts are pretty well isolated so you can pull out just the pieces you need:
https://github.com/marcandre/backports/blob/master/lib/backports/1.9.2/array.rb#L99
It's easy to implement something like:
class Array
def uniq
ret, keys = [], []
each do |x|
key = block_given? ? yield(x) : x
unless keys.include? key
ret << x
keys << key
end
end
ret
end
end

use the correct number of arguments for new in Ruby

I am working on a gem that can uses different version of Gherkin, but I'm facing a problem:
in the 2.4.0 version Gherkin::Formatter::Model::Scenario.new takes 6 arguments but in 2.6.5 it takes 7 arguments.
So my question is what is a best practice in this case ? Should I do:
case Gherkin::Version
when '2.4.0'
do the init with 6 arguments
else
with the 7
end
I was thinking also of creating a new_with_arity method:
class Object
def new_with_arity(*params)
puts method(:initialize).arity # => -1
puts method(:new).arity # => -1
new(*(params + [nil] * (params.count - method(:new).arity)))
end
end
However this does not work, the arity of new and initialize is -1.
Do you have an idea ?
I would recommend following Jim Deville's advice. Saying that it's quite an interesting idea and you were pretty close. The problem is you can't get the method without having an instance, so the trick is to use allocate first.
class Object
def new_with_arity(*params)
new *(params + [nil] * (allocate.method(:initialize).arity - params.size))
end
end
class One
def initialize a
[a]
end
end
class Two
def initialize a, b
[a, b]
end
end
One.new_with_arity 1 #=> [1]
Two.new_with_arity 1, 2 #=> [1, 2]
Two.new_with_arity 1 #=> [1, nil]
I would build 2 Gherkin adapters and load up the proper one for the proper version. Or, you are using Rubygems, so you can force a specific version of the Gherkin parser

First order array difference in Ruby

What's the slickest, most Ruby-like way to do this?
[1, 3, 10, 5].diff
should produce
[2, 7, -5]
that is, an array of first order differences. I've come up with a solution which I'll add below, but it requires ruby 1.9 and isn't all that slick. what else is possible?
I like this functional style:
module Enumerable
def diff
each_cons(2).map {|pair| pair.reverse.reduce :-}
end
end
EDIT: I just realized that the reverse is totally unnecessary. If this were a functional language, I would have used pattern matching, but Ruby doesn't support pattern matching. It does, however, support destructuring bind, which is a good enough approximation for pattern matching in this case.
each_cons(2).map {|first, second| second - first}
No smiley, though.
I like how this sounds if you just read it out loud from left to right: "For each pair, apply the difference between the first and second elements of the pair." In fact, I normally don't like the name collect and prefer map instead, but in this case that reads even better:
each_cons(2).collect {|first, second| second - first}
"For each pair, collect the difference between its elements." Sounds almost like a definition of first order difference.
Yet another way..Seems the shortest so far:)
module Enumerable
def diff
self[1..-1].zip(self).map {|x| x[0]-x[1]}
end
end
The concept comes from functional programming, of course:
module Enumerable
def diff
self.inject([0]) { |r,x| r[-1] += x; r << -x } [1..-2]
end
end
[1,3,10,5].diff
Note that you don't need any separate intermediate variables here
Here's the fastest way I could find (faster than all the others suggested here as of this moment, in both 1.8 and 1.9):
module Enumerable
def diff
last=nil
map do |x|
r = last ? x - last : nil
last = x
r
end.compact
end
end
With this close runner-up:
module Enumerable
def diff
r = []
1.upto(size-1) {|i| r << self[i]-self[i-1]}
r
end
end
Of the others here, testr's self-described "feeble" attempt is the next fastest, but it's still slower than either of these.
And if speed is no object, here's my aesthetic favorite:
module Enumerable
def diff!
[-shift+first] + diff! rescue []
end
def diff
dup.diff!
end
end
But this is (for reasons I don't entirely understand) an order of magnitude slower than any other suggestion here!
Minor variation on Jörg W Mittag's:
module Enumerable
def diff
each_cons(2).map{|a,b| b-a}
end
end
# Attempt, requires ruby 1.9.
module Enumerable
def diff
each_cons(2).with_object([]){|x,array| array << x[1] - x[0]}
end
end
Example:
[1,3,10,5].diff
=> [2, 7, -5]
Another way to do it.
module Enumerable
def diff
result = []
each_with_index{ |x, i|
return result if (i == (self.length-1))
result << self[i+1] - x
}
end
end
My feeble attempt...
module Enumerable
def diff
na = []
self.each_index { |x| r << self[x]-self[x-1] if x > 0 }
na
end
end
p [1,3,10,5].diff #returned [2, 7, -5]

Resources