o-takeshi-tech
@o-takeshi-tech (Takeshi Ooka)

Are you sure you want to delete the question?

If your question is resolved, you may close it.

Leaving a resolved question undeleted may help others!

We hope you find it useful!

もっときれいな書き方ある気しかしません。

解決したいこと

標準入力で文字列を受け取り、受け取った文字列のインデックスを偶数、奇数に分けて出力します。

例) 入力:abcde 出力結果:ace bd
str[0] = a, str[1] = b, str[2] = c, str[3] = d, str[4] = e

偶数と奇数はスペースで分かれています。
最初に数値numを受け取り、その回数分文字列を受け取ります。
テストケースをパス出来てはいますが、もっときれいな書き方がある気しかしないのでアドバイス頂けると嬉しいです。

該当するソースコード

num = gets.chomp.to_i

input = []
num.times do 
    input << gets.chomp
end


input.each do |str|
    odd = []
    even = []
    for i in 0..(str.length - 1) do
        if i % 2 == 0
            even << str[i]
        elsif i % 2 == 1
            odd << str[i]
        end
    end
    for i in 0..(even.length - 1) do
        print even[i]
    end
    print " "
    for i in 0..(odd.length - 1) do
        if i == odd.length - 1
            puts odd[i]
        else
            print odd[i]
        end
    end
end

かなり無理矢理でイケてないので、処理を1つにできないかと模索中です。
お力添え頂けると嬉しいです。

0
    for i in 0..(even.length - 1) do
        print even[i]
    end
    print " "
    for i in 0..(odd.length - 1) do
        if i == odd.length - 1
            puts odd[i]
        else
            print odd[i]
        end
    end

この辺りは,

puts "#{even.join} #{odd.join}"

とかで行けそうな気がします.

0Like
    odd = []
    even = []
    for i in 0..(str.length - 1) do
        if i % 2 == 0
            even << str[i]
        elsif i % 2 == 1
            odd << str[i]
        end
    end

この部分はこんな感じでどうでしょうか?

a = (input.split(//) + [""] * 3).each_slice(2).to_a
odd, even = a[0].zip(*a[1..-1]).map(&:join)

キレイではないかもしれないですが,%2 をしたくなかったので,こうしました.

# すみません.↑修正しました.

odd, even = (input.split(//) + [""] * 3).each_slice(2).to_a.then { |h, *t| h.zip(*t).map(&:join) }

a が消したかったので消しました.

0Like

@atm-snag さん
ご意見頂きありがとうございます!

puts "#{even.join} #{odd.join}"

この点joinメソッドはとても参考になります!ありがとうございます。

a = (input.split(//) + [""] * 3).each_slice(2).to_a
odd, even = a[0].zip(a[1]).map(&:join)

のコードですが、 文字列が4文字であれば大丈夫なんですが、5文字以上だと溢れてしまうかなと思いました。

[""] * 3

はしなくてもいいのではと少し思ったのですが、どうなんでしょうか?
僕の理解が足らない気がするので全然的がズレたこと言っていたらすいません!

0Like

@o-takeshi-tech
[""] * 3 してるのは,input = "" のような文字数が少ない場合のために例外を入れるのが面倒で入れました.
単純にバグってたので,↑のコードは修正しておきました.

0Like

@atm-snag さん
解説頂きありがとうございます!
コード全体をまだ理解できてないのですが、実装方法とても参考になりました。
ありがとうございます!

0Like
puts "何行入力するか、数字で入力してください"
number_of_lines = gets.to_i

if number_of_lines <= 0
  puts "(#{number_of_lines})は不正な数字です 終了します"
  return
end

puts "文字列を入力してください"
lines = number_of_lines.times.collect{ gets.strip }

converteds = lines.collect do |line|
  grouped = line.chars.group_by.with_index{|_, i| i % 2 == 0}
  odds = grouped[false]
  evens = grouped[true]

  [evens.join, odds.join].join(" ")
end

converteds.each{|x| puts x }
0Like

rubyでforが出てきたら少し頭を休めてじっくりコードを見直したほうが良いかなと思います。
長い間ruby書いてますが、forを使ったことはないです。

https://docs.ruby-lang.org/ja/latest/class/Enumerable.html
この辺りを連結して使えるようになるとコードも見た目読みやすいし、退避用の変数が減ります。退避用の変数が減れば、その分考えることが減ります。

0Like

やり方はひとつじゃない(There's More Than One Way To Do It; TMTOWTDI) ところがRubyの面白いところですね。

個人的にはRubyらしくメソッドチェーンをうまく活用する方法が好きですね。

num = gets.to_i
input = num.times.map{ gets.chomp }
puts input.partition.with_index{|_, i| i.even?}.map(&:join).join(' ')
1Like

@github0013@github さん
アドバイス頂きありがとうございます!
メソッドを連結するところで引き出しが増えました。
また精進します!

参照リンクまで送って頂きありがとうございました。

0Like

@neko_the_shadow さん
アドバイス頂きありがとうございます!
連結していくとかなり見やすくなるというところとても参考になります。

もっとシンプルにしていけるようにがんばります。

0Like

Your answer might help someone💌