質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.47%
Ruby

Rubyはプログラミング言語のひとつで、オープンソース、オブジェクト指向のプログラミング開発に対応しています。

Q&A

解決済

2回答

311閲覧

【お暇な時に】4桁ごとに交互にカウント

torisan

総合スコア678

Ruby

Rubyはプログラミング言語のひとつで、オープンソース、オブジェクト指向のプログラミング開発に対応しています。

0グッド

0クリップ

投稿2018/01/19 04:04

Ruby 1.9.3です。

ある変数に半角の0~3のみで構成される、長さが8の倍数の文字列が入っています。
(事前にチェックしていますので、例外は考慮しなくても大丈夫です)

例①(※改行文字は含まれません)
00010000
00000000
20001002
00000013
30000000

その中で、
・4桁ずつ交互に(例①で言う所の左4桁と右4桁ごとに)
・『2』の入っている数×2+『1』の入っている数
の合計の数字を出したいです。

例②
左4桁=0(2の数)×2+5(1の数)=5
右4桁=2(2の数)×2+4(1の数)=8
00012000
00000001
01013000
00000012
00000010
11000003
00000001

例③
左4桁=3(2の数)×2+1(1の数)=7
右4桁=2(2の数)×2+5(1の数)=9
02022020
00000000
03033030
02001000
00000100
13000010
00000011

例④
左4桁=0(2の数)×2+0(1の数)=0
右4桁=2(2の数)×1+8(1の数)=10
33330010
33330010
33330010
33330010
00000200
00000001
33330001
33330001
33330301

とりあえず自分は、
元変数を4文字ずつ読み、都度countで調べ変数hidariと変数migiに加算していくといった方法を考えました。
構想的には問題ないと思うのですが、もう少しcountの指定の仕方や
別の関数を使用したりして、スマートに出来ないかと思った次第です。

Ruby

1hensu = "021000000000000002000000000021001000000003000001" 2hidari = 0 3for i in 1..hensu.length / 8 4 tmp = hensu[(i-1)*8..(i-1)*8+3] 5 hidari += tmp.count("2") * 2 + tmp.count("1") 6end 7migi = 0 8for i in 1..hensu.length / 8 9 tmp = hensu[(i-1)*8+4..(i-1)*8+7] 10 migi += tmp.count("2") * 2 + tmp.count("1") 11end 12p hidari 13p migi

<蛇足?>
①大雑把ですが 1500~2500桁程度のデータが多いです。
②元文字列の 7~9割は"0"になると思われます。

以上、
もう少しわかりやすい記述方法や構想(軽ければ尚良し)
があれば教えて頂きたいです。
よろしくお願い致します。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答2

0

こんなのはどうでしょうか。

rb

1hensu.scan(/.{4}/).each_slice(2).to_a.transpose.map(&:join) 2 .map{ |str| str.count("2") * 2 + str.count("1") }

4 桁ずつにしたものを二つずつペアにし,できた二次元配列に行列の転置のような操作(縦横の入れ替え)をほどこし,左・右それぞれを連結し,云々というやり方です。

投稿2018/01/19 06:06

scivola

総合スコア2108

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

KSwordOfHaste

2018/01/19 07:59

「元のデータを望む形へ変換していき・・・」というコードは意味を捉えやすいなと感じました。 transposeって構造を大きく変更するものなので処理時間はどうだろうと動かしてみましたがそう遅いというわけでもなく・・・インタープリタ言語の場合ループで書くかループが実現しようとしていることをメソッドでやるかは後者の方が分かり易さの面でも速度の面でもよい選択なのかなと思いました。
torisan

2018/01/19 12:02

縦横変換など考えもしませんでした。 こんなに短くなってしまう物なんですね……。 勉強になる回答ありがとうございました。
scivola

2018/01/19 12:07

transpose は配列を変更するわけではなく,新たな配列を作って返します。 ためしに標準添付の profile ライブラリーを使ってプロファイルを作ってみましたが,transpose にかかっている時間は全体の 1% 程度でした。
otn

2018/01/19 13:37

each_sliceの次が思いつきませんでした。なるほど。
guest

0

ベストアンサー

まず、同じ方式で、わかりやすいのではないかと思う記述方法2種。

Ruby

1hensu = "021000000000000002000000000021001000000003000001" 2 3hidari = 0 40.step(hensu.length-1,8) do |i| 5 tmp = hensu[i,4] 6 hidari += tmp.count("2") * 2 + tmp.count("1") 7end 8migi = 0 94.step(hensu.length-1,8) do |i| 10 tmp = hensu[i,4] 11 migi += tmp.count("2") * 2 + tmp.count("1") 12end 13p hidari 14p migi 15 16hidari = 0 17migi = 0 18hensu.scan(/(....)(....)/).each do |(tmpL,tmpR)| 19 hidari += tmpL.count("2") * 2 + tmpL.count("1") 20 migi += tmpR.count("2") * 2 + tmpR.count("1") 21end 22p hidari 23p migi

あとは、1文字ずつ見ていって、12ならインデックスを8で割った余りでどちらかに加算する。

Ruby

1ensu = "021000000000000002000000000021001000000003000001" 2 3count=[0,0] 4hensu.each_char.with_index do |x,i| 5 case x 6 when "1" 7 count[(i%8)/4] += 1 8 when "2" 9 count[(i%8)/4] += 2 10 end 11end 12p count[0] 13p count[1]

投稿2018/01/19 05:32

otn

総合スコア84710

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

KSwordOfHaste

2018/01/19 07:35

コンパイラー脳(?)な自分はotnさんの最後の例をイメージしたのですが、やってみるとオリジナルより少々遅く、インタープリタ(というより文字と文字列の区別がないインタープリタ的言語?)だと文字列の一部を切り出す(文字列を生成する)回数の速度への影響が大きいのかなぁと感じました。部分文字列を切り出すのに正規表現が早いかRangeで素朴に切り出すのが早いかなども興味を引く点でした。(やってみてはないですが・・・)
torisan

2018/01/19 12:05

色々な回答ありがとうございました。 3番目の回答が一番分かりやすかったのでBA付けさせていただきます。
otn

2018/01/19 13:34

どれが速いかは中々直感では分からないですよね。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.47%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問