Equvialent of Python slices?

Hello,

Sorry for the lame question again, but even after a lot of googling I still couldn't find the $subj., ie. something like:

>>> "asdfghj"[2::2]
'dgj'
(= every second letter, beginning from the 2nd index in the string)
>>> "asdfghj"[::-1]
'jhgfdsa'
(= the whole word, 1 steps backwards - i.e. the reverse of the string)

ranges in Ruby are similar, without the 3rd 'step' param, which I am missing frequently... Also, with slices, you can omit one or both delimiters (i.e. if you omit the first (last) one, it defaults to the 0th (last) index of the list - is there some simiar possibility in Ruby, too?

Thx
Peter
http://www.rubyrailways.com

Hello,

Sorry for the lame question again, but even after a lot of googling I still couldn't find the $subj., ie. something like:

>>> "asdfghj"[2::2]
'dgj'
(= every second letter, beginning from the 2nd index in the string)

I'm not going to call this as pretty, of course, but:

>> test = "asdfghj"
=> "asdfghj"
>> test[2..-1].gsub(/(.)./, "\\1")
=> "dgj"

Another way is to use step():

>> result = ""
=> ""
>> (2...test.size).step(2) { |i| result << test[i, 1] }
=> 2...7
>> result
=> "dgj"

We can get that down to one line with enumerator:

>> require "enumerator"
=> true
>> (2...test.size).enum_for(:step, 2).inject("") { |r, i| r << test[i, 1] }
=> "dgj"

I do realize the Python you showed is sexier though.

>>> "asdfghj"[::-1]
'jhgfdsa'
(= the whole word, 1 steps backwards - i.e. the reverse of the string)

>> test.reverse
=> "jhgfdsa"

:wink:

James Edward Gray II

···

On Oct 4, 2006, at 8:19 AM, Peter Szinek wrote:

James Edward Gray II wrote:

> Hello,
>
> Sorry for the lame question again, but even after a lot of googling
> I still couldn't find the $subj., ie. something like:
>
> >>> "asdfghj"[2::2]
> 'dgj'
> (= every second letter, beginning from the 2nd index in the string)

Interesting, though I'm surprised Python has explicit syntax for what
seems like a highly specific type of operation. But, hey, cool.

I'm not going to call this as pretty, of course, but:

>> test = "asdfghj"
=> "asdfghj"
>> test[2..-1].gsub(/(.)./, "\\1")
=> "dgj"

Slightly OT here....

I'm trying to remember why test[2, -1] returns nil. Positive numbers
for the second integer work as expected:

test[2,1] => 'd'
test[2,2] => 'df'
test[2,100] => dfghj
test[2,-1] => nil

/me considers a patch to string.c

Regards,

Dan

···

On Oct 4, 2006, at 8:19 AM, Peter Szinek wrote:

Hi Peter,

In ruby you can extend built-in objects, so you can get the same
(general) functionality by adding a method to Enumerable (which is
mixed-in to String and Array [and Hash, too, but step is not meaningful
for that class]):

module Enumerable
  def step(*args)
    start, stop = 0, -1
    case args.size
      when 1
        step = args[0]
      when 2
        start = args[0]
        step = args[1]
      when 3
        start = args[0]
        stop = args[1]
        step = args[2]
      else
        raise(ArgumentError,
              "`step': wrong number of " +
              "arguments (#{args.size} for 3)",
              caller)
    end
    if self.is_a?(Hash)
      raise(NoMethodError,
            "`step': not implemented for Hash",
            caller)
    end
    seq = self[start..stop]
    pos = 0
    if self.is_a?(Array)
      out = seq[0,1]
    elsif self.is_a?(String)
      out = seq[0,1].to_s
    end
    while pos < seq.size
      val = seq[(pos += step)]
      out << val unless val.nil?
    end
    out
  end
end

# start at index 2 and step by 2...
p "abcdefg".step(2, 2) # => "ceg"
p %w{a b c d e f g}.step(2, 2) # => ["c", "e", "g"]

# this breaks
{'a'=>'b'}.step(2) # => -:60: `step': not implemented for Hash
(NoMethodError)

Regards,
Jordan

James Edward Gray II wrote:
>
> > Hello,
> >
> > Sorry for the lame question again, but even after a lot of googling
> > I still couldn't find the $subj., ie. something like:
> >
> > >>> "asdfghj"[2::2]
> > 'dgj'
> > (= every second letter, beginning from the 2nd index in the string)

Interesting, though I'm surprised Python has explicit syntax for what
seems like a highly specific type of operation. But, hey, cool.

> I'm not going to call this as pretty, of course, but:
>
> >> test = "asdfghj"
> => "asdfghj"
> >> test[2..-1].gsub(/(.)./, "\\1")
> => "dgj"

Slightly OT here....

I'm trying to remember why test[2, -1] returns nil. Positive numbers
for the second integer work as expected:

test[2,1] => 'd'
test[2,2] => 'df'
test[2,100] => dfghj
test[2,-1] => nil

I can see it logically, test[start position, length]. A negative one
length doesn't make much sense. test[2..-1] works though, since it's
start postion..(.)end position. Unfortunately you can't coun't backwards
with a negative length ( like if I want the last two characters I can't
say test[-1, -2]. )

···

On Wed, Oct 04, 2006 at 11:10:10PM +0900, Daniel Berger wrote:

> On Oct 4, 2006, at 8:19 AM, Peter Szinek wrote:

/me considers a patch to string.c

Regards,

Dan

Logan Capaldo wrote:

···

On Wed, Oct 04, 2006 at 11:10:10PM +0900, Daniel Berger wrote:
>
> James Edward Gray II wrote:
> > On Oct 4, 2006, at 8:19 AM, Peter Szinek wrote:
> >
> > > Hello,
> > >
> > > Sorry for the lame question again, but even after a lot of googling
> > > I still couldn't find the $subj., ie. something like:
> > >
> > > >>> "asdfghj"[2::2]
> > > 'dgj'
> > > (= every second letter, beginning from the 2nd index in the string)
>
> Interesting, though I'm surprised Python has explicit syntax for what
> seems like a highly specific type of operation. But, hey, cool.
>
> > I'm not going to call this as pretty, of course, but:
> >
> > >> test = "asdfghj"
> > => "asdfghj"
> > >> test[2..-1].gsub(/(.)./, "\\1")
> > => "dgj"
>
> Slightly OT here....
>
> I'm trying to remember why test[2, -1] returns nil. Positive numbers
> for the second integer work as expected:
>
> test[2,1] => 'd'
> test[2,2] => 'df'
> test[2,100] => dfghj
> test[2,-1] => nil
I can see it logically, test[start position, length]. A negative one
length doesn't make much sense. test[2..-1] works though, since it's
start postion..(.)end position. Unfortunately you can't coun't backwards
with a negative length ( like if I want the last two characters I can't
say test[-1, -2]. )

Ok, I just need to remember the second value is a length, not an index,
although that still confuses me.

I wonder if making that change would cause havoc with the regex engine.
Best to leave it alone I suppose.

Regards,

Dan