I have been scouring the documentation for ages and have also googled
everything I can think of (e.g. Array#split) to try and find a solution,
but with no luck.
Can anyone point me in the right direction.
I am grateful for any help.
Well this is different, but I’m not sure it’s better.
I suspect your version may be more robust (or at least easier to fix) if
the
data doesn’t end with a String (month).
ary_new = []
ii = 0
ary.each_with_index do |ee, jj|
if ee.kind_of?( String ) then
ary_new << ee
(ii … (jj - 1)).each { |i| ary_new << ary[ i ] }
ii = jj + 1
end
end
ary.replace( ary_new )
Is there any way to reverse this so that the months precede the
Can anyone point me in the right direction.
I am grateful for any help.
I would chose different data structures: if your events have a month
where they are scheduled I would make the month an attribute of Event.
Then you can sort your Event instances according to any criteria you
like - including month. Mixing types in a collection can make handling
that collection quite complex - as you are experiencing.
Borrowing from ActiveSupport’s Array#split (I modified it to keep the
token on which we split as part of the previous group, and also to
remove the last group if it’s empty):
irb(main):093:0> Event = Struct.new :id
=> Event
irb(main):094:0> a = [Event[1], Event[2], “MARCH”, Event[3], Event[4],
“FEBRUARY”, Event[5], “JANUARY”]
=> [#, #, “MARCH”, #, #, “FEBRUARY”, #,
“JANUARY”]
irb(main):095:0> class Array
irb(main):096:1> def split(&block)
irb(main):097:2> res = inject([[]]) do |results, element|
irb(main):098:3* if block.call(element)
irb(main):099:4> results.last << element
irb(main)4> results << []
irb(main):101:4> else
irb(main):102:4* results.last << element
irb(main):103:4> end
irb(main):104:3> results
irb(main):105:3> end
irb(main):106:2> res.pop if res.last.empty?
irb(main):107:2> res
irb(main):108:2> end
irb(main):109:1> end
=> nil
irb(main):111:0> a.split {|o| o.kind_of? String}.each {|m| el = m.pop;
m.unshift el}.flatten
=> [“MARCH”, #, #, “FEBRUARY”,
#, #, “JANUARY”, #]
First of all, thank you very much for the replies.
In the mean time I have managed to hack together a small function to do
what I want, but it is too embarrassingly bad to post here and I used
one of the other proposed solutions instead.
I agree that a different data structure would be much less cumbersome,
but I wouldn’t know which. What I’m doing is parsing a html document (a
calendar) into an array, and using that array to create widgets in a
FXRuby GUI. The month names serve as the title of a label and out of the
Event objects I then create the appropriate text fields, labels and
group boxes for each event. As a month can have multiple events I found
it easier to do it this way, as otherwise I would have to find some way
of ordering events to month names, which at first glance seemed pretty
complicated.
If anyone has any suggestions of a better way to approach this problem,
I would be very glad to hear them.
FXRuby GUI. The month names serve as the title of a label and out of the
Event objects I then create the appropriate text fields, labels and
group boxes for each event. As a month can have multiple events I found
it easier to do it this way, as otherwise I would have to find some way
of ordering events to month names, which at first glance seemed pretty
complicated.
If anyone has any suggestions of a better way to approach this problem,
I would be very glad to hear them.
Thanks for your help so far.
I agree with both Robert and Daniel. I would make the month a field of
the Event, so you can query it, order events by month, etc. And then I
would also go with Daniel’s suggestion of having a hash indexed by
month so you can get at the set of events for a month easily when you
need it (for example, when the user clicks on Next Month).
I have been scouring the documentation for ages and have also googled
everything I can think of (e.g. Array#split) to try and find a solution,
but with no luck.
If your Event has an accessor which shows the month of that object as a
String, then you could do something like this:
However, a heterogenous (mixed) list is not a convenient data structure
to work with, as you’ve probably found. There may be a better way to
group this data, depending on what you plan to do with it. For example,
you could build a hash of
month => [array of events for that month].
or a nested array of
[[month, [events]], [month, [events]], … ]
Thanks again for all of the helpful answers.
Every time I post a question here I always end up learning a lot.
Anyway, I took the advice offered and rewrote my program to improve my
data structure.
I now have a list of Month objects which have a date attribute that they
can be sorted by. A Month object can contain an arbitrary amount of
Event objects.
This works a lot better with less code (not surprisingly!)
If you’ve ever read “Real Programmers don’t use Pascal” (see Real Programmers Don't Use PASCAL - CodeProject ) you’ll know that
“Determined Real Programmers can write Fortran programs in any language”
Just because you’re a Ruby programmer you don’t have to use all that OO
stuff.
This algorithm picks out the first label and moves it into a new space
on the left, and then moves the second label to where the first was and
so on. Lastly it removes the vacated slot on the right:
I guess determined programmers can write VB programs in any language.
No fair. Any VB code looks almost, but not entirely, completely unlike
proper code.
–
Phillip G.
Though the folk I have met,
(Ah, how soon!) they forget
When I’ve moved on to some other place,
There may be one or two,
When I’ve played and passed through,
Who’ll remember my song or my face.
If you’ve ever read “Real Programmers don’t use Pascal” (see Real Programmers Don't Use PASCAL - CodeProject ) you’ll know that
“Determined Real Programemrs can write Fortran programs in any language”
Just because you’re a Ruby programmer you don’t have to use all that OO
stuff.
How can you use ruby without “all that OO stuff”? That’s one of the
main attractions.
I believe the program I wrote whilst not typical of Ruby programs is
quicker to understand than the more dense solutions given by others -
and that’s important in programming.
For all the people on here deciding now to ditch heavy OO and switch to
the more modern easy-going procedural style of Ruby, I would point out
that using globals is called ‘common coupling’ and frowned upon versus
‘normal coupling’ where you pass variable as method arguments.
You’re free to abuse the language however you like. I raised a
somewhat dubious eye to your practices, but YMYR. (Your machine your
rules)
I’d argue you’re not a Ruby programmer, and you’ve missed the whole
point of
Ruby, if you’re using that many globals.
As I relayed previously on this channel, I was introduced to Ruby by
Ulrika (about five years ago). On an old laptop I found one of her
programs, and it was written in a simple style with lots of globals. It
just seemed so dead easy to understand.
I believe the program I wrote whilst not typical of Ruby programs is
quicker to understand than the more dense solutions given by others -
and that’s important in programming.
For all the people on here deciding now to ditch heavy OO and switch to
the more modern easy-going procedural style of Ruby, I would point out
that using globals is called ‘common coupling’ and frowned upon versus
‘normal coupling’ where you pass variables as method arguments.
If you’ve ever read “Real Programmers don’t use Pascal” (see Real Programmers Don't Use PASCAL - CodeProject ) you’ll know that
“Determined Real Programemrs can write Fortran programs in any language”
Just because you’re a Ruby programmer you don’t have to use all that OO
stuff.
That’s true. However, I would add that the choice of language does not
determine the algorithm to use nor how it is implemented. We’ll come to
that in a minute.
This algorithm picks out the first label and moves it into a new space
on the left, and then moves the second label to where the first was and
so on. Lastly it removes the vacated slot on the right:
Here we see the first indication of a bad implementation: the number of
labels is encoded in the algorithm. You cannot use that program with
other than three labels. Even worse, the exact labels are hard coded
into the program. In other words, your program is overly dependent on
the input, or - put differently - your program is not very general and
poses too many restrictions on the input.
Here you are clearly cheating: you use “all that OO stuff”. Even worse,
by using Array#index you are hiding the fact that you traverse the input
Array far more often than necessary.
Actually I cheated there as I enclosed the #strings in quotes. Anyone
know how to deal with #s?
If you want to make the point that using Ruby does not necessitate the
usage of “all this OO stuff” a better program (i.e. one that at least
avoids issues raised so far) would certainly have given your argument
more strength.
I believe the program I wrote whilst not typical of Ruby programs is
quicker to understand than the more dense solutions given by others -
and that’s important in programming.
Well, then compare that to the version below. I claim that it uses
(mostly) procedural style and yet is easier to read and understand than
your version.
test whether the given element is a month label
def is_label(o)
String === o
end
exchange values at positions
def swap(arr, i, j)
not using parrallel assignment since
we want to avoid all the fancy stuff
x = arr[i]
arr[i] = arr[j]
arr[j] = x
end
Input: array with Events followed by month
Output: number of events without month at end
Side effect: months precede their Events
def realign_months(arr)
start = 0
i = 0
while i < arr.length
if is_label(arr[i])
# swap label and first
swap(arr, i, start)
# remember begin of next section
start = i + 1
end
i += 1
if remainder > 0
$stderr.puts “Last #{remainder} events are misaligned”
end
I would readily admit that it does not exactly do the same thing as your
program. You can find this version and a version that maintains
original element ordering (such as your version does) here:
It’s a great pleasure to welcome a new member of the Procedural Ruby
Club! Well done - your program was very nice although a bit nearer to
the Pascal era. (You don’t eat quiche, do you?)
Mine was a little more vintage - you can almost see the wire wheels. I
did initally have a good old fashioned loop but just couldn’t justify
keeping it.
Was there anything object-oriented? I’m not sure. I used objects and
their methods but only in the manner of built-in data-types and their
built-in operations. The program basically separates data and
procedures, and then leaves them as publicly available for anyone to
ride on.