![]() |
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) |
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. |
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= |
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 :-) |
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"] |
Re: An elegant way...
Rushed and probably full of horribleness, but it's something, I suppose:
http://gist.github.com/588341 |
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 |
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) |
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) |
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 12:08 AM. |
Powered by vBulletin®. Copyright ©2000 - 2013, vBulletin Solutions, Inc.
SEO by vBSEO ©2010, Crawlability, Inc.