Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > Ruby > An elegant way...

Reply
Thread Tools

An elegant way...

 
 
F. Senault
Guest
Posts: n/a
 
      09-20-2010
Hello everybody.

I've written a method to solve a little problem, but I find my solution
really ugly. So, I'm trying to find ways to improve it.

The method takes one argument, an array containing a sorted list of
strings representing episodes numbers. The episodes numbers are either
a number ('1', '12') or prefixed with a letter ('S1' for special 1). My
goal is to find sequences in the numbers and join them with dashes :

>> RAniDBTools.format_episodes_list([ '1', '2', '3', '4', '6', '7', '9', 'S1', 'S2' ])

=> "1-4, 6-7, 9, S1-S2"
>> RAniDBTools.format_episodes_list([ '1', '2', 'S3', 'S4', 'S5', 'O6' ])

=> "1-2, S3-S5, O6"

Here's the code ; what can I do to improve this ?

module RAniDBTools
def RAniDBTools.format_episodes_list(list)
lt = []
le = []
list.each do |epno|
if ('0'..'9').include? epno[0,1]
t = ''
e = epno.to_i
else
t = epno[0..0]
e = epno[1..-1].to_i
end
if lt.last == t
max = le.last.max rescue le.last
min = le.last.min rescue le.last
if e == max + 1
le[-1] = (min..e)
else
le << e
lt << t
end
else
le << e
lt << t
end
end
f = []
le.each_with_index do |e, i|
if e.is_a? Range
f << "#{lt[i]}#{e.min}-#{lt[i]}#{e.max}"
else
f << "#{lt[i]}#{e}"
end
end
f.join(', ')
end
end

TIA,

Fred
--
This is the right time, once in a lifetime So I find it hard to sleep,
don't you know The sun is shining in my window, life's in flow Making
music in the morning, laughter's light Creativity touches in for flight
(The Corrs, The Right Time)
 
Reply With Quote
 
 
 
 
Jesús Gabriel y Galán
Guest
Posts: n/a
 
      09-20-2010
On Mon, Sep 20, 2010 at 7:10 PM, F. Senault <(E-Mail Removed)> wrote:
> Hello everybody.
>
> I've written a method to solve a little problem, but I find my solution
> really ugly. =A0So, I'm trying to find ways to improve it.
>
> The method takes one argument, an array containing a sorted list of
> strings representing episodes numbers. =A0The episodes numbers are either
> a number ('1', '12') or prefixed with a letter ('S1' for special 1). =A0M=

y
> goal is to find sequences in the numbers and join them with dashes :
>
>>> RAniDBTools.format_episodes_list([ '1', '2', '3', '4', '6', '7', '9', '=

S1', 'S2' ])
> =3D> "1-4, 6-7, 9, S1-S2"
>>> RAniDBTools.format_episodes_list([ '1', '2', 'S3', 'S4', 'S5', 'O6' ])

> =3D> "1-2, S3-S5, O6"
>
> Here's the code ; what can I do to improve this ?
>
> module RAniDBTools
> =A0def RAniDBTools.format_episodes_list(list)
> =A0 =A0lt =3D []
> =A0 =A0le =3D []
> =A0 =A0list.each do |epno|
> =A0 =A0 =A0if ('0'..'9').include? epno[0,1]
> =A0 =A0 =A0 =A0t =3D ''
> =A0 =A0 =A0 =A0e =3D epno.to_i
> =A0 =A0 =A0else
> =A0 =A0 =A0 =A0t =3D epno[0..0]
> =A0 =A0 =A0 =A0e =3D epno[1..-1].to_i
> =A0 =A0 =A0end
> =A0 =A0 =A0if lt.last =3D=3D t
> =A0 =A0 =A0 =A0max =3D le.last.max rescue le.last
> =A0 =A0 =A0 =A0min =3D le.last.min rescue le.last
> =A0 =A0 =A0 =A0if e =3D=3D max + 1
> =A0 =A0 =A0 =A0 =A0le[-1] =3D (min..e)
> =A0 =A0 =A0 =A0else
> =A0 =A0 =A0 =A0 =A0le << e
> =A0 =A0 =A0 =A0 =A0lt << t
> =A0 =A0 =A0 =A0end
> =A0 =A0 =A0else
> =A0 =A0 =A0 =A0le << e
> =A0 =A0 =A0 =A0lt << t
> =A0 =A0 =A0end
> =A0 =A0end
> =A0 =A0f =3D []
> =A0 =A0le.each_with_index do |e, i|
> =A0 =A0 =A0if e.is_a? Range
> =A0 =A0 =A0 =A0f << "#{lt[i]}#{e.min}-#{lt[i]}#{e.max}"
> =A0 =A0 =A0else
> =A0 =A0 =A0 =A0f << "#{lt[i]}#{e}"
> =A0 =A0 =A0end
> =A0 =A0end
> =A0 =A0f.join(', ')
> =A0end
> end


I have no time to propose a complete solution. I'll leave to you
adding the "Sx" and "Ox" processing. This is how I'd do it it they
were all numbers:

irb(main):004:0> list =3D [1,2,3,4,6,7,9,16,17]
=3D> [1, 2, 3, 4, 6, 7, 9, 16, 17]
irb(main):018:0> result =3D [[list.first]]
=3D> [[1]]
irb(main):023:0> list.each_cons(2) do |x,y|
irb(main):024:1* if (x+1) =3D=3D y
irb(main):025:2> result.last << y
irb(main):026:2> else
irb(main):027:2* result << [y]
irb(main):028:2> end
irb(main):029:1> end
=3D> nil
irb(main):030:0> result
=3D> [[1, 2, 3, 4], [6, 7], [9], [16, 17]]
irb(main):031:0> s =3D ""
=3D> ""
irb(main):034:0> res =3D result.map {|x| x.size =3D=3D 1 ? x.to_s :
"#{x.first}-#{x.last}"}
=3D> ["1-4", "6-7", "9", "16-17"]
irb(main):035:0> res.join(",")
=3D> "1-4,6-7,9,16-17"

For the other stuff, I would have a flag that tells me if I'm in the
middle of a number, "S" or "O" run, and act accordingly.

Hope this helps,

Jesus.

 
Reply With Quote
 
 
 
 
James Edward Gray II
Guest
Posts: n/a
 
      09-20-2010
On Sep 20, 2010, at 12:10 PM, F. Senault wrote:

> The method takes one argument, an array containing a sorted list of
> strings representing episodes numbers. The episodes numbers are =

either
> a number ('1', '12') or prefixed with a letter ('S1' for special 1). =

My
> goal is to find sequences in the numbers and join them with dashes :
>=20
>>> RAniDBTools.format_episodes_list([ '1', '2', '3', '4', '6', '7', =

'9', 'S1', 'S2' ])
> =3D> "1-4, 6-7, 9, S1-S2"
>>> RAniDBTools.format_episodes_list([ '1', '2', 'S3', 'S4', 'S5', 'O6' =

])
> =3D> "1-2, S3-S5, O6"


Dave Thomas and I were playing around with an idea like this recently:

http://gist.github.com/570434

http://gist.github.com/570556

I hope those give you some fresh ideas.

James Edward Gray II=

 
Reply With Quote
 
brabuhr@gmail.com
Guest
Posts: n/a
 
      09-20-2010
On Mon, Sep 20, 2010 at 1:10 PM, F. Senault <(E-Mail Removed)> wrote:
> The method takes one argument, an array containing a sorted list of
> strings representing episodes numbers. =A0The episodes numbers are either
> a number ('1', '12') or prefixed with a letter ('S1' for special 1). =A0M=

y
> goal is to find sequences in the numbers and join them with dashes :
>
>>> RAniDBTools.format_episodes_list([ '1', '2', '3', '4', '6', '7', '9', '=

S1', 'S2' ])
> =3D> "1-4, 6-7, 9, S1-S2"
>>> RAniDBTools.format_episodes_list([ '1', '2', 'S3', 'S4', 'S5', 'O6' ])

> =3D> "1-2, S3-S5, O6"
>
> Here's the code ; what can I do to improve this ?


I wouldn't call this an improvement:

def format_episodes_list a
z =3D []
z << a.inject([""]){|i,j| i.last.succ=3D=3Dj ? i << j : (z << i ; [j])}
z[1..-1].map{|b| b.size=3D=3D1?b:"#{b.first}-#{b.last}"}.join(", ")
end

puts format_episodes_list([ '1', '2', '3', '4', '6', '7', '9', 'S1', 'S2' ]=
)
#=3D> 1-4, 6-7, 9, S1-S2
puts format_episodes_list([ '1', '2', 'S3', 'S4', 'S5', 'O6' ])
#=3D> 1-2, S3-S5, O6
puts format_episodes_list([ '1', '2', '9', '10', 'S9', 'S10' ])
#=3D> 1-2, 9-10, S9, S10

(And, I'm guessing that the last one there isn't correct

 
Reply With Quote
 
Joel VanderWerf
Guest
Posts: n/a
 
      09-20-2010
On 09/20/2010 10:10 AM, F. Senault wrote:
> Hello everybody.
>
> I've written a method to solve a little problem, but I find my solution
> really ugly. So, I'm trying to find ways to improve it.
>
> The method takes one argument, an array containing a sorted list of
> strings representing episodes numbers. The episodes numbers are either
> a number ('1', '12') or prefixed with a letter ('S1' for special 1). My
> goal is to find sequences in the numbers and join them with dashes :


a = [ '1', '2', 'S3', 'S4', 'S5', 'O6' ]

r0 = nil
r1 = nil
result = []

a.each_cons 2 do |prev, s|
case s
when prev.succ
r0 ||= prev
r1 = s
else
if r0
result << "#{r0}-#{r1}"
else
result << prev
end
r0 = r1 = nil
end
end

if r0
result << "#{r0}-#{r1}"
else
result << a.last
end

p result # ==> ["1-2", "S3-S5", "O6"]


 
Reply With Quote
 
Adam Prescott
Guest
Posts: n/a
 
      09-20-2010
Rushed and probably full of horribleness, but it's something, I suppose:

http://gist.github.com/588341

 
Reply With Quote
 
Joel VanderWerf
Guest
Posts: n/a
 
      09-20-2010
On 09/20/2010 11:06 AM, Joel VanderWerf wrote:
> ...


Refactoring that:

a = [ '1', '2', '3', '4', '6', '7', '9', 'S1', 'S2', "10", "11", "12" ]
#a = [ '1', '2', 'S3', 'S4', 'S5', 'O6' ]

module Enumerable
def each_run(cond)
run = nil
last = nil

each_cons 2 do |prev, s|
if cond[prev, s]
run ||= [prev]
run << s
else
yield run || prev
run = nil
end
last = s
end

yield run || [last]

self
end

end

result = []

a.each_run(proc {|prev, s| prev.succ == s}) do |run|
if run.size > 1
result << "#{run.first}-#{run.last}"
else
result << run.first
end
end

p result


 
Reply With Quote
 
F. Senault
Guest
Posts: n/a
 
      09-20-2010
Le 20 septembre ŕ 19:38, Jesús Gabriel y Galán a écrit :

/.../

> I have no time to propose a complete solution. I'll leave to you
> adding the "Sx" and "Ox" processing. This is how I'd do it it they
> were all numbers:


> irb(main):023:0> list.each_cons(2) do |x,y|


Ahha ! each_cons...

> irb(main):024:1* if (x+1) == y
> irb(main):025:2> result.last << y
> irb(main):026:2> else
> irb(main):027:2* result << [y]
> irb(main):028:2> end
> irb(main):029:1> end


M'kay. My current iteration looks like this :

def RAniDBTools.format_episodes_list(list)
list.group_by { |e| ('A'..'Z') === e[0,1] ? e[0,1] : '' }.collect do |p, l|
l = l.map { |e| e.gsub(/^[A-Z]/, '').to_i }
format_consecutive_numbers(p, l)
end.join(", ")
end

(I'd definitely need a group_and_map function here.)

def RAniDBTools.format_consecutive_numbers(prefix, list)
result = [[ list.first ]]
list.each_cons(2) do |x, y|
if y == x + 1
result.last << y
else
result << [ y ]
end
ends
result.map { |x| "#{prefix}#{x.first}" + (x.size == 1 ? "" : "-#{prefix}#{x.last}") }.join(", ")
end

Better ! I'm still reading the other answers in the thread, though...

Thanks a lot for the ideas !
s
Fred
--
If I don't think about the fact that she left me,
If I don't see the pearls fall from the sky,
If I don't hear the accusations of blasphemy,
If I don't feel the tears in my eyes,
This is the best day of my life. (Prince, 3 chains o' gold)
 
Reply With Quote
 
F. Senault
Guest
Posts: n/a
 
      09-20-2010
Le 20 septembre ŕ 20:17, Joel VanderWerf a écrit :

> a.each_run(proc {|prev, s| prev.succ == s}) do |run|


There's a catch with succ :

>> "S9".succ

=> "T0"

Definitely not what I want !

Fred
--
You ask me if I've known love
And what it's like to sing songs in the rain Well, I've seen love come
And I've seen it shot down I've seen it die in vain
Shot down in a blaze of glory (Bon Jovi, Blaze of Glory)
 
Reply With Quote
 
F. Senault
Guest
Posts: n/a
 
      09-20-2010
Le 20 septembre ŕ 19:44, James Edward Gray II a écrit :

> Dave Thomas and I were playing around with an idea like this recently:
>
> http://gist.github.com/570434
>
> http://gist.github.com/570556
>
> I hope those give you some fresh ideas.


Where does the slice_before method comes from ?

(Anyways, seeing your comment on the first bit of code, I think I should
use inject in my refactored form... probably...)

Fred
--
When I'm nice, people think I'm up to something and start sending me
bombs in the mail.
(Mike, CRFH - http://www.crfh.net/)
 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
Re: Is there an elegant way to set an unsigned vector to 1 Jan De Ceuster VHDL 5 01-13-2005 07:26 AM
Elegant algorithm. Vladimir ASP .Net 0 07-31-2004 05:51 PM
Any elegant solution for managing upload file size? Braky Wacky ASP .Net 8 07-15-2004 08:19 PM
More Elegant Column Widths in ASP:Table Objects? =?Utf-8?B?QWxleCBNYWdoZW4=?= ASP .Net 1 05-14-2004 07:38 PM
Elegant way of returning FieldNames? Jay Balapa ASP .Net 1 08-07-2003 10:25 PM



Advertisments