Convert integer string to array of integers

I did use the below :-

“12^ abc23 44”.scan(/\d+/).map(&:to_i)

=> [12, 23, 44]

Now, I thought, let’s try to do this without creating an intermediate
array.

Then I saw, String#scan supports block, so I can write

ar = []
“12^ abc23 44”.scan(/\d+/) { |e| ar << e.to_i }

Then I thought, lets use the block support of #scan some other way
and I
came up with the below :-

“12^ abc23 44”.enum_for(:scan, /\d+/).with_object([]) { |e, a| a <<
e.to_i }

=> [12, 23, 44]

It works, but not I am able to understand, if it is creating the
intermediate
array ( as #scan do without block), or block version of #scan is getting
called.

Regards,
Arup R.

Debugging is twice as hard as writing the code in the first place.
Therefore,
if you write the code as cleverly as possible, you are, by definition,
not
smart enough to debug it.

–Brian Kernighan

On 5 July 2014 17:52, Arup R. [email protected] wrote:

ar = []

It works, but not I am able to understand, if it is creating the
intermediate
array ( as #scan do without block), or block version of #scan is getting
called.

Does it matter that much? BTW if all you care about is only creating a
single array, you could use #map!

On Saturday, July 05, 2014 07:52:31 PM Matthew K. wrote:
It works, but not I am able to understand, if it is creating the
intermediate
array ( as #scan do without block), or block version of #scan is getting
called.

Does it matter that much?

Curiosity … :slight_smile:

BTW if all you care about is only creating a
single array, you could use #map!

Yes latter I found it, which shorten the length of code. :slight_smile: But
curiosity
remains still there inside the #enum_for construct…

Regards,
Arup R.

Debugging is twice as hard as writing the code in the first place.
Therefore,
if you write the code as cleverly as possible, you are, by definition,
not
smart enough to debug it.

–Brian Kernighan

On Sat, Jul 5, 2014 at 2:38 PM, Arup R.
[email protected] wrote:

Yes latter I found it, which shorten the length of code. :slight_smile: But curiosity
remains still there inside the #enum_for construct…

And what do you want to know?

Cheers

robert

On Sunday, July 06, 2014 12:14:37 PM Arup R. wrote:

On Saturday, July 05, 2014 09:37:00 PM Robert K. wrote:

On Sat, Jul 5, 2014 at 2:38 PM, Arup R. [email protected]

I want to know in the below code :-

“12^ abc23 44”.enum_for(:scan, /\d+/).with_object([]) { |e, a| a << e.to_i
} #or
“12^ abc23 44”.enum_for(:scan, /\d+/).map { |e, a| a << e.to_i }

sorry for wrong copy paste :-

“12^ abc23 44”.enum_for(:scan, /\d+/).map { |e| e.to_i }

Regards,
Arup R.

Debugging is twice as hard as writing the code in the first place.
Therefore,
if you write the code as cleverly as possible, you are, by definition,
not
smart enough to debug it.

–Brian Kernighan

On Saturday, July 05, 2014 09:37:00 PM Robert K. wrote:

On Sat, Jul 5, 2014 at 2:38 PM, Arup R. [email protected]
wrote:

Yes latter I found it, which shorten the length of code. :slight_smile: But curiosity
remains still there inside the #enum_for construct…

And what do you want to know?

Cheers

robert

Robert,

I want to know in the below code :-

“12^ abc23 44”.enum_for(:scan, /\d+/).with_object([]) { |e, a| a <<
e.to_i }
#or
“12^ abc23 44”.enum_for(:scan, /\d+/).map { |e, a| a << e.to_i }

e is coming from -

“12^ abc23 44”.scan(/\d+/) { |e| e } # from block version ?
#or
“12^ abc23 44”.scan(/\d+/) # produces array. From this array ?

Hope I am now able to express my curiosity. :slight_smile:

Regards,
Arup R.

Debugging is twice as hard as writing the code in the first place.
Therefore,
if you write the code as cleverly as possible, you are, by definition,
not
smart enough to debug it.

–Brian Kernighan

Continuation…

So,

“12^ abc23 44”.scan(/\d+/)
“12^ abc23 44”.scan(/\d+/).map { |e| e }
“12^ abc23 44”.enum_for(:scan, /\d+/).map { |e| e }
“12^ abc23 44”.enum_for(:scan, /\d+/).map.to_a
“12^ abc23 44”.enum_for(:scan, /\d+/).enum_for(:map).to_a

… are pretty equivalent (in results term) and you should use the
first form, and I see no reason for using the laters apart from
“learning” and understanding enumerators.

Abinoam Jr.

Hi Arup,

Sorry if I misunderstood your question, but I’ll try to help.

“12^ abc23 44”.scan(/\d+/) { |e| e }

It iterates through each element and then returns the ‘source’ String!

So if you run the line you have pasted, you just receive back the
string you’ve given.
But it truly has iterated through all matches.
To see it, change

“12^ abc23 44”.scan(/\d+/) { |e| e }
to
“12^ abc23 44”.scan(/\d+/) { |e| puts e }

And you’re gonna see it outputting:
12
23
44

And then returns => “12^ abc23 44”

If you use map (alias for collect) it collects/maps those values.

So,

“12^ abc23 44”.scan(/\d+/)
“12^ abc23 44”.scan(/\d+/).map { |e| e }

Was it related to your question? Did it help you?

On Sunday, July 06, 2014 08:41:34 AM Abinoam Jr. wrote:

… are pretty equivalent (in results term) and you should use the
first form,

Thanks for your details explanation.

apart from
“learning” and understanding enumerators.

Your catch is correct, Just to understand and learning.

It seems I am not able to clear myself to you people. I know how #scan
works.
But question is while I am writing

“any string”.enum_for(:scan, /\d+/) — then which version of block is
actually called, block version or without block version. Because I
am not
able to see it,

If I write “any string”.scan(/\d+/) — It is clear that I am using
without
block version.

Now If I write “any string”.scan(/\d+/) { |m| p m } - It is clear I am
using
block version.

Now, while I write - “any string”.enum_for(:scan, /\d+/) – I can’t see
how
$scan is actually working. So my question came out right there…

Hope it is clear now.

Regards,
Arup R.

Debugging is twice as hard as writing the code in the first place.
Therefore,
if you write the code as cleverly as possible, you are, by definition,
not
smart enough to debug it.

–Brian Kernighan

On Jul 6, 2014, at 7:27 AM, Arup R. [email protected]
wrote:

Now If I write “any string”.scan(/\d+/) { |m| p m } - It is clear I am using
block version.

Now, while I write - “any string”.enum_for(:scan, /\d+/) – I can’t see how
$scan is actually working. So my question came out right there…

Hope it is clear now.

One way I have started to understand how Ruby’s interpreter works is to
look at the source. These days I use pry to look at things in Ruby as I
can use pry’s $ command to see source:

[1]pry(main)> $ String#scan

From: string.c (C Method):
Owner: String
Visibility: public
Number of lines: 30

static VALUE
rb_str_scan(VALUE str, VALUE pat)
{
VALUE result;
long start = 0;
long last = -1, prev = 0;
char *p = RSTRING_PTR(str); long len = RSTRING_LEN(str);

pat = get_pat(pat, 1);
if (!rb_block_given_p()) {
    VALUE ary = rb_ary_new();

    while (!NIL_P(result = scan_once(str, pat, &start))) {
        last = prev;
        prev = start;
        rb_ary_push(ary, result);
    }
    if (last >= 0) rb_reg_search(pat, str, last, 0);
    return ary;
}

while (!NIL_P(result = scan_once(str, pat, &start))) {
    last = prev;
    prev = start;
    rb_yield(result);
    str_mod_check(str, p, len);
}
if (last >= 0) rb_reg_search(pat, str, last, 0);
return str;

}

There aren’t two different versions of String#scan, when a String is
sent the scan message the scan method checks to see if it was given a
block. If no block was given then it builds and returns a new array,
populates it and returns it. If there was a block given then it yields
the results as it finds them and eventually returns the original string.

Another fun place to look for implementations of bits of Ruby is in
Rubinius, as most of it is written in Ruby.

Hope this helps,

Mike

Mike S. [email protected]
http://www.stok.ca/~mike/

The “`Stok’ disclaimers” apply.

On Sun, Jul 6, 2014 at 1:27 PM, Arup R.
[email protected] wrote:

… are pretty equivalent (in results term) and you should use the
first form,

There are use cases for #enum_for though - these are typically related
to situations where the set of items generated may be large. Note
also that many methods implicitly do #enum_for if no block is passed,
e.g. Integer#times does this:

irb(main):008:0> x = 5.times
=> #<Enumerator: 5:times>
irb(main):009:0> x.class
=> Enumerator
irb(main):010:0> x.class.ancestors
=> [Enumerator, Enumerable, Object, Kernel, BasicObject]
irb(main):011:0> x.each {|i| p i}
0
1
2
3
4
=> 5

Now If I write “any string”.scan(/\d+/) { |m| p m } - It is clear I am using
block version.

Now, while I write - “any string”.enum_for(:scan, /\d+/) – I can’t see how
$scan is actually working. So my question came out right there…

Hope it is clear now.

Yes. And you can test this yourself fairly easily:

irb(main):001:0> class X; def a; printf “block: %s\n”, block_given? end
end
=> nil
irb(main):002:0> X.new.enum_for(:a).each {|x| p x}
block: true
=> nil

If the method actually invokes the block this is what happens:

irb(main):003:0> class X; def a; printf “block: %s\n”, block_given?;
yield 123 if block_given? end end
=> nil
irb(main):004:0> X.new.enum_for(:a).each {|x| p x}
block: true
123
=> 123

Kind regards

robert

Now If I write “any string”.scan(/\d+/) { |m| p m } - It is clear I am using
block version.

Yes, the block is here:

{ |m| p m }

Now, while I write - “any string”.enum_for(:scan, /\d+/) – I can’t see how
$scan is actually working.

Consider this: where does the block { |m| p m } appear in that
line of code? It would be pretty hard for scan to call a block that
doesn’t exist wouldn’t it?

Let’s get down to basics: a block is simply a method that you pass to
another method. The receiving method can call the block/method if it
wants to or it can do nothing with the block. Ruby’s syntax for blocks
makes it easy to misunderstand what a block is. A block is just an
anonymous method that you define right after a method call, and then the
anonymous method gets passed to the method. Here are some examples:

arr = [10, 20, 30]

class Array
def my_each(&block)
self.each do |elm|
block.call(elm)
end
end
end

arr.my_each do |x|
puts “#{x} says hello”
end

p = Proc.new do |x|
puts “#{x} says goodbye”
end

arr.my_each(&p)

–output:–
10 says hello
20 says hello
30 says hello
10 says goodbye
20 says goodbye
30 says goodbye

The thing about a block, though, is that a block can be passed to a
method that doesn’t specify any arguments. In that case, the method
calls the block using yield:

def do_stuff
#I am a method that can take a block
#that should be defined with 2 args
if block_given?
yield 10, 20
else
puts ‘hello’
end
end

do_stuff do |x, y|
puts x*y
end

do_stuff

–output:–
30
hello

Let’s get back to this:

Now, while I write - “any string”.enum_for(:scan, /\d+/) – I can’t see how
$scan is actually working.

Here are the docs for Object#enum_for:

===
enum_for(method = :each, *args) → enum

Creates a new Enumerator which will enumerate by calling method on obj,
passing args if any.

So this “Enumerator thing” is going to call scan() on whatever object is
specified to the left of enum_for, which in your example is a String.
What is an Enumerator? According to:

it’s some kind of object that has a next() method for stepping through
the values that scan() produces.