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

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

ただいまの
回答率

91.02%

  • Ruby

    6354questions

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

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

解決済

回答 2

投稿

  • 評価
  • クリップ 0
  • VIEW 133

torisan

score 148

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の指定の仕方や
別の関数を使用したりして、スマートに出来ないかと思った次第です。

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

<蛇足?>
①大雑把ですが 1500~2500桁程度のデータが多いです。
②元文字列の 7~9割は"0"になると思われます。
 
以上、
もう少しわかりやすい記述方法や構想(軽ければ尚良し)
があれば教えて頂きたいです。
よろしくお願い致します。

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

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

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

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 2

+4

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

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

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

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/01/19 16:59

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

    キャンセル

  • 2018/01/19 21:02

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

    キャンセル

  • 2018/01/19 21:07

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

    キャンセル

  • 2018/01/19 22:37

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

    キャンセル

checkベストアンサー

+3

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

hensu = "021000000000000002000000000021001000000003000001"

hidari = 0
0.step(hensu.length-1,8) do |i|
    tmp = hensu[i,4]
    hidari += tmp.count("2") * 2 + tmp.count("1")
end
migi = 0
4.step(hensu.length-1,8) do |i|
    tmp = hensu[i,4]
    migi += tmp.count("2") * 2 + tmp.count("1")
end
p hidari
p migi

hidari = 0
migi = 0
hensu.scan(/(....)(....)/).each do |(tmpL,tmpR)|
    hidari += tmpL.count("2") * 2 + tmpL.count("1")
    migi   += tmpR.count("2") * 2 + tmpR.count("1")
end
p hidari
p migi


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

ensu = "021000000000000002000000000021001000000003000001"

count=[0,0]
hensu.each_char.with_index do |x,i|
    case x
    when "1"
        count[(i%8)/4] += 1
    when "2"
        count[(i%8)/4] += 2
    end
end
p count[0]
p count[1]

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/01/19 16:35

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

    キャンセル

  • 2018/01/19 21:05

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

    キャンセル

  • 2018/01/19 22:34

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

    キャンセル

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

  • ただいまの回答率 91.02%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

  • 解決済

    条件に適合する配列要素を数える

    条件に適合する配列要素を数える 下はトランプのカードの名前の文字列を要素とする配列である。     ar = [ 'ハート','ダイヤ','スペード','ダイヤ','ダイヤ

  • 解決済

    ハッシュにして出力したい

    下記humans.csvをrbファイルで読み取って、記載した実行結果を出したいです。その際、途中まで書いて下記記載しているrbファイルのコードを使って出したいのですがどのように続き

  • 解決済

    Rubyの配列についての質問です

    ids = [1,2,3] User.find_by(id: ids[0]) User.find_by(id: ids[1]) User.find_by(id: ids[2])

  • 解決済

    文の意味

    見ていただきありがとうございます。 この文の一文一文が、どういう働きをしているのかがよくわかりません。 英単語のプログラムを作っています。 一応、ファイルの中にある文を、@m

  • 受付中

    コマンドプロンプトで計算ゲームをしたいが、正解率の所でエラーになる件

    ご覧いただきありがとうございます。 現在、コマンドプロンプト(ターミナル)で計算ゲームをするプログラムを作っています(おもに練習用です) まだrubyの勉強初めて一週間

  • 解決済

    Ruby 条件式(if文)を(二次元)配列に一気に適用する方法

    前提・実現したいこと [[12,4],[5,11],[15,8]] という二次元配列があったとします。 これらの配列内の数字を10より下なら0でより上なら1と表示したいです。 出力

  • 解決済

    RubyでFizzbuzz問題

    前提・実現したいこと 初めて投稿するので、不備等があり失礼な質問をしてしまうかもしれませんがよろしくお願いします。 Rubyで下記の設定でFizzBuzz問題を解決したいです。

  • 受付中

    Ruby : メソッド定義について

    テキスト処理についてのコードです。 Rubyでテキスト処理をしているのですが、同じような繰り返しが2回あるので、なんとかメソッドにして綺麗にコードを書けないかなと思って、試して

同じタグがついた質問を見る

  • Ruby

    6354questions

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