HiveBrain v1.2.0
Get Started
← Back to all entries
patternrubyMinor

Twisting words! (boustrophedon formatting)

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
boustrophedonformattingwordstwisting

Problem

I decided to implement properly the Code Golf challenge about twisting strings. I report the assignement verbatim for convenience:

Twisting Words!


Given a string and a positive integer. You must twist the string, back
and forth.

Example Input / Output




Input

Programming Puzzles & Code Golf
4


Output

Prog
mmar
ing
zzuP
les
oC &
de G
flo


Input


The input can be taken in through STDIN, or function argument. The
input will consist of a string and a positive integer, n. The
integer will determine the length of each twisted line.


The string is twisted back-and-forth. An input of HELLO, WORLD! and
5 would look like:




Output


The output will be the twisted text. It may not any trailing
whitespace. If the input string length is not divisible be the line
length, add a space until the line is filled:


An example of this: Input

Hello, World!
5



Output (Note the whitespace at the very end)

Hello
roW ,
ld!


My implementation

def twist(text, chunk_size)
text
.+(" " * ((text.length % chunk_size) - 1))
.chars
.each_slice(chunk_size)
.each_with_index
.map {|str, i| i.odd? ? str.reverse : str}
.map(&:join)
.join("\n")
end

puts twist("Hello, World!", 5)
puts
puts twist("foo bar baz", 7)

Solution

Looks fine to me. Only thing I'd change is the way the padding is done: You can use ljust instead, which seems a little more appropriate to me. Something like:

.ljust(text.length.fdiv(chunk_size).ceil * chunk_size, " ")


You can also use the with_index modifier on map instead of doing a separate each_with_index, i.e.:

.map.with_index { |chunk, index| index.odd? ? chunk.reverse : chunk }


Of course there are several approaches to this. For instance, you needn't necessarily use chars and then join. For instance:

def twist(text, chunk_size)
  text
    .ljust(text.length.fdiv(chunk_size).ceil * chunk_size, " ")
    .scan(%r/.{#{chunk_size}}/)
    .map.with_index { |chunk, index| index.odd? ? chunk.reverse : chunk }
    .join("\n")
end


I won't say it's a better solution, though. Fewer lines, sure, but the interpolated regex isn't pretty. But again, it's just to show an alternative approach.

You can also move the ljust, to avoid the long'ish bit of arithmetic:

def twist(text, chunk_size)
  text
    .scan(%r/.{1,#{chunk_size}}/)
    .map { |chunk| chunk.ljust(chunk_size, " ") }
    .map.with_index { |chunk, index| index.odd? ? chunk.reverse : chunk }
    .join("\n")
end


It's obviously it's kinda brute-force, since we know that it'd only be the last chunk that could require padding. But again: Just an alternative.

Code Snippets

.ljust(text.length.fdiv(chunk_size).ceil * chunk_size, " ")
.map.with_index { |chunk, index| index.odd? ? chunk.reverse : chunk }
def twist(text, chunk_size)
  text
    .ljust(text.length.fdiv(chunk_size).ceil * chunk_size, " ")
    .scan(%r/.{#{chunk_size}}/)
    .map.with_index { |chunk, index| index.odd? ? chunk.reverse : chunk }
    .join("\n")
end
def twist(text, chunk_size)
  text
    .scan(%r/.{1,#{chunk_size}}/)
    .map { |chunk| chunk.ljust(chunk_size, " ") }
    .map.with_index { |chunk, index| index.odd? ? chunk.reverse : chunk }
    .join("\n")
end

Context

StackExchange Code Review Q#101738, answer score: 3

Revisions (0)

No revisions yet.