# How would you write it vs Smalltalk

**URL:** <https://www.ruby-forum.com/t/how-would-you-write-it-vs-smalltalk/115259>\
**Category:** Ruby\
**Created:** [September 22, 2007, 7:37pm UTC](https://www.ruby-forum.com/t/how-would-you-write-it-vs-smalltalk/115259 "2007-09-22T19:37:20Z")\
**Posts on this page:** 8\
**Page:** 1

<div class="post-metadata">

**Author:** ![winterheat](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/w/7993a0/32.png) [@winterheat](https://www.ruby-forum.com/u/winterheat)\
**Post date:** [September 22, 2007, 7:37pm UTC](https://www.ruby-forum.com/t/how-would-you-write-it-vs-smalltalk/115259/1 "2007-09-22T19:37:20Z")

</div>

i found a description of Smalltalk in

[http://www.engin.umd.umich.edu/CIS/course.des/cis400/smalltalk/freq.html](http://www.engin.umd.umich.edu/CIS/course.des/cis400/smalltalk/freq.html)

and then I tried it in Ruby:

h = Hash.new(0)

print "Enter line: "

gets.downcase.each\_byte {|b| c = “%c” % b; h[c] += 1 if c =~ /[a-z]/}

p h.sort

C:\rails\depot\>ruby count\_alpha2.rb  
Enter line: This is a test of the line count  
[[“a”, 1], [“c”, 1], [“e”, 3], [“f”, 1], [“h”, 2], [“i”, 3], [“l”, 1],  
[“n”, 2],  
[“o”, 2], [“s”, 3], [“t”, 5], [“u”, 1]]

I just wonder how would you write it? There is no each\_char it seems,  
unless with ActiveSupport.

---

<div class="post-metadata">

**Author:** ![winterheat](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/w/7993a0/32.png) [@winterheat](https://www.ruby-forum.com/u/winterheat)\
**Post date:** [September 22, 2007, 7:50pm UTC](https://www.ruby-forum.com/t/how-would-you-write-it-vs-smalltalk/115259/2 "2007-09-22T19:50:52Z")

</div>

On Sun, 23 Sep 2007 02:37:28 +0900, SpringFlowers AutumnMoon wrote:

> I just wonder how would you write it? There is no each\_char it seems,  
> unless with ActiveSupport.

running away but a quick idea: you could use Integer#chr to get a char  
(well, a one-byte-string) from an integer.  
And, since you’re dwelling with bytes anyway, you could just do a test  
like  
if c =~ ?a…?z  
(?a being the literal to get the integer value of a character)

So something like:  
gets.downcase.each\_byte {|b| h[c.chr] += 1 if c =~ ?a…?z}

---

<div class="post-metadata">

**Author:** ![winterheat](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/w/7993a0/32.png) [@winterheat](https://www.ruby-forum.com/u/winterheat)\
**Post date:** [September 22, 2007, 8:40pm UTC](https://www.ruby-forum.com/t/how-would-you-write-it-vs-smalltalk/115259/3 "2007-09-22T20:40:57Z")

</div>

On 9/22/07, gabriele renzi [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) wrote:

> On Sun, 23 Sep 2007 02:37:28 +0900, SpringFlowers AutumnMoon wrote:
> 
> > I just wonder how would you write it? There is no each\_char it seems,  
> > unless with ActiveSupport.

> So something like:  
> gets.downcase.each\_byte {|b| h[c.chr] += 1 if c =~ ?a…?z}

Here’s another way:

puts “Enter line:”  
h = Hash.new(0)  
gets.scan(/[a-zA-Z]/) {|ch| h[ch.downcase] += 1 }  
p h.sort

–  
Rick DeNatale

My blog on Ruby  
[http://talklikeaduck.denhaven2.com/](http://talklikeaduck.denhaven2.com/)

---

<div class="post-metadata">

**Author:** ![winterheat](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/w/7993a0/32.png) [@winterheat](https://www.ruby-forum.com/u/winterheat)\
**Post date:** [September 23, 2007, 12:41pm UTC](https://www.ruby-forum.com/t/how-would-you-write-it-vs-smalltalk/115259/4 "2007-09-23T12:41:12Z")

</div>

Rick DeNatale schrieb:

> Here’s another way:
> 
> puts “Enter line:”  
> h = Hash.new(0)  
> gets.scan(/[a-zA-Z]/) {|ch| h[ch.downcase] += 1 }  
> p h.sort

Well, we need an inject solution, right?

p gets.downcase.scan(/[a-z]/).inject({}){|h,c|  
h.merge({c,h[c].to\_i+1})}.sort

cheers

Simon

---

<div class="post-metadata">

**Author:** ![winterheat](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/w/7993a0/32.png) [@winterheat](https://www.ruby-forum.com/u/winterheat)\
**Post date:** [September 24, 2007, 3:01am UTC](https://www.ruby-forum.com/t/how-would-you-write-it-vs-smalltalk/115259/5 "2007-09-24T03:01:22Z")

</div>

And this seems conceptually easier and it’s slightly faster(if I  
benchmarked it correctly):

input = gets  
h = Hash.new(0)

input.scan(/[a-z]/){|char| h[char] += 1}  
p h.sort

============

require “benchmark”

input = “123Hello+#”

h = Hash.new(0)  
Benchmark.bm(20) do |br|  
br.report(“scan with block:”) do  
200\_000.times do  
input.downcase.scan(/[a-z]/){|char| h[char] += 1}  
end  
end  
end

p h.sort  
puts

h = Hash.new(0)  
Benchmark.bm(20) do |br|  
br.report(“scan with inject:”) do  
200\_000.times do  
input.downcase.scan(/[a-z]/).inject(h) do |h, c|  
h[c] += 1  
h  
end  
end  
end  
end

p h.sort

–output:–

```
                      user system total real

```

scan with block: 2.690000 0.010000 2.700000 ( 2.714077)  
[[“e”, 200000], [“h”, 200000], [“l”, 400000], [“o”, 200000]]

```
                      user system total real

```

scan with inject: 2.830000 0.020000 2.850000 ( 2.856019)  
[[“e”, 200000], [“h”, 200000], [“l”, 400000], [“o”, 200000]]

---

<div class="post-metadata">

**Author:** ![winterheat](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/w/7993a0/32.png) [@winterheat](https://www.ruby-forum.com/u/winterheat)\
**Post date:** [September 24, 2007, 12:47am UTC](https://www.ruby-forum.com/t/how-would-you-write-it-vs-smalltalk/115259/6 "2007-09-24T00:47:04Z")

</div>

Simon KrÃ¶ger wrote:

> Rick DeNatale schrieb:
> 
> > Here’s another way:
> > 
> > puts “Enter line:”  
> > h = Hash.new(0)  
> > gets.scan(/[a-zA-Z]/) {|ch| h[ch.downcase] += 1 }  
> > p h.sort
> 
> Well, we need an inject solution, right?
> 
> p gets.downcase.scan(/[a-z]/).inject({}){|h,c|  
> h.merge({c,h[c].to\_i+1})}.sort

How about:

p gets.downcase.scan(/[a-z]/).inject(Hash.new(0)){|h, c| h[c]+= 1;  
h}.sort

---

<div class="post-metadata">

**Author:** ![winterheat](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/w/7993a0/32.png) [@winterheat](https://www.ruby-forum.com/u/winterheat)\
**Post date:** [September 24, 2007, 3:58am UTC](https://www.ruby-forum.com/t/how-would-you-write-it-vs-smalltalk/115259/7 "2007-09-24T03:58:12Z")

</div>

7stud – wrote:

> And this seems conceptually easier and it’s slightly faster(if I  
> benchmarked it correctly):
> 
> input = gets  
> h = Hash.new(0)
> 
> input.scan(/[a-z]/){|char| h[char] += 1}  
> p h.sort

Whoops. I didn’t downcase the input in that example, but I did downcase  
the input in the benchmark tests. In any case, apologies to Rick  
Denatale who already posted that solution.

---

<div class="post-metadata">

**Author:** ![winterheat](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/w/7993a0/32.png) [@winterheat](https://www.ruby-forum.com/u/winterheat)\
**Post date:** [September 24, 2007, 6:10am UTC](https://www.ruby-forum.com/t/how-would-you-write-it-vs-smalltalk/115259/8 "2007-09-24T06:10:40Z")

</div>

On Sep 22, 2:39 pm, “Rick DeNatale” [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) wrote:

> Here’s another way:
> 
> puts “Enter line:”  
> h = Hash.new(0)  
> gets.scan(/[a-zA-Z]/) {|ch| h[ch.downcase] += 1 }  
> p h.sort

More verbose but a teensy bit quicker by avoiding regex & downcase:

lambda do |str|  
h = Hash.new(0)  
str.each\_byte do |b|  
if (b \> 96 && b \< 123)  
h[b.chr] += 1  
elsif (b \> 64 && b \< 91)  
h[(b+32).chr] += 1  
end  
end  
h  
end
