Skip to content

Commit

Permalink
1.8.7: Had forgotten Array#permutation
Browse files Browse the repository at this point in the history
Also cleanup of Array#product
  • Loading branch information
marcandre committed Jan 20, 2010
1 parent 0e0534a commit ce255d3
Show file tree
Hide file tree
Showing 3 changed files with 49 additions and 19 deletions.
4 changes: 2 additions & 2 deletions VERSION.yml
@@ -1,5 +1,5 @@
---
:patch: 3
:major: 1
:minor: 13
:patch: 0
:build:
:minor: 12
4 changes: 2 additions & 2 deletions backports.gemspec
Expand Up @@ -5,11 +5,11 @@

Gem::Specification.new do |s|
s.name = %q{backports}
s.version = "1.12.3"
s.version = "1.13.0"

s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
s.authors = ["Marc-Andr\303\251 Lafortune"]
s.date = %q{2009-12-28}
s.date = %q{2010-01-20}
s.description = %q{ Essential backports that enable some of the really nice features of ruby 1.8.7, ruby 1.9 and rails from ruby 1.8.6 and earlier.
}
s.email = %q{github@marc-andre.ca}
Expand Down
60 changes: 45 additions & 15 deletions lib/backports/1.8.7/array.rb
Expand Up @@ -90,6 +90,31 @@ def index_with_block(*arg)
alias_method :find_index, :index
end

# Standard in Ruby 1.8.7+. See official documentation[http://ruby-doc.org/core-1.9/classes/Array.html]
def permutation(num = Backports::Undefined, &block)
return to_enum(:permutation, num) unless block_given?
num = num.equal?(Backports::Undefined) ?
size :
Backports.coerce_to(num, Fixnum, :to_int)
return self unless (0..size).include? num

final_lambda = lambda do |partial, remain|
yield partial
end

outer_lambda = num.times.inject(final_lambda) do |proc, ignore|
lambda do |partial, remain|
remain.each_with_index do |val, i|
new_remain = remain.dup
new_remain.delete_at(i)
proc.call(partial.dup << val, new_remain)
end
end
end

outer_lambda.call([], self)
end unless method_defined? :permutation

# pop. Standard in Ruby 1.8.7+. See official documentation[http://ruby-doc.org/core-1.9/classes/Array.html]
unless ([1].pop(1) rescue false)
def pop_with_optional_argument(n = Backports::Undefined)
Expand All @@ -105,22 +130,27 @@ def pop_with_optional_argument(n = Backports::Undefined)

# Standard in Ruby 1.8.7+. See official documentation[http://ruby-doc.org/core-1.9/classes/Array.html]
def product(*arg)
# Implementation notes: We build an enumerator for all the combinations
# by building it up successively using "inject" and starting from a trivial enumerator.
# It would be easy to have "product" yield to a block but the standard
# simply returns an array, so you'll find a simple call to "to_a" at the end.
# Implementation notes: We build a block that will generate all the combinations
# by building it up successively using "inject" and starting with one
# responsible to append the values.
#
trivial_enum = Enumerator.new(Backports::Yielder.new{|yielder| yielder.yield [] }) # Enumerator.new{...} is 1.9+ only
[self, *arg].map{|x| Backports.coerce_to(x, Array, :to_ary)}.
inject(trivial_enum) do |enum, array|
Enumerator.new(Backports::Yielder.new do |yielder| # Enumerator.new{...} is 1.9+ only
enum.each do |partial_product|
array.each do |obj|
yielder.yield partial_product + [obj]
end
end
end)
end.to_a
result = []

arg.map!{|x| Type.coerce_to(x, Array, :to_ary)}
arg.reverse! # to get the results in the same order as in MRI, vary the last argument first
arg.push self

outer_lambda = arg.inject(result.method(:push)) do |proc, values|
lambda do |partial|
values.each do |val|
proc.call(partial.dup << val)
end
end
end

outer_lambda.call([])

result
end unless method_defined? :product

# rindex. Standard in Ruby 1.8.7+. See official documentation[http://ruby-doc.org/core-1.9/classes/Array.html]
Expand Down

0 comments on commit ce255d3

Please sign in to comment.