challenge 文字列の均等分割

一行の文字列を指定した数の行にできるだけ文字数が均等になるように分割してください.
ただし,除算や剰余算を使わないで書いてみてください.

sample = "ゆめよりもはかなき世のなかをなげきわびつゝあかしくらすほどに四月十よひにもなりぬれば木のしたくらがりもてゆく"

divid 4 sample =>
 "ゆめよりもはかなき世のなかを"
 "なげきわびつゝあかしくらすほ"
 "どに四月十よひにもなりぬれ"
 "ば木のしたくらがりもてゆく"

divid 5 sample => 
 "ゆめよりもはかなき世の"
 "なかをなげきわびつゝあ"
 "かしくらすほどに四月十"
 "よひにもなりぬれば木の"
 "したくらがりもてゆく"

divid 6 sample => 
 "ゆめよりもはかなき"
 "世のなかをなげきわ"
 "びつゝあかしくらす"
 "ほどに四月十よひに"
 "もなりぬれば木のし"
 "たくらがりもてゆく"

この問題は、除算だけでははく算術演算とか、文字列の長さをstrlenの類いで測るとかをしなくても、多分書けるのではないかと思います。

Posted feedbacks - Ruby

例えば5分割の場合、以下のように配列を作成後、文字が入っている所に入力文字を当てはめていくようにしました。

"ゆはのげゝら四にれたも"
"めかなきあす月もばくて"
"よなかわかほ十な木らゆ"
"りきをびしどよりのがく"
"も世なつくにひぬしり"

shiroさんと同様のロジックですね。
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
def strDiv(n,s)
  r = [[]]
  s1 = s.split(//)
  while s1!=[]
    1.upto(n) {|i|
      (r[i-1] ||= []) << s1.shift
    }
  end
  s1 = s.split(//)
  r.each {|i|
    i.each {|j|
      print s1.shift if j
    }
    puts
  }
end


strDiv(5,"ゆめよりもはかなき世のなかをなげきわびつゝあかしくらすほどに四月十よひにもなりぬれば木のしたくらがりもてゆく")

最初に,行数分の文字ずつ(例えば,4分割なら4文字ずつ)与えられた文字列を走査し,[14, 14, 13, 13] のような各行の文字数からなる配列を作ります.次に,配列を走査しつ つ,この文字数ずつ文字列をとって配列の中身を置き換え,出力とします.

% ./divid.rb
divid 4:
["ゆめよりもはかなき世のなかを",
 "なげきわびつゝあかしくらすほ",
 "どに四月十よひにもなりぬれ",
 "ば木のしたくらがりもてゆく"]

divid 5:
["ゆめよりもはかなき世の",
 "なかをなげきわびつゝあ",
 "かしくらすほどに四月十",
 "よひにもなりぬれば木の",
 "したくらがりもてゆく"]

divid 6:
["ゆめよりもはかなき",
 "世のなかをなげきわ",
 "びつゝあかしくらす",
 "ほどに四月十よひに",
 "もなりぬれば木のし",
 "たくらがりもてゆく"]
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
require 'pp'
$KCODE='EUC'

class String
  def divid(lines)
    out, x, y = [0] * lines, split(''), nil
    y.times {|i| out[i] += 1 } while (y = x.slice!(0, lines).size) > 0

    rest = self
    out.map! do |len|
      _, ret, rest = *rest.match(/(.{#{len}})(.*)/)
      ret
    end
  end
end

sample = "ゆめよりもはかなき世のなかをなげきわびつゝあかしくらすほどに四月十よひにもなりぬれば木のしたくらがりもてゆく"
(4..6).to_a.each do |i|
  puts "divid #{i}:"
  pp sample.divid(i)
  puts
end

  • http://ja.doukaku.org/comment/4258/
  • http://ja.doukaku.org/comment/4266/

を参考に ruby1.9 Enumerator とメソッドチェインで書いてみました。

$ ruby1.9 --version
ruby 1.9.0 (2007-11-02 patchlevel 0) [i686-linux]
1
2
3
4
5
6
def divid(n, str)
    (1..n).cycle.zip(str = str.split(//u)).sort.inject(["", 1]) {|(r,i),(j,_)|
        r << ((i == j) ? "" : "\n") << str.shift
        [r, j]
    }.first
end

器を作って埋めていく方式。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
require 'pp'
sample = 'ゆめよりもはかなき世のなかをなげきわびつゝあかしくらすほどに四月十よひにもなりぬれば木のしたくらがりもてゆく'

def divid(num,str)
   str_ = str.split(//)
   buf, _n = str_.inject([[],0]) do |acc,ch|
      tmp, n = acc
      tmp[n] ||= []
      tmp[n] << ch
      [tmp, if (n_ = n + 1) < num then n_ else 0 end]
   end

   str_.inject([0,0]) do |idx,ch|
      n, m = idx
      if buf[n][m].nil?
         n += 1
         m = 0
      end
      buf[n][m] = ch
      [n, m + 1]
   end

   buf.map {|ary| ary.join}
end

(4..6).each do |n|
   pp divid(n, sample)
end

他の人のコードを見ずに書いてみました。
見返してみると、kenaxt さんのコード(#4250)とほとんど同じですね。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
def divid(num, str)
  a = Array.new(num){ [] }
  chrs = str.split('')
  tmp = chrs.clone

  until tmp.empty?
    a.each_index do |i|
      break if tmp.empty?
      a[i] << tmp.shift
    end
  end

  a.each do |b|
    b.each_index do |i|
      b[i] = chrs.shift
    end
  end
  a.map{ |b| b.join('') }.join("\n")
end

sample = "ゆめよりもはかなき世のなかをなげきわびつゝあかしくらすほどに四月十よひにもなりぬれば木のしたくらがりもてゆく"
puts divid(5, sample)

Index

Feed

Other

Link

Pathtraq

loading...