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

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

ただいまの
回答率

90.36%

  • Ruby

    8771questions

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

ruby とある問題での回答例。関数やクラス使えそうか?

受付中

回答 4

投稿

  • 評価
  • クリップ 1
  • VIEW 527

garchomp

score 102

失礼します。
とある問題を説いていたら次のようなコードになりました。(問題の内容は拡散禁止されているため個人的な回答内容から読み取ってください。)

ちなみに入力される値はこれです。

~~

n
s_1
s_2
...
s_n

例:
3
SET 1 10
SET 2 20
ADD 40

10 50
~~

x = gets.to_i
a=0
b=0
for i in 1..x do
    rd=gets.split(" ")
    if rd[0]=="SET"
        if rd[1].to_i==1
            a=rd[2].to_i
        elsif rd[1].to_i==2
            b=rd[2].to_i
        end
    elsif rd[0]=="ADD"
        b=a+rd[1].to_i
    elsif rd[0]=="SUB"
        b=a-rd[1].to_i
    end
end

puts "#{a} #{b}"

恐らく、これらはdef classなどをうまく使うこともできるのでは?とも思いましたが、あいにく使い慣れていないので頭で考えてみたら上記のような回答になりましたが、関数などを定義する場合はどのような記述になるでしょうか?

また、関数、クラスなどを使っていく際に必要な考え方、組み立て方、見通しの建て方などありましたらご指導よろしくお願いいたします。

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

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

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

    クリップを取り消します

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

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

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

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

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

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

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

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

    質問の評価を下げる

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

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

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

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

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

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

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

    詳細な説明はこちら

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

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

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

回答 4

+1

関数をつかって処理を分割してみました。
gets でのデータ入力を処理から分離させることもしています。
各関数が mem を入力、mem を返すようになってます。

a.rb

def play(statements, mem)
  statements.each do |statement|
    tokens = statement.split(' ')
    inst = tokens.shift
    case inst
    when 'SET'
      mem = do_set(tokens, mem)
    when 'ADD'
      mem = do_add(tokens, mem)
    when 'SUB'
      mem = do_sub(tokens, mem)
    else
      raise "bad instraction: #{token[0]}"
    end
  end
  mem
end

def do_set(tokens, mem)
  pos = tokens[0].to_i - 1
  val = tokens[1].to_i
  mem[pos] = val
  mem
end

def do_add(tokens, mem)
  mem[1] = mem[0] + tokens[0].to_i
  mem
end

def do_sub(tokens, mem)
  mem[1] = mem[0] - tokens[0].to_i
  mem
end

lines = []
x = gets.to_i
x.times { lines << gets }

mem = [0, 0] # [a, b]
mem = play(lines, mem)
puts mem.join(' ')


![イメージ説明](3bb44f3ca196a3d554d8fbeecbd8c14c.png)

Mem クラス(a と b の状態をもち、その状態を変更したり参照するメソッドを持つ) として定義すれば、各メソッドでいちいち mem を返すようなことは不要にできます。

クラスを定義すると、扱える変数を a, b だけでなくもっと多くするとか、SET, ADD, SUB 以外の操作もできるようにするといった場合に、変更とテストがしやすくなると思います。
(質問文のコード自体は短いので、そういった変更はいまのままでも簡単にできますが)

実際に、扱える変数を a..z に増やしたり、MUL, DIV, MOD といった処理をあつかえるように変更してみるとよいと思います。
(最終ゴールとしてはマシン語シュミレータをつくるとか、そのマシン語を生成するコンパイラーをつくるとか...)

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2017/05/28 21:34

    買いおつありがとうございます!
    確かにこれだとメンテナンス性も高く、拡張なども非常にしやすいですね・・・

    先のことも考えたプログラムを書けるように色々頑張ってみます!
    マシン語・・・難しそうですね・・・頑張ってみます(汗)

    キャンセル

+1

さらに、クラスをつかってかいてみました。
メソッドへの分離をした時にあった swith-case の分岐をなくすこともしてみました。

class Mem
  def initialize(mem = [0] * 2)
    @mem = mem
    @actions = {
      SET: method(:do_set),
      ADD: method(:do_add),
      SUB: method(:do_sub)
    }
  end

  def dump
    @mem.join(' ')
  end

  def play(statements)
    statements.each do |statement|
      args = statement.split(' ')
      inst = args.shift.to_sym
      raise "bad instraction: #{inst}" unless @actions[inst]
      @actions[inst].call(args)
    end
  end

  private

  def do_set(args)
    @mem[args[0].to_i - 1] = args[1].to_i
  end

  def do_add(args)
    @mem[1] = @mem[0] + args[0].to_i
  end

  def do_sub(args)
    @mem[1] = @mem[0] - args[0].to_i
  end
end

# lines = []
# x = gets.to_i
# x.times { lines << gets }
lines = [
  'SET 1 10',
  'SET 2 20',
  'ADD 40'
]

mem = Mem.new [0, 0]
mem.play(lines)
puts mem.dump

投稿

編集

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2017/05/29 14:54

    勉強になります。

    キャンセル

0

a, b = 0, 0

x = gets.chomp.to_i

x.times do
  e = gets.chomp.split("\s").map { |t| t.to_i.to_s == t ? t.to_i : t }
  case e[0]
  when 'SET' then e[1] == 1 ? a = e[2] : b = e[2]
  when 'ADD' then b = a + e[1]
  when 'SUB' then b = a - e[1]
  end
end

puts "#{a} #{b}"
data = []

loop do
  input = gets
  break if input.nil?
  data << input.chomp
end

def answer(array)
  a, b = 0, 0

  array.drop(1).each do |e|
    e = e.split("\s").map { |t| t.to_i.to_s == t ? t.to_i : t }
    case e[0]
    when 'SET' then e[1] == 1 ? a = e[2] : b = e[2]
    when 'ADD' then b = a + e[1]
    when 'SUB' then b = a - e[1]
    end
  end

  return "#{a} #{b}"
end

puts answer(data)


質問者様のコードを参考にしてやってみました。
メソッド初心者の私の個人的な考えですが今回の場合は
メソッドを使わないほうが簡単なのではと思います。

投稿

編集

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2017/05/28 09:21

    回答ありがとうございます!

    メソッド使うかどうかは時と場合による。ですか。。。

    同じ処理を複数回やる時にメソッドを考えた方が良さそうですね。

    よく考えてみたら今回の場合ループで片付けられる。。。

    キャンセル

0

arr = Array.new(2,0)
# p a,b
class Array
def order(x)
  num = x[1].to_i
  case x[0]
    when "SET"
      self[num - 1] = x[2].to_i
    when "ADD"
      self[1] = self[0] + num
    when "SUB"
      self[1] = self[0] - num
    end
  end
end

gets.to_i.times{ arr.order(gets.split) }

arr.join(" ").tap{|s| puts s }

自分がこの問題を解いた時の回答はこれですね
わざわざ新しいclassを書くよりはArrayクラスにメソッドを加えてしまった方が手取り早くコードが短くなると考えました。

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2017/05/30 13:27

    解答ありがとうございます!
    arrayクラスにメソッドを加える…そんなこともできるんですね…
    全然考え付きませんでした^^;

    勉強り成りました!

    キャンセル

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

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

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

  • Ruby

    8771questions

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