Skip to content
Permalink
Browse files

Merge pull request #552 from kostya/minmax2

Enumerable, Array#minmax
  • Loading branch information
alex committed Apr 1, 2013
2 parents 922a3a0 + 43e6447 commit 2fdb0f4b2ad43ca9105fd99101f4424ad86e722d
@@ -257,14 +257,6 @@ def map!(&block)

alias :collect! :map!

def max(&block)
max = self[0]
self.each do |e|
max = e if (block ? block.call(max, e) : max <=> e) < 0
end
max
end

def uniq!(&block)
raise RuntimeError.new("can't modify frozen #{self.class}") if frozen?
seen = {}
@@ -156,24 +156,60 @@ def reject(&block)
result
end

def min
inject do |minimum, current|
if minimum > current
current
else
minimum
end
def max(&block)
max = nil
self.each_with_index do |e, i|
max = e if i == 0 || Topaz.compare(e, max, &block) > 0
end
max
end

def max
inject do |maximum, current|
if maximum < current
current
else
maximum
end
def min(&block)
min = nil
self.each_with_index do |e, i|
min = e if i == 0 || Topaz.compare(e, min, &block) < 0
end
min
end

def max_by(&block)
return self.enum_for(:max_by) unless block
max = maxv = nil
self.each_with_index do |e, i|
ev = yield(e)
max, maxv = e, ev if i == 0 || Topaz.compare(ev, maxv) > 0
end
max
end

def min_by(&block)
return self.enum_for(:min_by) unless block
min = minv = nil
self.each_with_index do |e, i|
ev = yield(e)
min, minv = e, ev if i == 0 || Topaz.compare(ev, minv) < 0
end
min
end

def minmax(&block)
min = max = nil
self.each_with_index do |e, i|
min = e if i == 0 || Topaz.compare(e, min, &block) < 0
max = e if i == 0 || Topaz.compare(e, max, &block) > 0
end
[min, max]
end

def minmax_by(&block)
return self.enum_for(:minmax_by) unless block
min = max = minv = maxv = nil
self.each_with_index do |e, i|
ev = yield(e)
max, maxv = e, ev if i == 0 || Topaz.compare(ev, maxv) > 0
min, minv = e, ev if i == 0 || Topaz.compare(ev, minv) < 0
end
[min, max]
end

def partition(&block)
@@ -1,7 +1 @@
fails:Enumerable#max_by returns an enumerator if no block
fails:Enumerable#max_by returns nil if #each yields no objects
fails:Enumerable#max_by returns the object for whom the value returned by block is the largest
fails:Enumerable#max_by returns the object that appears first in #each in case of a tie
fails:Enumerable#max_by uses max.<=>(current) to determine order
fails:Enumerable#max_by is able to return the maximum for enums that contain nils
fails:Enumerable#max_by gathers whole arrays as elements when each yields multiple
@@ -1,4 +1 @@
fails:Enumerable#max raises an ArgumentError for incomparable elements
fails:Enumerable#max return the maximum element (with block
fails:Enumerable#max returns the minimum for enumerables that contain nils
fails:Enumerable#max gathers whole arrays as elements when each yields multiple
@@ -1,7 +1 @@
fails:Enumerable#min_by returns an enumerator if no block
fails:Enumerable#min_by returns nil if #each yields no objects
fails:Enumerable#min_by returns the object for whom the value returned by block is the largest
fails:Enumerable#min_by returns the object that appears first in #each in case of a tie
fails:Enumerable#min_by uses min.<=>(current) to determine order
fails:Enumerable#min_by is able to return the maximum for enums that contain nils
fails:Enumerable#min_by gathers whole arrays as elements when each yields multiple
@@ -1,4 +1 @@
fails:Enumerable#min raises an ArgumentError for incomparable elements
fails:Enumerable#min return the minimun when using a block rule
fails:Enumerable#min returns the minimum for enumerables that contain nils
fails:Enumerable#min gathers whole arrays as elements when each yields multiple
@@ -1,7 +1 @@
fails:Enumerable#minmax_by returns an enumerator if no block
fails:Enumerable#minmax_by returns nil if #each yields no objects
fails:Enumerable#minmax_by returns the object for whom the value returned by block is the largest
fails:Enumerable#minmax_by returns the object that appears first in #each in case of a tie
fails:Enumerable#minmax_by uses min/max.<=>(current) to determine order
fails:Enumerable#minmax_by is able to return the maximum for enums that contain nils
fails:Enumerable#minmax_by gathers whole arrays as elements when each yields multiple
@@ -1,5 +1 @@
fails:Enumerable#minmax min should return the minimum element
fails:Enumerable#minmax returns [nil, nil] for an empty Enumerable
fails:Enumerable#minmax raises an ArgumentError when elements are incomparable
fails:Enumerable#minmax return the minimun when using a block rule
fails:Enumerable#minmax gathers whole arrays as elements when each yields multiple
@@ -22,3 +22,8 @@ def method_coerce_int(self, space, w_obj, w_type, method):
if not isinstance(w_type, W_ClassObject):
raise space.error(space.w_TypeError, "type argument must be a class")
return space.convert_type(w_obj, w_type, method)

@moduledef.function("compare")
def method_compare(self, space, w_a, w_b, block=None):
return space.compare(w_a, w_b, block)

@@ -8,28 +8,15 @@
from topaz.objects.objectobject import W_Object
from topaz.utils.packing.pack import RPacker


class RubySorter(TimSort):
def __init__(self, space, list, listlength=None, sortblock=None):
TimSort.__init__(self, list, listlength=listlength)
self.space = space
self.sortblock = sortblock

def lt(self, a, b):
if self.sortblock is None:
w_cmp_res = self.space.send(a, self.space.newsymbol("<=>"), [b])
else:
w_cmp_res = self.space.invoke_block(self.sortblock, [a, b])
if w_cmp_res is self.space.w_nil:
raise self.space.error(
self.space.w_ArgumentError,
"comparison of %s with %s failed" %
(self.space.obj_to_s(self.space.getclass(a)),
self.space.obj_to_s(self.space.getclass(b)))
)
else:
return self.space.int_w(w_cmp_res) < 0

cmp_res = self.space.compare(a, b, self.sortblock)
return self.space.int_w(cmp_res) < 0

class W_ArrayObject(W_Object):
classdef = ClassDef("Array", W_Object.classdef, filepath=__file__)
@@ -76,13 +76,6 @@ def method_method_missing(self, space, w_name, args_w):
def method_eq(self, space, w_other):
return space.newbool(self is w_other)

@classdef.method("<=>")
def method_cmp(self, space, w_other):
if w_other is self:
return space.newint(0)
else:
return space.w_nil

@classdef.method("!")
def method_not(self, space):
return space.newbool(not space.is_true(self))
@@ -149,6 +142,13 @@ def method_inspect(self, space):
def method_to_s(self, space):
return space.newstr_fromstr(space.any_to_s(self))

@classdef.method("<=>")
def method_cmp(self, space, w_other):
if w_other is self:
return space.newint(0)
else:
return space.w_nil

@classdef.method("===")
def method_eqeqeq(self, space, w_other):
return space.send(self, space.newsymbol("=="), [w_other])
@@ -706,3 +706,18 @@ def any_to_s(self, w_obj):

def obj_to_s(self, w_obj):
return self.str_w(self.send(w_obj, self.newsymbol("to_s")))

def compare(self, w_a, w_b, block=None):
if block is None:
w_cmp_res = self.send(w_a, self.newsymbol("<=>"), [w_b])
else:
w_cmp_res = self.invoke_block(block, [w_a, w_b])
if w_cmp_res is self.w_nil:
raise self.error(
self.w_ArgumentError,
"comparison of %s with %s failed" %
(self.obj_to_s(self.getclass(w_a)),
self.obj_to_s(self.getclass(w_b)))
)
else:
return w_cmp_res

0 comments on commit 2fdb0f4

Please sign in to comment.
You can’t perform that action at this time.