56660


eachなどで繰り返しをする際に2回目以降、最後に代入した変数を使用して配列の中から一つをランダムに除外したものを表示したいのですがなかなか上手くいきません。  
以下のようにしているのですが、繰り返し2回目になるとエラーが出てしまいます。

[code]

    (1..5).each do |num|
        if(num - 1 == 0)
            puts "1回目"
            no_fruits = nil
        else
            puts num.to_s << "回目"
            no_fruits = no
        end
    
    fruit1 = "apple"
    fruit2 = "orange"
    fruit3 = "strawberry"
    fruit4 = "kiwi"
    fruit5 = "cherry"
    fruit6 = "banana"
    fruit7 = no_fruits
    
    all = [fruit1, fruit2, fruit3, fruit4, fruit5, fruit6, fruit7 ].reject {|item| item == fruit7 }
    p all
    
    no = all.sample
    p no
    end
    
[/code]

結果↓

[code]

    1回目
    ["apple", "orange", "strawberry", "kiwi", "cherry"]
    "strawberry"
    2回目
    Traceback (most recent call last):
            2: from test.rb:12:in `<main>'
            1: from test.rb:12:in `each'
    test.rb:18:in `block in <main>': undefined local variable or method `no' for main:Object (NameError)
    Did you mean?  not
    
[/code]

となり上手くいきませんでした。  
一応以下のようにすればそれっぽいことはできましたが、無理やりやっている感じがします。

[code]

    (1..5).each do |num|
        if(num - 1 == 0)
            puts "1回目"
            fruit1 = "apple"
            fruit2 = "orange"
            fruit3 = "strawberry"
            fruit4 = "kiwi"
            fruit5 = "cherry"
            fruit6 = "banana"
        else
            puts num.to_s << "回目"
            fruit1 = "apple"
            fruit2 = "orange"
            fruit3 = "strawberry"
            fruit4 = "kiwi"
            fruit5 = "cherry"
            fruit6 = "banana"
            fruit7 = [fruit1, fruit2, fruit3, fruit4, fruit5, fruit6].sample
            puts "除外 = " << fruit7
        end
    
    all = [fruit1, fruit2, fruit3, fruit4, fruit5, fruit6, fruit7].reject {|item| item == fruit7 }
    p all
    end
    
[/code]

もっと他に良いやり方があればぜひ教えて頂きたいです。


CC BY-SA 4.0
2019-07-15T07:40:24.933
56654
2019-08-26T00:06:01.807
2019-08-26T00:06:01.807
3060
29428
question
ruby
繰り返しのときの代入の持ち越し？について

[code]

    (1..5).each do |num|
      if(num - 1 == 0)
        puts "１回目"
        no_fruits = nil
      else
        puts num.to_s << "回目"
        no_fruits = no
      end
    
    #略    
    
      no = all.sample 
      p no
    end
    
[/code]

ループ末尾の`no =
all.sample`で`no`が定義されますが、これはループ内にしかスコープなので、ループ末尾に到達すると消えてしまいます。なので、ループ2回目の`no_fruits
= no` で`no`を参照しても、この時点では定義されていないので、`undefined local variable or
method`になるわけです。

なので、外側のスコープで変数を定義してやれば、次のループに変数を持ち超すことができます。

単純にはこうです。

[code]

    no = nil # ''でも1でも
    
    (1..5).each do |num|
    #(略)
    end
    
[/code]

ただこれだと、`no`はループないでしか使わないのにその後ずっと生き残ってしまうので、あまりきれいではありません。

コメントでinjectメソッドに触れられていますが、

[code]

    (1..5).inject(nil) do |no, num|
       (略)
    
       all.sample
    end
    
[/code]

こうすると、ループ末尾の`all.sample`の値が次のループの時は`no`に入っている、という動きになります。injectメソッドについては[リファレンス](https://docs.ruby-
lang.org/ja/latest/class/Enumerable.html#I_INJECT)見てみてください。

ただ、2つめのコードを見ると、「前回ループで抽出したもの」は絶対の条件ではないように見えます。であれば、

[code]

    all =  [fruit1, fruit2, fruit3, fruit4, fruit5, fruit6]
    
    (1..5).each do |num|
      if num == 1
        p all
      else
        p all.delete_at(rand(all.length)) #ランダムに1個取り除いたものを表示
      end
    end
    
[/code]

とかでもいいような気がします。


CC BY-SA 4.0
2019-07-15T12:52:24.030
56660
2019-07-15T12:52:24.030
5793
56654
answer


> 最後に代入した変数を使用して配列の中から一つをランダムに除外したものを表示したい

これは、「用意した配列から要素をランダムに除外して、そのあとの配列の中身を表示させるループ処理を書きたい」という理解であっているでしょうか？

であれば、次のように書くことができるかもしれません：

[code]

    def random_sampling(array, count = 1)
      # 終了条件を設定
      return nil if array.size.zero?
    
      #
      # 関数内の処理本体部分
      #
    
      element = array.sample
    
      puts "#{count}回目"
      p array
      puts '-' * 30
    
      # 再帰処理
      # * array から取り出した element を除外
      # * 何回目かカウントする変数をインクリメント
      # ...をしつつ同じ関数を呼び出すことで、処理結果を引き継いで再実行
      random_sampling(array - [element], count.succ)
    end
    
    target = %w[apple orange strawberry kiwi cherry banana]
    
    random_sampling(target)
    # =>
    # 1回目
    # ["apple", "orange", "strawberry", "kiwi", "cherry", "banana"]
    # ------------------------------
    # 2回目
    # ["orange", "strawberry", "kiwi", "cherry", "banana"]
    # ------------------------------
    # 3回目
    # ["strawberry", "kiwi", "cherry", "banana"]
    # ------------------------------
    # 4回目
    # ["kiwi", "cherry", "banana"]
    # ------------------------------
    # 5回目
    # ["kiwi", "banana"]
    # ------------------------------
    # 6回目
    # ["kiwi"]
    # ------------------------------
    
[/code]


CC BY-SA 4.0
2019-08-25T18:05:24.813
57592
2019-08-25T18:05:24.813
3861
56654
answer