All occurances of a character in a string

R

Raghu Go

Hi - I am trying to figure out the ruby way of printing all occurances
of a character in a string..

The index method on string gives only the first occurance only.

Example input string - abbccdaab
desired output - 'a' = 0 6 7
'b' = 1 2 8
'c' = 3 4
'd' = 5

Any help greatly appreciated..
 
P

Peter Szinek

[Note: parts of this message were removed to make it a legal post.]

Hi Raghu

My 2-minute horrible-hack(tm):

input = "abbccdaab"
i = 0;
input.split('').inject({}) {|a,v| a[v] = a[v] ? (a[v] <<
input[i..-1].index(v)+i) : [input[i..-1].index(v)+i]; i+=1; a}

{"a"=>[0, 6, 7], "b"=>[1, 2, 8], "c"=>[3, 4], "d"=>[5]}

I am sure there has to be a *MUCH* nicer way though, because this is
rather ugly...

Cheers,
Peter
___
http://www.rubyrailways.com
http://scrubyt.org
 
S

Siep Korteling

S2 said:
S2 said:
irb(main):006:1>   ret[c] = ret[c].nil? ? d : d << ret[c]
irb(main):007:1>   ret[c].flatten!

oh sorry, here are a few things that are not needed:
a = "abbccdaab"
i = 0
ret = Hash.new
a.scan(/./) {|c|
ret[c] = ret[c].nil? ? : ret[c] << i
i = i + 1
}
p a
p ret


The block form of Hash.new gets rid of the if-statement; like this:

str = "abbccdaab"
ar = str.split("")
result = Hash.new{Array.new}

ar.each_with_index do|item,index|
result[item] = result[item]<<index
end

result.each{|k,v| puts k + " = " + v.join(",")}

regards,

Siep
 
R

Raghu Go

I did a quick test and like Siep's modifications..

Method1 Time elapsed: 0.236999988555908 milliseconds

Siep's modification Method2 Time elapsed: 0.123999834060669 milliseconds


def method1(a)
i = 0
ret = Hash.new
a.scan(/./) {|c|
ret[c] = ret[c].nil? ? : ret[c] << i
i = i + 1
}
p a
p ret
end

def method2(str) #Siep
ar = str.split("")
result = Hash.new{Array.new}

ar.each_with_index do|item,index|
result[item] = result[item]<<index
end
result.each{|k,v| puts k + " = " + v.join(",")}
end

Siep said:
S2 said:
S2 said:
irb(main):006:1> ret[c] = ret[c].nil? ? d : d << ret[c]
irb(main):007:1> ret[c].flatten!

oh sorry, here are a few things that are not needed:
a = "abbccdaab"
i = 0
ret = Hash.new
a.scan(/./) {|c|
ret[c] = ret[c].nil? ? : ret[c] << i
i = i + 1
}
p a
p ret


The block form of Hash.new gets rid of the if-statement; like this:

str = "abbccdaab"
ar = str.split("")
result = Hash.new{Array.new}

ar.each_with_index do|item,index|
result[item] = result[item]<<index
end

result.each{|k,v| puts k + " = " + v.join(",")}

regards,

Siep
 
D

David A. Black

Hi --

Hi - I am trying to figure out the ruby way of printing all occurances
of a character in a string..

The index method on string gives only the first occurance only.

Example input string - abbccdaab
desired output - 'a' = 0 6 7
'b' = 1 2 8
'c' = 3 4
'd' = 5

Any help greatly appreciated..

I have this really strong feeling that there's a really easy way, but
I can't think of it or find it. Meanwhile, if you're using 1.9 you
could do something like:

str = "abcdbcdae"

h = Hash.new {|h,k| h[k] = [] }
str.each_char.map.with_index {|char, i| h[char] << i }

which would put a hash of results in h.

I just have this hunch that there was a way to accumulate offsets from
a scan or gsub operation, but I can't come up with it.


David

--
Rails training from David A. Black and Ruby Power and Light:
INTRO TO RAILS June 9-12 Berlin
ADVANCING WITH RAILS June 16-19 Berlin
INTRO TO RAILS June 24-27 London (Skills Matter)
See http://www.rubypal.com for details and updates!
 
R

Robert Klemme

Hi --

Hi - I am trying to figure out the ruby way of printing all occurances
of a character in a string..

The index method on string gives only the first occurance only.

Example input string - abbccdaab
desired output - 'a' = 0 6 7
'b' = 1 2 8
'c' = 3 4
'd' = 5

Any help greatly appreciated..

I have this really strong feeling that there's a really easy way, but
I can't think of it or find it. Meanwhile, if you're using 1.9 you
could do something like:

str = "abcdbcdae"

h = Hash.new {|h,k| h[k] = [] }
str.each_char.map.with_index {|char, i| h[char] << i }

which would put a hash of results in h.

In 1.8

irb(main):001:0> require 'enumerator'
=> true
irb(main):002:0> str = "abcdbcdae"
=> "abcdbcdae"
irb(main):003:0> ind = Hash.new {|h,k| h[k]=[]}
=> {}
irb(main):004:0> str.to_enum:)scan,/./).each_with_index {|c,i|ind[c]<<i}
=> #<Enumerable::Enumerator:0x7ff75768>
irb(main):005:0> ind
=> {"a"=>[0, 7], "b"=>[1, 4], "c"=>[2, 5], "d"=>[3, 6], "e"=>[8]}
I just have this hunch that there was a way to accumulate offsets from
a scan or gsub operation, but I can't come up with it.

Like this?

irb(main):017:0> str = "abcdbcdae"
=> "abcdbcdae"
irb(main):018:0> ind = Hash.new {|h,k| h[k]=[]}
=> {}
irb(main):019:0> str.scan(/./) {|c| ind[c] << $`.length}
=> "abcdbcdae"
irb(main):020:0> ind
=> {"a"=>[0, 7], "b"=>[1, 4], "c"=>[2, 5], "d"=>[3, 6], "e"=>[8]}

Cheers

robert
 
D

David A. Black

Hi --

Hi --

Hi - I am trying to figure out the ruby way of printing all occurances
of a character in a string..

The index method on string gives only the first occurance only.

Example input string - abbccdaab
desired output - 'a' = 0 6 7
'b' = 1 2 8
'c' = 3 4
'd' = 5

Any help greatly appreciated..

I have this really strong feeling that there's a really easy way, but
I can't think of it or find it. Meanwhile, if you're using 1.9 you
could do something like:

str = "abcdbcdae"

h = Hash.new {|h,k| h[k] = [] }
str.each_char.map.with_index {|char, i| h[char] << i }

which would put a hash of results in h.

In 1.8

irb(main):001:0> require 'enumerator'
=> true
irb(main):002:0> str = "abcdbcdae"
=> "abcdbcdae"
irb(main):003:0> ind = Hash.new {|h,k| h[k]=[]}
=> {}
irb(main):004:0> str.to_enum:)scan,/./).each_with_index {|c,i|ind[c]<<i}
=> #<Enumerable::Enumerator:0x7ff75768>
irb(main):005:0> ind
=> {"a"=>[0, 7], "b"=>[1, 4], "c"=>[2, 5], "d"=>[3, 6], "e"=>[8]}
I just have this hunch that there was a way to accumulate offsets from
a scan or gsub operation, but I can't come up with it.

Like this?

irb(main):017:0> str = "abcdbcdae"
=> "abcdbcdae"
irb(main):018:0> ind = Hash.new {|h,k| h[k]=[]}
=> {}
irb(main):019:0> str.scan(/./) {|c| ind[c] << $`.length}
=> "abcdbcdae"
irb(main):020:0> ind
=> {"a"=>[0, 7], "b"=>[1, 4], "c"=>[2, 5], "d"=>[3, 6], "e"=>[8]}

It may well have been that, or something like it.


David

--
Rails training from David A. Black and Ruby Power and Light:
INTRO TO RAILS June 9-12 Berlin
ADVANCING WITH RAILS June 16-19 Berlin
INTRO TO RAILS June 24-27 London (Skills Matter)
See http://www.rubypal.com for details and updates!
 
L

Lee Jarvis

I apologise for the complete ugliness of this code :)

Look away of you're screamish!

ARGV.to_s.split(/\s*/).map{|x|x.downcase}.inject(Hash.new(0)){|h,x|h[x]
+=1 and h}.each{|i,h| print "#{i}(#{h}), "}

Foobar, output:

a(1), b(1), o(2), f(1), r(1)
 
L

Lee Jarvis

Whoops, I didn't read the question properly, this prints all
occurances, not positions..
 
H

Harry Kakueki

Hi - I am trying to figure out the ruby way of printing all occurances
of a character in a string..

The index method on string gives only the first occurance only.

Example input string - abbccdaab
desired output - 'a' = 0 6 7
'b' = 1 2 8
'c' = 3 4
'd' = 5

Any help greatly appreciated..

Here is one way.

arr = "abbccdaab".split(//)
arr.uniq.each do |s|
res = []
(0...arr.length).each {|x| res << x if arr[x] =~ /#{s}/}
p s, res
end

Harry
 
A

Adam Shelly

I thought of the 'indexes' method, but that works in reverse. So I
made my own version:

class Array
def all_indexes val
(0..length).map{|i|self==val ? i : nil}.compact
end
alias :all_indicies :all_indexes
end

p 'hello world'.split('').all_indicies('l')

=> [2, 3, 9]

Source = 'abbccdaab'
s=Source.split('')
s.uniq.each{|v| puts "'#{v}' = #{s.all_indexes(v)*' '}"}

=> 'a' = 0 6 7
'b' = 1 2 8
'c' = 3 4
'd' = 5


-Adam
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,744
Messages
2,569,482
Members
44,901
Latest member
Noble71S45

Latest Threads

Top