Combined ranges

Anybody know if there’s an easy way to accomplish the equivalent of
this:

[1…20, 30…46].each{|n|

n = 1,2,3,4,5…30, 31, 32

}

?

Thanks!
-rp

Will this work:
[1…20,30…46].each{|r| r.each {|n| p n}}

David

[1…20, 30…46].each{|n|
 # n = 1,2,3,4,5…30, 31, 32
}

Only thing that comes to mind for me is

r1 = 1…20
r2 = 30…46
(r1.to_a + r2.to_a).each{|n| puts n}

Probably not the best solution, but works…

-Jonathan N.

Adding parentheses may make it a little clearer:
[(1…20),(30…46)].each{|r| r.each {|n| p n}}
David

On Fri, Apr 2, 2010 at 6:33 PM, Roger P. [email protected]
wrote:

So that’ll work.
or

[[(1…20)], 25, [(30…46)]].flatten.each {|n| p n}


Rick DeNatale

Blog: http://talklikeaduck.denhaven2.com/
Github: http://github.com/rubyredrick
Twitter: @RickDeNatale
WWR: http://www.workingwithrails.com/person/9021-rick-denatale
LinkedIn: http://www.linkedin.com/in/rickdenatale

You can splat objects with to_a everywhere.
[*1…20, 25, *30…46].each {|n| p n}

Tomo

David S. wrote:

Will this work:
[1…20,30…46].each{|r| r.each {|n| p n}}

Yeah that works.

I guess if I need individual values in there (like 25) I can do

[1…20, 25…25, 30…46].each{|r| r.each {|n| p n}}

So that’ll work.
Thanks.
-rp

On 4/2/10, Roger P. [email protected] wrote:

Anybody know if there’s an easy way to accomplish the equivalent of
this:

[1…20, 30…46].each{|n|

n = 1,2,3,4,5…30, 31, 32

}

?

Oh, I wish for a real integer set class!

On Fri, Apr 2, 2010 at 8:20 PM, Tomo K. [email protected]
wrote:

[*1…20, 25, *30…46]

I’m afraid that that give a syntax error in both 1.8.7 and 1.9


Rick DeNatale

Blog: http://talklikeaduck.denhaven2.com/
Github: http://github.com/rubyredrick
Twitter: @RickDeNatale
WWR: http://www.workingwithrails.com/person/9021-rick-denatale
LinkedIn: http://www.linkedin.com/in/rickdenatale

On Apr 2, 2010, at 10:01 PM, Rick DeNatale wrote:

On Fri, Apr 2, 2010 at 8:20 PM, Tomo K. [email protected] wrote:

[*1…20, 25, *30…46]

I’m afraid that that give a syntax error in both 1.8.7 and 1.9

I only have 1.9.0 handy, but did something change when I wasn’t looking:

$ ruby1.9 -v
ruby 1.9.0 (2008-07-25 revision 18217) [i686-darwin9]
$ ruby1.9 -e ‘p [*1…20, 25, *30…46]’
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
25, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46]

Gary W.

On Apr 2, 2010, at 16:28 , Rick DeNatale wrote:

[[(1…20)], 25, [(30…46)]].flatten.each {|n| p n}

or:

class Range
alias :to_a :to_ary
end

[1…20, 25, 30…46].flatten
=> [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19,
20, 25, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45,
46]

I think that’s a lot prettier… seems safe to me :smiley:

On Fri, Apr 2, 2010 at 11:33 PM, Roger P. [email protected]
wrote:

David S. wrote:

Will this work:
[1…20,30…46].each{|r| r.each {|n| p n}}

Yeah that works.
I guess if I need individual values in there (like 25) I can do
[1…20, 25…25, 30…46].each{|r| r.each {|n| p n}}

Given the solutions proposed, in suggesting this I have a feeling
I may well be missing something, but since I might learn something:
why not write a method (and maybe add it to Array) like:

def each_element_or_range_element( arr )
arr.each do |er|
if er.kind_of?( Range ) then er.each { |e| yield e }
else yield er
end
end
end

aa = [ 1…2, 355, 3…4, 113, 2.5 , 3.5…5.5 ]
each_element_or_range_element(aa) { |e| print " #{e}" }
1 2 355 3 4 113 2.5
TypeError: can’t iterate from Float

On Apr 3, 5:42 am, Ryan D. [email protected] wrote:

[1…20, 25, 30…46].flatten

=> [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 25, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46]

I think that’s a lot prettier… seems safe to me :smiley:

I can’t think of any reason that it wouldn’t be safe --and if it is
then it’s a very nice solution. But Ryan did you use the :smiley: emoticon
to suggest that it really was unsafe?

In any case, to avoid the large footprint of using flatten you could
try something like

module Enumerable
def visit
each do |n|
if Enumerable===n
n.each{ |*s| yield(*s) }
else
yield(n)
end
end
end
end

[1…20, 25, 30…46].visit{ |n| p n }

*I did not test this code, so it may need tweaking. But you get the
idea.

On 04/03/2010 04:14 AM, Gary W. wrote:

$ ruby1.9 -e ‘p [*1…20, 25, *30…46]’
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 25, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46]

I don’t think so.

[email protected]:~$ ruby19 --version
ruby 1.9.1p376 (2009-12-07 revision 26041) [i686-linux]
[email protected]:~$ ruby19 -e ‘p [1,2,*10…15,345]’
[1, 2, 10, 11, 12, 13, 14, 15, 345]

Kind regards

robert

On 04/03/2010 01:50 PM, Colin B. wrote:

why not write a method (and maybe add it to Array) like:

def each_element_or_range_element( arr )
arr.each do |er|
if er.kind_of?( Range ) then er.each { |e| yield e }
else yield er
end
end
end

Here’s my general purpose solution:

module Enumerable
def each_flat(levels, &b)
each do |x|
if levels > 1 && Enumerable === x
x.each_flat(levels - 1, &b)
else
b[x]
end
end
self
end
end

a = [
1,
2,
10…15,
3,
4,
[99,100,101,[“no more”]],
]

a.each_flat 2 do |x|
p x
end

Kind regards

robert

Here, I worked on it I came up with:

module Enumerable

def visit(type=Enumerable, &block)
  if block_given?
    each do |e|
      case e
      when type
        e.visit(type, &block)
      else
        block.call(e)
      end
    end
  else
    to_enum(:visit, type)
  end
end

end

I am going to add this to Facets, but I have to decide for sure on the
name. Which is better?

#visit
#traverse
#recurse

other ?

On Sat, Apr 3, 2010 at 2:30 PM, Intransition [email protected]
wrote:

Here, I worked on it I came up with:
Is this the Array#recursively “TODO: Can this be generalized in
Enumerable?” :slight_smile:
http://facets.rubyforge.org/apidoc/api/core/classes/Array.html#M000055

Oddly enough, I’d also started wondering about a fully recursive
version!
Borrowing ideas from Facets (Array#recursively, Enumerable#traverse)
I came up with the code at the end of this post. It’s not as general
as either your code or Robert K.'s (sort of “orthogonal” to yours)
but it was intended to cope with an element of the array
having an each method but not mixing in Enumerable

I am going to add this to Facets, but I have to decide for sure on the
name. Which is better? #visit #traverse #recurse other ?
I know they are long names, but because it’s a recursive each, why not
#each_recursively (Facets already uses recursively) or #each_recursive
(I prefer the latter - shorter!) and maybe have visit as a short alias?
Or maybe use Robert K.'s #each_flat, although since this will
apply a recursive each to Ranges (or Files, or anything else using each
which mixes in Enumerable) I’m not sure that flatten (or a derivative)
is fully appropriate?

I also like Robert K.'s idea of having a level parameter,
so if Robert is agreeable - and from his Ruby-talk posts he seems to be
a very agreeable person! - maybe include levels, maybe renamed depth?
(I’ve thought of using level in a more general Find module, and
eventually decided depth was a better word for the concept. I can’t
remember why, but I’m sure there must have been very good reasons!)
And maybe cater for “unlimited” depth using depth/levels = nil ? So:
if levels > 1 && Enumerable === x
x.each_flat(levels - 1, &b)
would become
if (! levels || levels > 1) && Enumerable === x
x.each_flat( levels && levels - 1, &b)

A question: should the depth/levels test be levels > 1 or > 0?
Using [ 2…2 ] and “levels > 1”:
levels param: 0 #=> 2…2; 1 #=> 2…2; 2 #=> 2;
Using [ 2…2 ] and “levels > 0”:
levels param: 0 #=> 2…2; 1 #=> 2; 2 #=> 2;
It seems (maybe?) more logical to have depth/levels arguments:
0 means don’t do any recursive expansion of each;
1 means do some recursive expansion of each;

Intended to cope with an element of an array (or whatever)

having an each method but not mixing in Enumerable.

module Enumerable
def visits(&block)
each { |item| Enumerable.visits?(item, &block) }
end
def Enumerable.visits?(obj, &block)
if obj.respond_to?( :each ) then
obj.each { |item| Enumerable.visits?(item, &block) }
else
yield obj
end
end
end

On Apr 3, 11:47 am, Colin B. [email protected] wrote:

On Sat, Apr 3, 2010 at 2:30 PM, Intransition [email protected] wrote:

Here, I worked on it I came up with:

Is this the Array#recursively “TODO: Can this be generalized in Enumerable?” :slight_smile:http://facets.rubyforge.org/apidoc/api/core/classes/Array.html#M000055

Thanks you for pointing this one out. I am working to make these
methods more uniform/consistent across all of Facets. There is also
similar methods for Pathname and Dir (e.g. Dir#recurse).

I know they are long names, but because it’s a recursive each, why not
#each_recursively (Facets already uses recursively) or #each_recursive
(I prefer the latter - shorter!) and maybe have visit as a short alias?
Or maybe use Robert K.'s #each_flat, although since this will
apply a recursive each to Ranges (or Files, or anything else using each
which mixes in Enumerable) I’m not sure that flatten (or a derivative)
is fully appropriate?

Yes, I was thinking of #recursive_each as well, since that name is
also along the lines of #reverse_each. On the other hand #recurse is
nice and short and to the point.

 if (! levels || levels > 1) && Enumerable === x
   x.each_flat( levels && levels - 1, &b)

A question: should the depth/levels test be levels > 1 or > 0?
Using [ 2…2 ] and “levels > 1”:
levels param: 0 #=> 2…2; 1 #=> 2…2; 2 #=> 2;
Using [ 2…2 ] and “levels > 0”:
levels param: 0 #=> 2…2; 1 #=> 2; 2 #=> 2;
It seems (maybe?) more logical to have depth/levels arguments:
0 means don’t do any recursive expansion of each;
1 means do some recursive expansion of each;

Yes, I agree, a depth parameter could be useful as well.

  yield obj
end

end
end

Interesting, you could take this a step further.

class Object
def visits(&block)
if respond_to?(:each)
each{ |item| item.visits(&block) }
else
yield(self)
end
end
end

Then every object would be “visitable”.

However, using respond_to? can be dangerous. Consider if I (foolishly)
did:

class Object
def each
yield(self)
end
end

The more OOP approach would be:

class Object
def visits
yield(self)
end
end

module Enumerable
def visits(&block)
each{ |item| item.visits(&block) }
end
end

Then you can override #visits in any object as desired.

On Sun, Apr 4, 2010 at 12:47 AM, Intransition [email protected]
wrote:

Yes, I was thinking of #recursive_each as well, since that name is
also along the lines of #reverse_each. On the other hand #recurse is
nice and short and to the point.

Some time after suggesting #each_recursive it occurred to me that
a possibility is #each_each which (apart from the issue of objects
which have an each method but which don’t mix in Enumerable)
sort of says what it does. Then we could also have
#each_each_with_index, Array#reverse_each_each, etc.

On Sun, Apr 4, 2010 at 1:12 AM, Caleb C. [email protected] wrote:

def visits(&block)

At one time, I got interested enough in this problem to write a fairly
complete solution to this problem (at least I think so). If
interested, please have a look at:
http://github.com/coatl/ron/blob/master/lib/ron/graphedge.rb

So, temporarily ignoring the problem of possible infinite loops
(which I’d just begun to worry about - I was using a = [2] ; a << a,
which in IRB gives [2, […]], and a = a[1] #=> [2, […]],
but your example is even simpler)
you opted for recursive_each (and recursive_reverse_each)?

Going back to the original problem, my understanding is that
Roger P. was looking for a simple way of putting some
data into an array and then getting at it, in which case
the likely maximum depth may well be known, and then
Robert K.'s solution with a mandatory level/depth argument
seems to work.

So I withdraw my suggestion of level/depth = nil for infinite depth!
(Interestingly, Numeric#step raises an error if the step is 0,
but Date#step seems to allow infinite loops with a step of 0.)

This forum is not affiliated to the Ruby language, Ruby on Rails framework, nor any Ruby applications discussed here.

| Privacy Policy | Terms of Service | Remote Ruby Jobs