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

···

--
Posted via http://www.ruby-forum.com/.

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

David

···

--
Posted via http://www.ruby-forum.com/.

[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 Nielsen

Oh, I wish for a real integer set class!

···

On 4/2/10, Roger Pack <rogerpack2005@gmail.com> 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
}

?

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

···

--
Posted via http://www.ruby-forum.com/.

David Springer 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

···

--
Posted via http://www.ruby-forum.com/.

Well, there's Fixnum / Bignum:

irb(main):004:0> set = 0
=> 0
irb(main):005:0> set[1]
=> 0
irb(main):006:0> set |= (1 << 1)
=> 2
irb(main):007:0> set[1]
=> 1
irb(main):008:0> set |= (1 << 100)
=> 1267650600228229401496703205378
irb(main):009:0> set[1]
=> 1
irb(main):010:0> set[100]
=> 1

It's fairly easy to build something around that, e.g.

class IntSet
   include Enumerable

   def initialize
     @s = 0
   end

   def add? x
     @s[x] == 0 and @s |= (1 << x)
   end

   def add x
     add? x
     self
   end

   alias << add

   def delete? x
     @s[x] == 1 and @s ^= (1 << x)
   end

   def include? x
     @s[x] == 1
   end

   def each
     x = 0
     it = 1 << x

     while it <= @s
       yield x if @s[x] == 1
       x += 1
       it <<= 1
     end

     self
   end
end

is = IntSet.new

is << 10 << 5 << 14

is.each {|x| p x}

Kind regards

  robert

···

On 04/03/2010 03:07 AM, Caleb Clausen wrote:

On 4/2/10, Roger Pack <rogerpack2005@gmail.com> 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!

--
remember.guy do |as, often| as.you_can - without end
http://blog.rubybestpractices.com/

or

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

···

On Fri, Apr 2, 2010 at 6:33 PM, Roger Pack <rogerpack2005@gmail.com> wrote:

David Springer 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.

--
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

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 Fri, Apr 2, 2010 at 11:33 PM, Roger Pack <rogerpack2005@gmail.com> wrote:

David Springer 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}}

Well, yeah, and that's fine for storing sets of small integers. Or I
could put my Integers into a Set, and that's fine for small sets of
integers. I have used both techniques in the past. What I have in mind
is more scalable: a way to store large sets of large integers.
Efficiently. So, what I would like to see is a data structure with
O(1) (or at most O(log(n))) insertion, deletion, and lookup times, as
well as (as close as possible to) O(1) memory cost per stored item.
Contiguous ranges of integers should be storable with not much more
memory cost than that of a single integer.

Bitmaps come close, but also cost O(1) bits per integer (< the largest
integer stored) which _isn't_ in the set. A hash-based set costs
something like O(2*wordsize) bits per stored integer. Perhaps this can
be reduced to O(2+wordsize) if using google's sparse array/sparse
hash. (Which Roger has been kind enough to add a ruby interfaces
for.... but not an integer set.)

Of course there's a contradiction here; if:
1) the integer set is fairly dense, and
2) members are randomly distributed throughout it,
then Kolmogorov complexity theory says you can't get any better
storage efficiency than a bitmap. So, this miraculous data structure
I'm imagining has to be allowed to discard one or the other of those
assumptions. Discarding 1) leads to something like google's sparse
array (sparse bitmap really; I'm not sure if google's sparse array
code could be used as is). Discarding 2) leads you in the direction of
a tree or trie. That's what I'm more interested in. Maybe something
based on Judy would suit my purposes....

I've wanted this several times, but never really needed it badly
enough to go and implement what I want to see. (As it almost surely
involves writing a fair bit of c code.)

···

On 4/4/10, Robert Klemme <shortcutter@googlemail.com> wrote:

On 04/03/2010 03:07 AM, Caleb Clausen wrote:

Oh, I wish for a real integer set class!

Well, there's Fixnum / Bignum:

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

Tomo

···

On Fri, Apr 2, 2010 at 7:28 PM, Rick DeNatale <rick.denatale@gmail.com>wrote:

On Fri, Apr 2, 2010 at 6:33 PM, Roger Pack <rogerpack2005@gmail.com> > wrote:
> David Springer 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.

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

[[*(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 Apr 2, 2010, at 16:28 , Rick DeNatale wrote:

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

···

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

On Fri, Apr 2, 2010 at 11:33 PM, Roger Pack <rogerpack2005@gmail.com> wrote:

David Springer 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

--
remember.guy do |as, often| as.you_can - without end
http://blog.rubybestpractices.com/

Oh, I wish for a real integer set class!

Well, there's Fixnum / Bignum:

Well, yeah, and that's fine for storing sets of small integers. Or I
could put my Integers into a Set, and that's fine for small sets of
integers. I have used both techniques in the past. What I have in mind
is more scalable: a way to store large sets of large integers.
Efficiently. So, what I would like to see is a data structure with
O(1) (or at most O(log(n))) insertion, deletion, and lookup times, as
well as (as close as possible to) O(1) memory cost per stored item.
Contiguous ranges of integers should be storable with not much more
memory cost than that of a single integer.

Bitmaps come close, but also cost O(1) bits per integer (< the largest
integer stored) which _isn't_ in the set. A hash-based set costs
something like O(2*wordsize) bits per stored integer.

I believe, it's more since you explicitly stated you want large numbers (=> Bignum).

Perhaps this can
be reduced to O(2+wordsize) if using google's sparse array/sparse
hash. (Which Roger has been kind enough to add a ruby interfaces
for.... but not an integer set.)

Of course there's a contradiction here; if:
1) the integer set is fairly dense, and
2) members are randomly distributed throughout it,
then Kolmogorov complexity theory says you can't get any better
storage efficiency than a bitmap. So, this miraculous data structure
I'm imagining has to be allowed to discard one or the other of those
assumptions. Discarding 1) leads to something like google's sparse
array (sparse bitmap really; I'm not sure if google's sparse array
code could be used as is). Discarding 2) leads you in the direction of
a tree or trie. That's what I'm more interested in. Maybe something
based on Judy would suit my purposes....

I've wanted this several times, but never really needed it badly
enough to go and implement what I want to see. (As it almost surely
involves writing a fair bit of c code.)

Take that as a hint. :slight_smile:

Kind regards

  robert

···

On 04.04.2010 20:21, Caleb Clausen wrote:

On 4/4/10, Robert Klemme <shortcutter@googlemail.com> wrote:

On 04/03/2010 03:07 AM, Caleb Clausen wrote:

--
remember.guy do |as, often| as.you_can - without end
http://blog.rubybestpractices.com/

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

···

On Fri, Apr 2, 2010 at 8:20 PM, Tomo Kazahaya <tomonacci@gmail.com> wrote:

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

--
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

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 Apr 3, 5:42 am, Ryan Davis <ryand-r...@zenspider.com> wrote:

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:

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 Wright

···

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

On Fri, Apr 2, 2010 at 8:20 PM, Tomo Kazahaya <tomonacci@gmail.com> wrote:

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

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

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 ?

I don't think so.

robert@fussel:~$ ruby19 --version
ruby 1.9.1p376 (2009-12-07 revision 26041) [i686-linux]
robert@fussel:~$ ruby19 -e 'p [1,2,*10..15,345]'
[1, 2, 10, 11, 12, 13, 14, 15, 345]

Kind regards

  robert

···

On 04/03/2010 04:14 AM, Gary Wright wrote:

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

On Fri, Apr 2, 2010 at 8:20 PM, Tomo Kazahaya <tomonacci@gmail.com> 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]

--
remember.guy do |as, often| as.you_can - without end
http://blog.rubybestpractices.com/

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 Klemme'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 Klemme'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 Klemme'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 Sat, Apr 3, 2010 at 2:30 PM, Intransition <transfire@gmail.com> wrote: