# Chaining comparisons

**URL:** <https://rubytalk.org/t/chaining-comparisons/6926>\
**Category:** ruby-talk\
**Created:** [19 July 2003 05:58 UTC](https://rubytalk.org/t/chaining-comparisons/6926 "2003-07-19T05:58:51Z")\
**Posts on this page:** 16\
**Page:** 2

<div class="post-metadata">

**Author:** ![Pit](https://avatars.discourse-cdn.com/v4/letter/p/f14d63/32.png) [@Pit](https://rubytalk.org/u/Pit)\
**Post date:** [19 July 2003 14:23 UTC](https://rubytalk.org/t/chaining-comparisons/6926/21 "2003-07-19T14:23:04Z")

</div>

I’m not Dave Thomas 🙂 but you can also use inject here:

module Enumerable  
def ordered?  
inject { | last, item | return false unless last \< item; item }  
true  
end  
end

Regards,  
Pit

> **···**
>
> On 19 Jul 2003 at 17:41, Brian Candler wrote:
> 
> > Both versions generate a temporary copy of the array, e.g. self[1…-1] does  
> > that too. But you can avoid it:
> > 
> > module Enumerable  
> > def ordered?  
> > first = true  
> > prev = nil  
> > each do |item|  
> > if first  
> > first = false  
> > else  
> > return false if prev \> item  
> > end  
> > prev = item  
> > end  
> > return true  
> > end  
> > end

---

<div class="post-metadata">

**Author:** ![Austin\_Ziegler2](https://avatars.discourse-cdn.com/v4/letter/a/ad7895/32.png) [@Austin\_Ziegler2](https://rubytalk.org/u/Austin_Ziegler2)\
**Post date:** [19 July 2003 16:13 UTC](https://rubytalk.org/t/chaining-comparisons/6926/22 "2003-07-19T16:13:00Z")

</div>

Expression-oriented languages return values from the expressions.  
Statement-oriented languages don’t. Perl and Ruby are expression-  
oriented; C and Pascal are not.

```
# Ruby

```

def foo  
“Foo”  
end  
puts foo

```
# Perl

```

sub foo {  
“Foo”  
}  
print &foo;

```
/* C */

```

char \*foo() {  
return “Foo”;  
}  
printf(“%s\n”, foo());

```
{ Pascal }

```

Function foo: Return String;  
Begin  
Return “Foo”;  
End;  
WriteLn(Foo());

The C and the Pascal require explicit return statements to work. The  
Perl and Ruby do not.

-austin

> **···**
>
> On Sat, 19 Jul 2003 15:51:42 +0900, Daniel Carrera wrote:
> 
> > On Sat, Jul 19, 2003 at 03:47:38PM +0900, Gavin Sinclair wrote:
> > 
> > > Ruby is a very expression-oriented language, and derives its  
> > > strength from conceptual purity. If an expression evaluated to X  
> > > in some circumstances and Y in others, a small part of Ruby would  
> > > be lost.  
> > > I realize that this is a dumb question, but what is an  
> > > expression-oriented language?
> 
> > Can you contrast Ruby with a language that is not  
> > expression-oriented?
> 
> –  
> austin ziegler \* austin@halostatue.ca \* Toronto, ON, Canada  
> software designer \* pragmatic programmer \* 2003.07.19  
> \* 12:06:45

---

<div class="post-metadata">

**Author:** ![Mauricio\_Fernndez](https://avatars.discourse-cdn.com/v4/letter/m/e495f1/32.png) [@Mauricio\_Fernndez](https://rubytalk.org/u/Mauricio_Fernndez)\
**Post date:** [20 July 2003 06:04 UTC](https://rubytalk.org/t/chaining-comparisons/6926/23 "2003-07-20T06:04:55Z")

</div>

It’s hard to achieve thread-safety that way.

> **···**
>
> On Sun, Jul 20, 2003 at 02:22:37PM +0900, Joel VanderWerf wrote:
> 
> > As you say, there is only one true; but you still can save state in it:
> > 
> > irb(main):001:0\> true.instance\_eval {@x = 1}  
> > 1  
> > irb(main):002:0\> true.instance\_eval {@x}  
> > 1
> 
> –  
> \_ \_
> 
> > > \_\_ \_\_ _| |_ \_\_\_ \_ \_\_ \_\_\_ \_\_ \_ \_ \_\_  
> > > '\_ \ / _`| __/__ | '_` \_ \ / ` | ’ \   
> > > ) | (| | |_\_\_ \ | | | | | (_| | | | |  
> > > .\_\_/ \_,_|\ __|__ /| |_| |_|\__,_|_| |\_|  
> > > Running Debian GNU/Linux Sid (unstable)  
> > > batsman dot geo at yahoo dot com
> 
> - DDD no longer requires the librx library. Consequently, librx  
> errors can no more cause DDD to crash.  
> – DDD

---

<div class="post-metadata">

**Author:** ![Jason\_Creighton3](https://avatars.discourse-cdn.com/v4/letter/j/e19adc/32.png) [@Jason\_Creighton3](https://rubytalk.org/u/Jason_Creighton3)\
**Post date:** [20 July 2003 23:17 UTC](https://rubytalk.org/t/chaining-comparisons/6926/24 "2003-07-20T23:17:48Z")

</div>

> Jason Creighton wrote:
> 
> > > When I learned python I was overjoyed that I could evaluate 1 \< 2 \< 3  
> > > and get “true”. I just realized that you can’t do that in Ruby. Is  
> > > there a reason why? Is it good? I know I can use “between”, but  
> > > still…
> > 
> > [http://www.rubygarden.org/article.php?sid=286](http://www.rubygarden.org/article.php?sid=286)
> > 
> > So basically, it’s because it’s hard to implement, even more so because  
> > true/false/nil are singleton objects. (So you can’t, for instance, save state  
> > in a particular instance of ‘true’, because there’s only one.)
> 
> As you say, there is only one true; but you still can save state in it:
> 
> irb(main):001:0\> true.instance\_eval {@x = 1}  
> 1  
> irb(main):002:0\> true.instance\_eval {@x}  
> 1
> 
> Not that it’s relevant to the 1 \< 2 \< 3 discussion, but it’s kinda cute…

Yeah, it is kinda cute. How does that work? It works for Fixnum objects,  
too…

> > (0…16).each { |n| n.instance\_eval { @square = n\*n } }  
> > =\> 0…16  
> > 5.instance\_eval { @square }  
> > =\> 25

How can that work when Fixnum is stored in VALUE? And that’s another thing:  
VALUE is either an immediate value (Fixnum/true/false/nil) or a pointer to an  
object. Doesn’t that mean there’s only 31 bits (on 32 bit machins) available  
for the pionter? How can that work? I always thought that pointers would have  
to be able to cover the whole address space…

Jason Creighton

> **···**
>
> On Sun, 20 Jul 2003 14:22:37 +0900 Joel VanderWerf [vjoel@PATH.Berkeley.EDU](mailto:vjoel@PATH.Berkeley.EDU) wrote:
> 
> > > On Sat, 19 Jul 2003 14:58:51 +0900 \> \> “Kurt M. Dresner” [kdresner@cs.utexas.edu](mailto:kdresner@cs.utexas.edu) wrote:

---

<div class="post-metadata">

**Author:** ![Brian\_Candler](https://avatars.discourse-cdn.com/v4/letter/b/5f9b8f/32.png) [@Brian\_Candler](https://rubytalk.org/u/Brian_Candler)\
**Post date:** [19 July 2003 15:10 UTC](https://rubytalk.org/t/chaining-comparisons/6926/25 "2003-07-19T15:10:25Z")

</div>

Which implementation of ‘inject’ are you using? The one in PragProg requires  
an initial value to be passed as a parameter.

With an array of N elements you either need to do N-1 comparisons, or you  
need to start with a sentinel value which is guaranteed to be less than all  
other elements (nil and 0 both aren’t suitable). So I don’t see how the  
above works, but without its partner ‘inject’ implementation I can’t comment  
further.

Regards,

Brian.

> **···**
>
> On Sat, Jul 19, 2003 at 11:23:04PM +0900, Pit Capitain wrote:
> 
> > I’m not Dave Thomas 🙂 but you can also use inject here:
> > 
> > module Enumerable  
> > def ordered?  
> > inject { | last, item | return false unless last \< item; item }  
> > true  
> > end  
> > end

---

<div class="post-metadata">

**Author:** ![Mark\_J\_Reed](https://avatars.discourse-cdn.com/v4/letter/m/f6c823/32.png) [@Mark\_J\_Reed](https://rubytalk.org/u/Mark_J_Reed)\
**Post date:** [19 July 2003 18:11 UTC](https://rubytalk.org/t/chaining-comparisons/6926/26 "2003-07-19T18:11:10Z")

</div>

I think that’s a misleading characterization, especially if it lumps  
C and Pascal together. They’re similar languages, but they have  
some important differences, and while I would agree that Pascal is  
not expression-oriented, I would say that C is. The fact that a  
function call requires an explicit return is somewhat irrelevant to  
the larger point that single statements in C, including assignments,  
have values, whereas in Pascal no statements have values.

C is not as thoroughly expression-oriented as Perl and Ruby,  
to be sure. Compound statements don’t have a return value  
(which is why the ?:: operator exists; you can’t do  
{x = if (a) b; else (c);}), and you can declare void functions which  
are likewise valueless (although this was a later addition to the language).

Chained comparisons don’t work in Perl5, either, though they may work  
in Perl6. But then Perl is not known to eschew features just because they  
may be more complicated to compile; on the language scale of  
“regular”, “context-free”, “context-sensitive”, Perl may be described  
as “context-downright-touchy”.

-Mark

> **···**
>
> On Sun, Jul 20, 2003 at 01:13:00AM +0900, Austin Ziegler wrote:
> 
> > Expression-oriented languages return values from the expressions.  
> > Statement-oriented languages don’t. Perl and Ruby are expression-  
> > oriented; C and Pascal are not.

---

<div class="post-metadata">

**Author:** ![Joel\_VanderWerf1](https://avatars.discourse-cdn.com/v4/letter/j/94ad74/32.png) [@Joel\_VanderWerf1](https://rubytalk.org/u/Joel_VanderWerf1)\
**Post date:** [20 July 2003 06:11 UTC](https://rubytalk.org/t/chaining-comparisons/6926/27 "2003-07-20T06:11:26Z")

</div>

Mauricio Fernández wrote:

> **···**
>
> > On Sun, Jul 20, 2003 at 02:22:37PM +0900, Joel VanderWerf wrote:
> > 
> > > As you say, there is only one true; but you still can save state in it:
> > > 
> > > irb(main):001:0\> true.instance\_eval {@x = 1}  
> > > 1  
> > > irb(main):002:0\> true.instance\_eval {@x}  
> > > 1
> > 
> > It’s hard to achieve thread-safety that way.
> 
> No worse than a global var, anyway. It wasn’t a serious suggestion, just  
> a statement of surprise that it was even possible to set attributes of  
> literals. You can do it for Fixums, too. (From reading the source, I  
> seem to remember that it’s not done by storing anything within the  
> object, which is impossible with a Fixnum, but by a big hash mapping  
> objects and instance var names to values.)

---

<div class="post-metadata">

**Author:** ![Joel\_VanderWerf1](https://avatars.discourse-cdn.com/v4/letter/j/94ad74/32.png) [@Joel\_VanderWerf1](https://rubytalk.org/u/Joel_VanderWerf1)\
**Post date:** [20 July 2003 23:47 UTC](https://rubytalk.org/t/chaining-comparisons/6926/28 "2003-07-20T23:47:46Z")

</div>

Jason Creighton wrote:

> How can that work when Fixnum is stored in VALUE? And that’s another thing:  
> VALUE is either an immediate value (Fixnum/true/false/nil) or a pointer to an  
> object. Doesn’t that mean there’s only 31 bits (on 32 bit machins) available  
> for the pionter? How can that work? I always thought that pointers would have  
> to be able to cover the whole address space…

You don’t need the low-order bit if all allocations are on even  
addresses (some archtectures even force this).

---

<div class="post-metadata">

**Author:** ![ts1](https://avatars.discourse-cdn.com/v4/letter/t/a8b319/32.png) [@ts1](https://rubytalk.org/u/ts1)\
**Post date:** [21 July 2003 09:06 UTC](https://rubytalk.org/t/chaining-comparisons/6926/29 "2003-07-21T09:06:16Z")

</div>

> How can that work when Fixnum is stored in VALUE? And that's another thing:  
> VALUE is either an immediate value (Fixnum/true/false/nil) or a pointer to an  
> object. Doesn't that mean there's only 31 bits (on 32 bit machins) available  
> for the pionter?

You have effectively only 31 bits available for an ID, but not for the  
reason that you think. This will give you the maximum number of ID that  
you can have in a script.

On a 32 bits machins, you can have only (2\*\*20 - 1) ID for a script, if  
I'm right

Guy Decoux

---

<div class="post-metadata">

**Author:** ![Robert](https://avatars.discourse-cdn.com/v4/letter/r/e95f7d/32.png) [@Robert](https://rubytalk.org/u/Robert)\
**Post date:** [21 July 2003 12:21 UTC](https://rubytalk.org/t/chaining-comparisons/6926/30 "2003-07-21T12:21:20Z")

</div>

An alternative

def less(\*args); compare\_chain(proc{|a,b|a\<b}, \*args); end  
def greater(\*args); compare\_chain(proc{|a,b|a\>b}, \*args); end

def compare\_chain(comp, \*args)  
last = nil

args.each do |i|  
return false if last and not comp.call(last,i)  
last = i  
end

true  
end

less 1,10,22  
less 2,1,14  
less -2,1,14  
greater 10,3,-100  
greater 2,1,14

```
robert

```

“Simon Strandgaard” [0bz63fz3m1qt3001@sneakemail.com](mailto:0bz63fz3m1qt3001@sneakemail.com) schrieb im  
Newsbeitrag [news:pan.2003.07.19.09.12.52.551696@sneakemail.com](mailto:news:pan.2003.07.19.09.12.52.551696@sneakemail.com)…

> > > You can do this:
> > > 
> > > if [1, 2, 3].ordered?  
> > > puts “ok”  
> > > end
> > > 
> > > It will require that you extend the Array class yourself, like this:
> > > 
> > > > expand -t4 b.rb  
> > > > class Array  
> > > > def ordered?  
> > > > self == sort  
> > > > end  
> > > > end
> > 
> > (I’m a lazy typist 🙂
> 
> Work smarter, Not harder.  
> I know sort, But this solution didn’t come to mind.
> 
> > Both versions generate a temporary copy of the array, e.g. self[1…-1]  
> > does  
> > that too. But you can avoid it:
> 
> Yes. Avoiding temporary copy were my goal when I started writing it.  
> As you can see I apparently forgot it in the hurry 🙂
> 
> [snip enum#ordered?]
> 
> > You can then check whether all the lines in a file are ordered, for  
> > example,

> **···**
>
> > On Sat, 19 Jul 2003 18:41:33 +0900, Brian Candler wrote:
> > 
> > > On Sat, Jul 19, 2003 at 05:08:03PM +0900, Simon Strandgaard wrote:  
> > > without reading it into memory. (I am a big fan of Enumerable 🙂
> > 
> > Enum is Nice.
> > 
> > Some more thoughts on #ordered?
> > 
> > Supplying an operator, could be useful?
> > 
> > [3, 2, 1].ordered? :\> #=\> true  
> > [2, 2, 2].ordered? :\> #=\> false  
> > [2, 2, 2].ordered? :\>= #=\> true
> > 
> > Supplying an block could also be useful?
> > 
> > [2, 2, 2].ordered? { |a, b| (((a-b) ^ (b-a)) % 3) == 0 }  
> > #=\> true
> > 
> > [1, 2, 3].ordered? { |a, b| (((a-b) ^ (b-a)) % 3) == 0 }  
> > #=\> false
> > 
> > –  
> > Simon Strandgaard

---

<div class="post-metadata">

**Author:** ![ts1](https://avatars.discourse-cdn.com/v4/letter/t/a8b319/32.png) [@ts1](https://rubytalk.org/u/ts1)\
**Post date:** [19 July 2003 15:18 UTC](https://rubytalk.org/t/chaining-comparisons/6926/31 "2003-07-19T15:18:17Z")

</div>

> Which implementation of 'inject' are you using? The one in PragProg requires  
> an initial value to be passed as a parameter.

svg% cat b.rb  
#!/usr/bin/ruby -v  
module Enumerable  
&nbsp;&nbsp;&nbsp;def ordered?  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;inject { | last, item | return false unless last \< item; item }  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;true  
&nbsp;&nbsp;&nbsp;end  
end

p [1,2,3,1].ordered?  
p [1,2,3].ordered?  
svg%

svg% b.rb  
ruby 1.8.0 (2003-07-18) [i686-linux]  
false  
true  
svg%

Guy Decoux

---

<div class="post-metadata">

**Author:** ![Pit](https://avatars.discourse-cdn.com/v4/letter/p/f14d63/32.png) [@Pit](https://rubytalk.org/u/Pit)\
**Post date:** [19 July 2003 20:24 UTC](https://rubytalk.org/t/chaining-comparisons/6926/32 "2003-07-19T20:24:56Z")

</div>

It’s Andy’s Windows installer version:

D:\Temp\>ruby -v  
ruby 1.8.0 (2003-05-26) [i386-mswin32]

And ri says about inject:

D:\Temp\>ri inject  
This is a test ‘ri’. Please report errors and omissions  
on [http://www.rubygarden.org/ruby?RIOnePointEight](http://www.rubygarden.org/ruby?RIOnePointEight)

> **···**
>
> On 20 Jul 2003 at 0:10, Brian Candler wrote:
> 
> > Which implementation of ‘inject’ are you using? The one in PragProg requires  
> > an initial value to be passed as a parameter.
> 
> * * *
> 
> ## Enumerable#inject enumObj.inject(initial) {| memo, obj | block } → anObject enumObj.inject {| memo, obj | block } → anObject
> 
> Combines the elements of enumObj by applying the block to an  
> accumulator value (memo) and each element in turn. At each step,  
> memo is set to the value returned by the block. The first form lets  
> you supply an initial value for memo. The second form uses the  
> first element of the collection as a the initial value (and skips  
> that element while iterating).
> 
> > With an array of N elements you either need to do N-1 comparisons,
> 
> This is what the second form does.
> 
> > or you  
> > need to start with a sentinel value which is guaranteed to be less than all  
> > other elements (nil and 0 both aren’t suitable).
> 
> This is what the first form would do.
> 
> BTW, if you wanted to add the compare method as a parameter as  
> someone else suggested, you could define
> 
> module Enumerable  
> def ordered?( compare\_method = :\< )  
> inject { | last, item |  
> return false unless last.send( compare\_method, item )  
> item  
> }  
> true  
> end  
> end
> 
> and then call it like
> 
> p [1, 2, 2].ordered? # =\> false  
> p [1, 2, 2].ordered?( :\<= ) # =\> true
> 
> Isn’t it fun to code in Ruby :\< )
> 
> Regards,  
> Pit

---

<div class="post-metadata">

**Author:** ![Jason\_Creighton3](https://avatars.discourse-cdn.com/v4/letter/j/e19adc/32.png) [@Jason\_Creighton3](https://rubytalk.org/u/Jason_Creighton3)\
**Post date:** [20 July 2003 05:14 UTC](https://rubytalk.org/t/chaining-comparisons/6926/33 "2003-07-20T05:14:00Z")

</div>

The inject in 1.8 defaults its initial value to the first item in the collection.

Jason Creighton

> **···**
>
> On Sun, 20 Jul 2003 00:10:25 +0900 Brian Candler [B.Candler@pobox.com](mailto:B.Candler@pobox.com) wrote:
> 
> > On Sat, Jul 19, 2003 at 11:23:04PM +0900, Pit Capitain wrote:
> > 
> > > I’m not Dave Thomas 🙂 but you can also use inject here:
> > > 
> > > module Enumerable  
> > > def ordered?  
> > > inject { | last, item | return false unless last \< item; item }  
> > > true  
> > > end  
> > > end
> > 
> > Which implementation of ‘inject’ are you using? The one in PragProg requires  
> > an initial value to be passed as a parameter.

---

<div class="post-metadata">

**Author:** ![Simon\_Strandgaard](https://avatars.discourse-cdn.com/v4/letter/s/e47774/32.png) [@Simon\_Strandgaard](https://rubytalk.org/u/Simon_Strandgaard)\
**Post date:** [21 July 2003 12:41 UTC](https://rubytalk.org/t/chaining-comparisons/6926/34 "2003-07-21T12:41:31Z")

</div>

OK… this is the nicest solution so far 🙂

I didn’t thought of using proc’s for binary compares.

> **···**
>
> On Mon, 21 Jul 2003 14:54:10 +0200, Robert Klemme wrote:
> 
> > An alternative
> > 
> > def less(\*args); compare\_chain(proc{|a,b|a\<b}, \*args); end  
> > def greater(\*args); compare\_chain(proc{|a,b|a\>b}, \*args); end
> > 
> > def compare\_chain(comp, \*args)  
> > last = nil
> > 
> > args.each do |i|  
> > return false if last and not comp.call(last,i)  
> > last = i  
> > end
> > 
> > true  
> > end
> > 
> > less 1,10,22  
> > less 2,1,14  
> > less -2,1,14  
> > greater 10,3,-100  
> > greater 2,1,14
> 
> –  
> Simon Strandgaard

---

<div class="post-metadata">

**Author:** ![Robert](https://avatars.discourse-cdn.com/v4/letter/r/e95f7d/32.png) [@Robert](https://rubytalk.org/u/Robert)\
**Post date:** [21 July 2003 15:22 UTC](https://rubytalk.org/t/chaining-comparisons/6926/35 "2003-07-21T15:22:33Z")

</div>

“Simon Strandgaard” [0bz63fz3m1qt3001@sneakemail.com](mailto:0bz63fz3m1qt3001@sneakemail.com) schrieb im  
Newsbeitrag [news:pan.2003.07.21.12.42.13.887241@sneakemail.com](mailto:news:pan.2003.07.21.12.42.13.887241@sneakemail.com)…

> OK… this is the nicest solution so far 🙂

I’ve found an even nicer solution that allows user defined comparisons  
nicely:

def less(\*args); check\_chain(\*args){|a,b|a\<b}; end  
def greater(\*args); check\_chain(\*args){|a,b|a\>b}; end

def check\_chain(\*args, &comp)  
raise “Block needed” unless comp

last = nil

args.each do |i|  
return false if last and not comp.call(last,i)  
last = i  
end

true  
end

less 1,10,22  
less 2,1,14  
less -2,1,14  
greater 10,3,-100  
greater 2,1,14

check\_chain( 2, 4, 16 ){|a,b| a_a==b}  
check\_chain( 2, 4, 17 ){|a,b| a_a==b}

The thing that bugged my about the last one was the first parameter to  
compare\_chain() which prevented nice user defined checks.

> I didn’t thought of using proc’s for binary compares.

The proposed implementation of ordering? inspired my. Though while  
writing this I see a more general pattern here that reminds a bit of  
Enumerable#inject (Ruby 1.8):

module Enumerable  
def connect(coll)  
last = nil  
first = true

```
each do |i|
  if first
    first = false
  else
    coll = yield(coll,last,i)
  end

  last = i
end

coll

```

end  
end

def less(\*args); args.connect( true ){|c,a,b|c && a\<b}; end  
def greater(\*args); args.connect( true ){|c,a,b|c && a\>b}; end

[1, 2, 3].connect( true ){|coll,a,b|coll && a\<b}  
[2, 4, 16].connect( true ){|coll,a,b|coll && a\*a==b}

These versions are less efficient for sequences that fail the test but one  
might consider to change the implementation to stop if coll is false or  
nil.

Method Enumerable#connect might even be considert a library addenum, IMHO.  
Maybe inject might be changed to yield one more parameter the way it is  
shown here. What does Matz think? What do others think?

Regards

```
robert

```

---

<div class="post-metadata">

**Author:** ![Robert](https://avatars.discourse-cdn.com/v4/letter/r/e95f7d/32.png) [@Robert](https://rubytalk.org/u/Robert)\
**Post date:** [22 July 2003 05:08 UTC](https://rubytalk.org/t/chaining-comparisons/6926/36 "2003-07-22T05:08:36Z")

</div>

“Robert Klemme” [bob.news@gmx.net](mailto:bob.news@gmx.net) schrieb im Newsbeitrag  
[news:bfgvjq$e7itp$1@ID-52924.news.uni-berlin.de](mailto:news:bfgvjq$e7itp$1@ID-52924.news.uni-berlin.de)…

(Now I start already at 36 talking to myself…)

> Method Enumerable#connect might even be considert a library addenum, IMHO.  
> Maybe inject might be changed to yield one more parameter the way it is  
> shown here. What does Matz think? What do others think?

I’d like to propose a slightly different version of Enumerable#inject which  
uses a sliding window on the enum and is compatible with the 1.8 version:

module Enumerable  
def inject(val=nil, &bl)  
raise “Block missing” unless bl

```
size = bl.arity
raise "Need block with at least 1 argument" if size == 0

size = size < 0 ? 1+size : size-1
args=[]

each do |e|
  args.push e

  if args.length == size
    val = yield val, *args
    args.shift
  end
end

val

```

end  
end

Now, apart from the usual inject things like sum, product and max  
calculations you can do a lot of nice things like

irb(main):374:0\* a=[1, 20, 30, 40, 41, 42, 88, 123]  
=\> [1, 20, 30, 40, 41, 42, 88, 123]  
irb(main):375:0\> b=  
=\>   
irb(main):376:0\> # SMOOTH  
irb(main):377:0\* sm=  
=\>   
irb(main):378:0\> a.inject(0){|idx, x, y| sm[idx] = (x+y).to\_f / 2; idx+1}  
=\> 7  
irb(main):379:0\> sm  
=\> [10.5, 25.0, 35.0, 40.5, 41.5, 65.0, 105.5]  
irb(main):380:0\> sm=  
=\>   
irb(main):381:0\> a.inject(0){|idx, x, y, z| sm[idx] = (x+y+z).to\_f / 3;  
idx+1}  
=\> 6  
irb(main):382:0\> sm  
=\> [17.0, 30.0, 37.0, 41.0, 57.0, 84.33333333]  
irb(main):383:0\> # WEIGHTED SMOOTHING  
irb(main):384:0\* sm=  
=\>   
irb(main):385:0\> a.inject(0){|idx, x, y, z| sm[idx] = (x+y+y+z).to\_f / 4;  
idx+1}  
=\> 6  
irb(main):386:0\> sm  
=\> [17.75, 30.0, 37.75, 41.0, 53.25, 85.25]  
irb(main):387:0\> # TEST SORTED  
irb(main):388:0\* a.inject(true) {|cond, x, y| cond && x\<y}  
=\> true  
irb(main):389:0\> b.inject(true) {|cond, x, y| cond && x\<y}  
=\> true  
irb(main):390:0\> def ordered?(\*args); args.inject(true) {|cond, x, y| cond  
&& x\<  
y}; end  
=\> nil  
irb(main):391:0\> ordered? \*a  
=\> true  
irb(main):392:0\> ordered? 1,2,4  
=\> true  
irb(main):393:0\>

What do you think?

```
robert

```

[Previous page](https://rubytalk.org/t/chaining-comparisons/6926.md?page=1)
