[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.ruby

Split a string based on change of character

Andrew Savige

8/11/2007 12:52:00 AM

For a string "ZBBBCZZ", I want to produce a list ["Z", "BBB", "C", "ZZ"]
That is, break the string into pieces based on change of character.

Though this works:

s = "ZBBBCZZ"
x = s.scan(/((.)\2*)/).map {|i| i[0]}

I'm new to Ruby and am interested to learn if there is a better way to
do it.

BTW, in Python, it can be done with a regex (similar to above) or via
their itertools library:

import itertools
s = "ZBBBCCZZ"
x = [''.join(g) for k, g in itertools.groupby(s)]

Does anyone know if Ruby has a similar library to Python's itertools?

Thanks,
/-



____________________________________________________________________________________
Sick of deleting your inbox? Yahoo!7 Mail has free unlimited storage.
http://au.docs.yahoo.com/mail/unlimitedst...

22 Answers

Peña, Botp

8/11/2007 3:55:00 AM

0

From: Andrew Savige [mailto:ajsavige@yahoo.com.au]
# s = "ZBBBCZZ"
# x = s.scan(/((.)\2*)/).map {|i| i[0]}

when it comes to string patterns like this, nothing beats regex

# import itertools
# s = "ZBBBCCZZ"
# x = [''.join(g) for k, g in itertools.groupby(s)]
# Does anyone know if Ruby has a similar library to Python's itertools?

hmm, you seem to like this than your previous regex+map solution, why? (i ask because i prefer your first solution --not that it's ruby)

in 1.9 or the upcoming ruby, it keeps getting better and better and may look like this,

s = "ZBBBCZZ"
x = s.split('').group_by{|x| x}.entries

or possibly to

x = s.split('').group_by.entries

but unfortunately i don't have a 1.9 build here to test (grrr, shouldn't have deleted that vm).

kind regards -botp

Jeremy Hinegardner

8/11/2007 9:13:00 AM

0

On Sat, Aug 11, 2007 at 09:52:24AM +0900, Andrew Savige wrote:
> For a string "ZBBBCZZ", I want to produce a list ["Z", "BBB", "C", "ZZ"]
> That is, break the string into pieces based on change of character.
>
> Though this works:
>
> s = "ZBBBCZZ"
> x = s.scan(/((.)\2*)/).map {|i| i[0]}
>
> I'm new to Ruby and am interested to learn if there is a better way to
> do it.
>
> BTW, in Python, it can be done with a regex (similar to above) or via
> their itertools library:
>
> import itertools
> s = "ZBBBCCZZ"
> x = [''.join(g) for k, g in itertools.groupby(s)]
>
> Does anyone know if Ruby has a similar library to Python's itertools?

Nothing off the top of my head, but how does this work for you ?

in_str.split('').inject([]) do |m,l|
if m.last and m.last[0].chr == l
m[-1] += l
else
m << l
end
m
end

Its not too lines, but it will return the same array

enjoy

-jeremy

--
========================================================================
Jeremy Hinegardner jeremy@hinegardner.org


Wolfgang Nádasi-donner

8/11/2007 9:28:00 AM

0

Andrew Savige wrote:
> s = "ZBBBCZZ"
> x = s.scan(/((.)\2*)/).map {|i| i[0]}

Maybe this ist faster:

result = []
"ZBBBCZZ".scan(/((.)\2*)/){erg.push [$~[0]]}
p erg # => [["Z"], ["BBB"], ["C"], ["ZZ"]]

Wolfgang Nádasi-Donner
--
Posted via http://www.ruby-....

Wolfgang Nádasi-donner

8/11/2007 9:29:00 AM

0


> Maybe this ist faster:
>
> result = []
> "ZBBBCZZ".scan(/((.)\2*)/){erg.push [$~[0]]}
> p erg # => [["Z"], ["BBB"], ["C"], ["ZZ"]]
>
> Wolfgang Nádasi-Donner

result = []
"ZBBBCZZ".scan(/((.)\2*)/){result.push [$~[0]]}
p erg # => [["Z"], ["BBB"], ["C"], ["ZZ"]]

Sorry - typo by translation of variable name :-(

Wolfgang Nádasi-Donner
--
Posted via http://www.ruby-....

Simon Kröger

8/11/2007 9:56:00 AM

0

Andrew Savige schrieb:
> For a string "ZBBBCZZ", I want to produce a list ["Z", "BBB", "C", "ZZ"]
> That is, break the string into pieces based on change of character.
>
> Though this works:
>
> s = "ZBBBCZZ"
> x = s.scan(/((.)\2*)/).map {|i| i[0]}

you may want to write it as ...map{|i,|i}

> I'm new to Ruby and am interested to learn if there is a better way to
> do it.
>
> BTW, in Python, it can be done with a regex (similar to above) or via
> their itertools library:
>
> import itertools
> s = "ZBBBCCZZ"
> x = [''.join(g) for k, g in itertools.groupby(s)]
> Does anyone know if Ruby has a similar library to Python's itertools?


No idea, here is another variant to play with:

x = /#{s.gsub(/(.)\1*/, '(\1+)')}/.match(s).captures

funny little problem.

cheers

Simon

David A. Black

8/11/2007 12:44:00 PM

0

David A. Black

8/11/2007 1:15:00 PM

0

Xavier Noria

8/11/2007 1:40:00 PM

0

On Aug 11, 2007, at 2:52 AM, Andrew Savige wrote:

> For a string "ZBBBCZZ", I want to produce a list ["Z", "BBB", "C",
> "ZZ"]
> That is, break the string into pieces based on change of character.
>
> Though this works:
>
> s = "ZBBBCZZ"
> x = s.scan(/((.)\2*)/).map {|i| i[0]}

Yeah, it's short but I agree with things you dislike about it. My
approach was essentially the same as Jeremy's;

s.split(//).inject([]) {|g, c| (g.last && g.last[c] ? g.last : g)
<< c; g}

That's just playing around though, I think that approach is not better.

In my view a better idiom would be to split on character switches.
That would be concise. But as you know if you put groups you get them
back. I see no way to express the condition for boundaries without
using groups.

-- fxn


James Gray

8/11/2007 4:24:00 PM

0

On Aug 11, 2007, at 8:14 AM, dblack@rubypal.com wrote:

> Hi --
>
> On Sat, 11 Aug 2007, Andrew Savige wrote:
>
>> For a string "ZBBBCZZ", I want to produce a list ["Z", "BBB", "C",
>> "ZZ"]
>> That is, break the string into pieces based on change of character.
>>
>> Though this works:
>>
>> s = "ZBBBCZZ"
>> x = s.scan(/((.)\2*)/).map {|i| i[0]}
>>
>> I'm new to Ruby and am interested to learn if there is a better
>> way to
>> do it.
>
> Probably not better, but just for fun, here's a way using the strscan
> extension. I'd be very interested if anyone can get this to be less
> clunky -- in particular, the - [""] at the end.
>
> require 'strscan'
> s = StringScanner.new("AABCCCDAAAEE")
>
> s.string.split(//).inject([]) {|a,b| a << s.scan_until(/(?!#
> {b})/) } - [""]
>
> => ["AA", "B", "CCC", "D", "AAA", "EE"]

My best effort:

>> require "strscan"
=> true
>> scanner = StringScanner.new("ZBBBCZZ")
=> #<StringScanner 0/7 @ "ZBBBC...">
>> char_runs = Array.new
=> []
>> char_runs << scanner.matched while scanner.scan(/(.)\1*/m)
=> nil
>> char_runs
=> ["Z", "BBB", "C", "ZZ"]

James Edward Gray II


botp

8/11/2007 5:00:00 PM

0

On 8/11/07, dblack@rubypal.com <dblack@rubypal.com> wrote:
> > s = "ZBBBCZZ"
> > x = s.split('').group_by{|x| x}.entries
> >
> > or possibly to
> >
> > x = s.split('').group_by.entries
>
> I'm going to have to get special glasses that can read invisible
> ink.... :-)

whoops, sorry =)
that should be

fr
x = s.split('').group_by{|x| x}.entries.map{|x| x.join}

to
x = s.split('').group_by.entries.map{|x| x.join}

i assume that group_by without a block would group the elements by
themselves. maybe i should name it group not group_by :)

kind regards -botp