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

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

ただいまの
回答率

90.62%

  • Ruby

    7306questions

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

rubyのメソッドの基本的な仕様について。

解決済

回答 2

投稿

  • 評価
  • クリップ 0
  • VIEW 848
現在入れた文字列の射影を取るメソッドを使っているのですが、その際に引数に指定した配列(ソースのa)がなぜだか変化してしまいます。
ソースを見ても原因がわからず、dupやcloneを使っても変化してしまうためお手上げ状態です。
ものすごく基本的な質問ですが、良ければ原因をお教え下さい。



def projection(db , series)
  
  wo=0
  
  while wo<db.length                #dbの配列数
  
    wi=0
    while wi < series.length         #系列の配列数だけ回す。
      
      wa = 0
      while wa < db[wo].length                        #db[wo]の配列数だけ回す。
      
        
        if db[wo][wa].index(series[wi]) != nil      #db配列要素の中に系列要素があった場合、if文の中に入る。
          
          wu=0                #系列がある配列要素より前のdb配列要素をすべてカット
          while wu < db[wo].length
            db[wo][wu]=db[wo][wa+wu]
            wu=wu+1
          end
          
          wu=0                #配列要素内の系列までの文字をすべてカット
          we=db[wo][0].index(series[wi])            #dbの一つ目の系列がある場所
          we = we+(series[wi].length-1)
          while wu <= we
            db[wo][0].slice!(0)
            wu=wu+1
          end
          
          db[wo][0].insert(0,"_")             #カットした場所に_を置く。
          
          if db[wo][0]=="_\n"                 #カットしたことで配列の中身が_と改行のみになった場合、カットする。。
            wu=0
            while wu < db[wo].length
              db[wo][wu]=db[wo][wu+1]
              wu=wu+1
            end
          end
          
          
          break
        end
        wa=wa+1
      end
      wi=wi+1
    end
    db[wo].compact!                            #空になった配列要素をカット
    
    
    wo=wo+1
  end
  db.compact!                                #空になった配列要素をカット
  return db
end





a=[["1234567890","123456789"],["1234567890","123456789"]]
b=["3"]

c=projection(a , b)

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

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

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

    クリップを取り消します

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

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

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

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

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

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

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

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

    質問の評価を下げる

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

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

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

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

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

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

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

    詳細な説明はこちら

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

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

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

回答 2

checkベストアンサー

0

projectionの中で、仮引数のdbが指すオブジェクトを書き換えているので、実引数のaにも影響が及びます。
Rubyの変数は、C等で言うとすべてポインタ(リファレンス)だと思ってください。

あと、オブジェクトを内部に含んだオブジェクト~~例えば["A","B"]~~の場合、clonedupをしても複製されるのは外側のオブジェクト(例だと[ ])だけで、内部に含まれたオブジェクト("A""B")は複製されず共有されます。
a=["A","B"]
puts a.object_id     #=>21104256
puts a[0].object_id  #=>21104280
puts a[1].object_id  #=>21104268

b=a.clone
puts b.object_id     #=>21104160 aとは別オブジェクト
puts b[0].object_id  #=>21104280 a[0]と同一オブジェクト
puts b[1].object_id  #=>21104268 a[1]と同一オブジェクト

浅いコピー(shallow copy)と深いコピー(deep copy)に付いて調べてみてください。

db2 = db.cloneは浅いコピーなので、深いコピーならこの場合は、
db2 = db.map{|x| x.map{|y| y.clone}}
ですね。

投稿

編集

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2015/02/28 17:36

    ありがとうございます。
    よく理解出来ました。

    キャンセル

  • 2015/02/28 17:38

    とりあえずの解決策を追記しておきました。

    キャンセル

0

2次元配列は、 dup や clone では、完全には 複製をつくることはできません。

- Rubyで二次元配列のコピー http://simanman.hatenablog.com/entry/2013/06/20/161437

次のプログラムを試してみてください。
# coding: utf-8

def my_func(db)
  db[0] = 'x'
  db[0][0] = "y"
  return db
end

def my_func_1(db)
  work = db.clone
  work[0] = "x"
  work[1][0] = "y"
  return work
end

def my_func_2(db)
  work = Marshal.load(Marshal.dump(db))
  work[0] = "x"
  work[1][0] = "y"
  return work
end

a = [["1234567890","123456789"],["1234567890","123456789"]]
c = my_func(a)
puts "--- after my_func"
p a
p c

a = [["1234567890","123456789"],["1234567890","123456789"]]
c = my_func_1(a)
puts "\n--- after my_func_1"
p a
p c

a = [["1234567890","123456789"],["1234567890","123456789"]]
c = my_func_2(a)
puts "\n--- after my_func_2"
p a
p c
実行すると次のようになります。
$ ruby array.rb
--- after my_func
["y", ["1234567890", "123456789"]]
["y", ["1234567890", "123456789"]]

--- after my_func_1
[["1234567890", "123456789"], ["y", "123456789"]]
["x", ["y", "123456789"]]

--- after my_func_2
[["1234567890", "123456789"], ["1234567890", "123456789"]]
["x", ["y", "123456789"]]

my_func, my_func_1, my_func_2 での配列の複写方法と、その複写した配列へに代入の結果の差がわかるとおもいます。
my_func_2 の方法で配列を複写すると、解決するとおもいます。

投稿

編集

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2015/03/02 01:19

    ありがとうございます!
    こちらの方法も試してみます。

    キャンセル

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

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

関連した質問

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

  • Ruby

    7306questions

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