Velocity Reviews

Velocity Reviews (http://www.velocityreviews.com/forums/index.php)
-   Ruby (http://www.velocityreviews.com/forums/f66-ruby.html)
-   -   An elegant way... (http://www.velocityreviews.com/forums/t864502-an-elegant-way.html)

F. Senault 09-20-2010 05:09 PM

An elegant way...
 
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)

Jesús Gabriel y Galán 09-20-2010 05:38 PM

Re: An elegant way...
 
On Mon, Sep 20, 2010 at 7:10 PM, F. Senault <fred@lacave.net> 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.


James Edward Gray II 09-20-2010 05:44 PM

Re: An elegant way...
 
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=


brabuhr@gmail.com 09-20-2010 06:05 PM

Re: An elegant way...
 
On Mon, Sep 20, 2010 at 1:10 PM, F. Senault <fred@lacave.net> 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 :-)


Joel VanderWerf 09-20-2010 06:06 PM

Re: An elegant way...
 
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"]



Adam Prescott 09-20-2010 06:11 PM

Re: An elegant way...
 
Rushed and probably full of horribleness, but it's something, I suppose:

http://gist.github.com/588341


Joel VanderWerf 09-20-2010 06:17 PM

Re: An elegant way...
 
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



F. Senault 09-20-2010 06:38 PM

Re: An elegant way...
 
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)

F. Senault 09-20-2010 06:40 PM

Re: An elegant way...
 
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)

F. Senault 09-20-2010 06:43 PM

Re: An elegant way...
 
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/)


All times are GMT. The time now is 01:16 AM.

Powered by vBulletin®. Copyright ©2000 - 2014, vBulletin Solutions, Inc.
SEO by vBSEO ©2010, Crawlability, Inc.