月別アーカイブ: 2014年6月

ruby

ディープコピー 【Ruby】

『オブジェクトのコピー』,『メソッドの引数(値渡し、参照渡し)』の延長です。私もよくわかっていないので、さらっと流します。

配列のコピーや、メソッドの引数に配列を渡すとき、『副作用』(コピー先の値を変更すると、コピー元の値も変更される)が発生するので、『副作用』を避ける場合、cloneメソッドで複製を作る方法を紹介しました。

しかし、多重ループの場合 cloneメソッドでは、2次以上の部分に副作用が残ります。その際に用いるのが、ディープコピー(deep copy)という方法です。

Javaではキチンと?書かないといけないようですが、rubyでは次のコードでディープコピー行えるようです。(*2)

obj_m = Marshal.load(Marshal.dump(obj))

Marshalモジュール : オブジェクトをファイル(または文字列)に書き出したり、読み戻したり する機能を提供するモジュール(*1)
渡したオブジェクトを、Marshal.dump で出力し、Marshal.loadで読み込み、オブジェクトを返すイメージです。

実際にサンプル(sample01)を見てみます、まず clone メソッドでコピーした場合の副作用を見てみます。
4, 5行目 : clone で複製したオブジェクトは別物になっています。
しかし、
6, 7行目 : arrA[0]と、arrB[0]は同じオブジェクトを参照
8, 9行目 : arrA[1]と、arrB[1]は同じオブジェクトを参照
しているので、arrA[0][1]の値を変更した際に、arrBの中の値も変更されています(副作用)。

arrA = Array.new(2){ |i| Array.new(4){ |j| i * 4 + j + 1 } }
p arrA # => [[1, 2, 3, 4], [5, 6, 7, 8]]
arrB = arrA.clone
p arrA.object_id # => 17481360
p arrB.object_id # => 17481200
p arrA[0].object_id # => 17481350
p arrB[0].object_id # => 17481350
p arrA[1].object_id # => 17481340
p arrB[1].object_id # => 17481340
arrA[0][1] = 10
p arrA # => [[1, 10, 3, 4], [5, 6, 7, 8]]
p arrB # => [[1, 10, 3, 4], [5, 6, 7, 8]]

ディープコピーを使ったサンプル(sample02)では、
6, 7, 8, 9行目 : arrA[0], arrB[0], arrA[1], arrB[1] が、それぞれ別々のオブジェクトを参照しています。
arrA[0][1]の値を変更しても、arrBの中の値は変更されていません。

arrA = Array.new(2){ |i| Array.new(4){ |j| i * 4 + j + 1 } }
p arrA # => [[1, 2, 3, 4], [5, 6, 7, 8]]
arrB = Marshal.load(Marshal.dump(arrA))
p arrA.object_id # => 7977880
p arrB.object_id # => 7977670
p arrA[0].object_id # => 7977870
p arrB[0].object_id # => 7977660
p arrA[1].object_id # => 7977860
p arrB[1].object_id # => 7977650
arrA[0][1] = 10
p arrA # => [[1, 10, 3, 4], [5, 6, 7, 8]]
p arrB # => [[1, 2, 3, 4], [5, 6, 7, 8]]

蛇足で、3次元配列もディープコピーを見てみますと、別々のオブジェクトを参照しているようです。

arrA = Array.new(3){ |i| Array.new(2){ |j| Array.new(3){|k| i * 6 + j * 3 + k + 1 }} }
p arrA # => [[[1, 2, 3], [4, 5, 6]], [[7, 8, 9], [10, 11, 12]], [[13, 14, 15], [16, 17, 18]]]
p arrA[0] # => [[1, 2, 3], [4, 5, 6]]
p arrA[0][0] # => [1, 2, 3]
arrB = Marshal.load(Marshal.dump(arrA))
p arrA.object_id # => 17830590
p arrB.object_id # => 17830150
p arrA[0].object_id # => 17830580
p arrB[0].object_id # => 17830140
p arrA[0][0].object_id # => 17830570
p arrB[0][0].object_id # => 17830130

(*1)Ruby 2.1.0 リファレンスマニュアル module Marshal

(*2)Ruby 1.8.7 リファレンスマニュアル instance method Object#clone

ruby

メソッドの引数(値渡し、参照渡し)

Rubyの引数は値渡しです。

Rubyの引数は値渡しです。参照渡しではありません。ググるとそのようにまとめてらっしゃる方が多々ありますので間違いはないとおもいます。Ruby リファレンスマニュアルで探してみたんですが、記載を見つけられませんでした、確認でき次第アドレスを掲載します。
(*1)参考リンクを追加しました。

ここではRubyの引数(値渡し,参照渡し)について自分なりにまとめてみます。

Rubyist Magazine – 値渡しと参照渡しの違いを理解する

を深く読んでください。を深く読んでください。を深く読んでください。
この記事よりもよっぽど詳しいです。。。

メソッドの復習と名称

def hoge(a) # メソッド: hoge, 仮引数: a
    a += 10 # a に 10 を足す
end

x = 10 # 変数 x
hoge(x) # メソッド hoge に、実引数 x を渡す

値渡しと参照渡し

値渡しと参照渡しについて簡単に説明します。詳細は本当にググってください…

・値渡し (call by value) :実引数として変数を渡しても、その値のみが渡される。そのため、仮引数を変更しても、実変数は変更されない。

def hoge(a) # メソッド: hoge, 仮引数: a
    a += 10 # a に 10 を足す
    p a # => 20
end

x = 10 # 変数 x
hoge(x) # メソッド hoge に、実引数 x を渡す
p x # => 10

・参照渡し (call by variable) :実引数として変数を渡しすとき、変数に対する参照(メモリ番地)先を渡す。そのため、仮引数の値を変更すると、実変数の値も同様に変更されたことになる。

def hoge(a) # メソッド: hoge, 仮引数: a
    a += 10 # a に 10 を足す
end

x = 10 # 変数 x
hoge(x) # メソッド hoge に、実引数 x を渡す
p x # => 20

注)仮のコードです、rubyでは動作確認できません

引数(実引数)が配列の場合

Rubyは『値渡し』です。しかし、実引数にが配列の場合『参照渡し』のような結果になるときがあります。実引数で渡した配列が、仮引数の値を変更すると実引数の値も変わってしまう『副作用』が生じます。実はこの時『参照の値渡し』と言う値渡しが行われています。
理屈は以前の記事オブジェクトのコピーと同じで、実引数も仮引数も同じオブジェクトを見ている、仮引数にはオブジェクトの参照の値が渡されたということになります。

def hoge(a) # メソッド: hoge, 仮引数: 配列 a
    a[0] += 10 # 配列a[0] に 10 を足す
end

x = [10] # 変数: 配列 x
hoge(x) # メソッド hoge に、実引数 x を渡す
p x # => [20] # 実引数の値が変更されている

objcet_idを確認してみる

def hoge(a)
    a[0] += 10
    p a.object_id # => 17968120
end

x = [10]
p x.object_id # => 17968120
hoge(x)
p x # => [20] # 実引数の値が変更されている

*)object_idで同一性を確認しているだけです。rubyではメモリの番地を調べることはできないようです。

引数(実引数)が配列の場合の『副作用』を予防する

この副作用を予防するには、実引数と仮引数が別のオブジェクトを参照していれば良いということになります。なので、複製を作ればOKになります。

def hoge(a)
  p a.object_id # => 540724920
end

x = [1, 2, 3, 4, 5]
p x.object_id # => 539436540
temp = x.clone
hoge(temp)
def hoge(*a) # * 複数の引数を配列として受け取ります。
  p a.object_id # => 539428060
end

x = [1, 2, 3, 4, 5]
p x.object_id # => 539443780
hoge(*x) # * 展開して渡します

sample01, sample02 もobject_idが違うので、『副作用』は起こりません。

しかし・・・多重配列だと・・・別の機会追記しました。

Rubyist Magazine – 値渡しと参照渡しの違いを理解する

引数 – Wikipedia

*1)お気楽 Ruby プログラミング入門第 3 回●値呼びと参照呼び

変数や定数は,あるオブジェクトを指しています.何も代入しなくても nilオブジェクトを指しています.代入は,変数や定数が新しいオブジェクトを 指すようにします.

したがって,代入によりオブジェクトがコピーされて新しく作られることは なく,右辺の表現の表しているオブジェクトを左辺の変数や定数が指すように することが代入によって行われます.

*1)Ruby FAQ: 変数,定数,引数(文字化けします、EUCで開いてください)

ruby

オブジェクトのコピー 【Ruby】

ここでは、オブジェクトを複製するときに注意すること(特に配列オブジェクト)を記述します。
phpでは考えなくてよかったことですが、他の言語ではどうなんでしょうね。

オブジェクトの複製の説明ですが、メソッドの引数にも共通している内容だと思います。
メソッドの引数については、次回触れてみようと思います。(値渡し,参照渡し)

少し復習

rubyでは変数も何かのオブジェクトです。

変数『a』という箱に”cototoco”という文字を入れたイメージですが、「String(文字列)オブジェクト”cototoco”に、『a』とラベルを付けた」と、言うとらえ方もsample0よりわかります。
*)変数はオブジェクトにつける名札 Ruby リファレンスマニュアルの用語集 変数より

a = "cototoco"
p a.class # => String
p a.object_id # => 540010740

注) すべてオブジェクトと記載しようとして思い調べてみたら、違うようです。
メソッド,ブロック,演算子のand, or 等々はオブジェクトではないとのことです。
Rubyでは、すべてがオブジェクト。じゃないよ! – このブログは証明できない。

オブジェクトのコピー[導入部]

文字列オブジェクト『a』を『b』に代入してみます。
『a』と『b』のobject_idが同じ値になっていることから、ラベルの違う『a』と『b』は同じオブジェクトを参照していることが分かります。同じオブジェクトなので、内容も同じです。しかし、object_idが1つなのでオブジェクトはコピー(複製)されていません。

a = "cototoco"
p a.class # => String
p a.object_id # => 540009530
b = a
p b.class # => String
p b.object_id # => 540009530

ここで、『a』に別の値を入れてみます。
すると、『a』は初期化されので、新しいobject_idが振られていることが分かります。
『a』と『b』は別々のオブジェクトになり、中の文字列も別々の値になっています。
『a』の値を変更しても、『b』の値は保持されているので、複製の目的は成り立っています。

# sample1の続き
a = ".net"
p a.object_id # => 539434520
p b # => "cototoco"
p b.object_id # => 540009530

オブジェクトのコピー[本題]

さて、『a』が配列オブジェクトの場合もStringオブジェクトと同様の結果になりますが、少し注意することが必要です。
『a』の配列の中の値を変更する場合、『b』の値も変更されてしまいます。

a[1]の値を変更した結果、b[1]の値も変更されています。不思議に感じますが、object_idを調べてみると『a』と『b』は同じオブジェクトを参照していることがわかります。『a』と『b』の参照先は同じなので、『a』を変更するということは、『b』を変更することになります。

a = [3, 7, 9, 2]
b = a
p a[1] # => 7
a[1] = 10
p a # => [3, 10, 9, 2]
p b # => [3, 10, 9, 2]
a.object_id # => 540642090
b.object_id # => 540642090

『a』と『b』を別々のオブジェクトにするとこの動作がなくなります。

1, 『a』を初期化する。sample2の様に、『a』に改めて値を代入します。

a = [3, 7, 9, 2]
b = a
a = [3, 10, 9, 2]
p a # => [3, 10, 9, 2]
p b # => [3, 7, 9, 2]
a.object_id # => 539950350
b.object_id # => 539958810

2, clone, dup メソッドを使う。
cloneメソッドはオブジェクトの複製を返すメソッドです。(リファレンスマニュアル

a = [3, 7, 9, 2]
b = a.clone
a[1] = 10
p a # => [3, 10, 9, 2]
p b # => [3, 7, 9, 2]
a.object_id # => 540474720
b.object_id # => 540331010

配列オブジェクトの複製は、cloneメソッドsample5かsample4の方法を持ちいりましょう。

破壊的メソッドはレシーバ自身を変更する

以前の記事、配列 メソッドについてのように、破壊的メソッドはレシーバ自身を変更します。
この時、意図せずsample3パターンにはまってしまう時があります。

例えば、配列『arr_a』に値を追加する時、現在の値を『temp』に保存する場合を考えます。
配列に値を追加するメソッドにpushがあります。pushは破壊的メソッドなのでレシーバを変更します。
では、『arr_a』を『temp』に保存し、『arr_a』にpushで値を追加してみます。

arr_a = [3, 7, 9, 2]
temp = arr_a
arr_a.push(100)
p temp # => [3, 7, 9, 2, 100]

状態を保存したはずの『temp』の値まで変更されてしまいました。
このようなときはsample5のように、cloneメソッドを持ちいりましょう。

Rubyでは、すべてがオブジェクト。じゃないよ! – このブログは証明できない。
リファレンスマニュアル

Latitude E7240 メモリ増設

先日購入した『Latitude E7240』にメモリを追加しました。

Latitude E7240(7000シリーズ)はUltrabookブックにしては珍しく、バッテリーの取り外しができ、メモリ増設や、SSDの交換も比較的簡単に行えます。

増設したメモリ

Kingston DDR3L 1600MHz (PC3-12800)
Non-ECC CL11 SODIMM (204pin) 1.35V
型番:KVR16LS11/4

2014-06-10 21.07

DDR3ではなく、低電力のDDR3Lが必要です。

オーナーズマニュアル

増設方法などは、DELLのサイトからダウンロードできる、オーナーズマニュアルを参考にします。液晶やキーボードの交換まで記載されています。

交換方法

交換方法は非常に簡単です、ネジはたった2本外すだけでOKです。
バッテリーを外し、赤矢印の2か所のネジを外し、カバーを下方向にずらすだけで、メモリースロットにアクセスできます。空いているスロット(写真左側)に購入したメモリーをセットして完了です。

DSC00308

 

写真の赤枠の個所、mSSDがちょうど入りそうなスペースがあります。

「mSSDが追加できる!!」

と思ってよく見ると、mSATA端子がなく、ただ『穴』が空いているだけでした・・・。

 

cpuz201406

Hyundai, Kingston 相性が心配でしたが、Dual Channel で8G認識しているようです。
しばらく様子見です。

ruby

配列 メソッドについて

前回の続きです。前回配列の操作について記事にしましたが、ここでは配列クラスの標準メソッドで便利そうなのを抜粋します。
このページは随時追加更新していくと思います。

配列のメソッド(class Array)

Rubyのメソッドやメソッドの詳細を探すときは、リファレンスが一番です^^;
他にも、逆引きをまとめてくれている方のサイトなどとても助かります。ありがたく参考にしましょう。
メソッドは、当記事で一部を抜粋して紹介しております。

破壊的メソッド

メソッドの中には、レシーバ(元々のオブジェクト)自身の内容を変更してしまうものがあります。このようなメソッドをRubyでは『破壊的メソッド』と名付けられています。

下のsampleのように、「first」,「sort」メソッドはレシーバ(配列オブジェクト)自身には変化が無く、破壊的メソッドである「shift」,「sort!」実行後は、レシーバ自身に変更が反映されていることがわかります。

# 破壊しないメソッド
array = [5, 3, 8, 4]
p array.first => 5
p array => [5, 3, 8, 4]
p array.sort => [3, 4, 5, 8]
p array => [5, 3, 8, 4]

# 破壊的メソッド
array = [5, 3, 8, 4]
p array.shift => 5
p array => [3, 8, 4]
p array.sort! => [3, 4, 8]
p array => [3, 4, 8]

「sort」のように「!」が付いているものは確実に破壊的メソッドですが、「shift」のように見た目では分からないものもあります。(shiftの意味を考えれば破壊的メソッドです。)
メソッドが破壊的な振る舞いをするか曖昧な場合は、マニュアルやsampleなどで確認してから使用するようにしましょう。 特に配列は思っていた結果と違う場合などに、この辺を疑ってみると良いかもしれません。

メソッド(Class Array)

追加、削除など
.unshift # 先頭要素に追加
.shift # 先頭の要素を返し、レシーバの先頭要素を削除する
.push # 末尾に追加
.pop # 末尾の要素を返し、レシーバの末尾要素を削除する
.first # 最初の要素を返す
.last # 最後の要素を返す

.max # 要素の最大値を取得
.min # 要素の最小値を取得
length, size

配列の要素数を返す

array = [1, 2, 8, 4, 10]
p array.length # => 5
p array.size # => 5
array = [[1, 2], [8, 4, 10]]
p array.length # => 2
p array.size # => 2
# size, length はエイリアスの関係

知っとくと便利そうなメソッド

下記にサンプルを載せています。

.flatten # 多重配列を平坦化する。
.delete(x) # xの要素を全て取り除く
.reject # 条件に一致した場合、取り除く
.slice(x..y) # 指定した部分を取りだす
.uniq # 重複要素を削除する [1,1] => [1]
.sort # ソート
.reverse # 逆順にする
.join # 要素を任意の文字列で区切った文字列を取得
.split# 文字列を配列に変換
.select # 条件を満たす要素を抽出
.index # 要素を探すし、その位置を返す
.map # 各要素にブロックを実行し配列を返す
.choice # ランダムに取得する。
.max_by # 条件付きの最大値
.min_by # 条件付きの最小値
.transpose # 転置配列を返す
flatten

多重配列を平坦化する

array = [[1, 2], [8, 4, 10]]
p array.flatten # => [1, 2, 8, 4, 10]
p array # => [[1, 2], [8, 4, 10]]
p array.size # => 2
p array.flatten.size # => 5
delete

xの要素を全て取り除く

array = [ "momo", "banana", 100, 100, "momo" ]
p array.delete("momo") # => "momo"
p array # => ["banana", 100, 100]
reject

条件に一致した要素を取り除く(「reject!」)

array = [1, 2, 3, 4, 5, 6, 7, 8, 9]
p array.reject { |val| val < 5 } # => [5, 6, 7, 8, 9]
p array # => [1, 2, 3, 4, 5, 6, 7, 8, 9]
p array.reject! { |val| val < 5 } # => [5, 6, 7, 8, 9]
p array # => [5, 6, 7, 8, 9]
slice

指定した部分を取りだす(「slice!」取り除く)

array = [8, 3, 4, 6, 10, 2]
p array.slice(2,2) # => [4, 6]
p array.slice(2..4) # => [4, 6, 10]
p array.slice!(2,2) # => [4, 6]
p array # => [8, 3, 10, 2]
uniq

重複要素を削除する

array = [ "momo", "banana", 100, 100, "momo" ]
p array.uniq # => ["momo", "banana", 100]
p array # => ["momo", "banana", 100, 100, "momo"]
array.uniq! # => ["momo", "banana", 100]
p array # => ["momo", "banana", 100]
sort

ソート

array = [ 7, -2, 4, 10 ]
p array.sort # => [-2, 4, 7, 10]
p array # => [7, -2, 4, 10]
p array.sort! # => [-2, 4, 7, 10]
p array # => [-2, 4, 7, 10]
reverse

逆順にする

array = [ 7, -2, 4, 10 ]
p array.reverse # => [10, 4, -2, 7]
# 大きい順
p array.sort.reverse # => [10, 7, 4, -2]
p array # => [7, -2, 4, 10]
join

要素を任意の文字列で区切った文字列を取得

array = [ "momo", "banana", "mikan", "sumomo"]
p array.join("+") # => "momo+banana+mikan+sumomo"
p array.join(",") # => "momo,banana,mikan,sumomo"
p array.join() # => "momobananamikansumomo"
split

文字列を任意の文字列で区切り配列に変換

text = "hoge\nmoge\ntoge\n"
p array = text.split("\n") # => ["hoge", "moge", "toge"]
text = "123,456,789"
p array = text.split(",") # => ["123", "456", "789"]
text = "123,456,789"
p array = text.split(",").map(&:to_i) # => [123, 456, 789]
index

要素を探すし、その位置を返す。

array = [ "banana", 100, 352.6, 9, 100 ]
p array.index("banana") # => 0
p array.index(352.6) # => 2
p array.index(300) # => nil
# 文字列時
string = "cototoco.jp"
p string.index(".") # => 8
sample(x)

x個の要素をランダムに取得する

array = [ "momo", "banana", "mikan", "sumomo"]
p array.sample # => "banana"
p array.sample(2) => ["sumomo", "mikan"]
p array = [ "momo", "banana", "mikan", "sumomo"]
max_by,min_by

条件付きの最大値,条件付きの最小値

array = [ "momo", "banana", "mikan", "sumomo"]
p array.max_by {|val| val.length } # => "banana"
array = [ 2, -6, 5, 8 ]
p array.min_by {|val| val * val } # => 2
transpose

転置配列を返す

array = [[1,2,3],[4,5,6],[7,8,9]]
p array.transpose # => [[1, 4, 7], [2, 5, 8], [3, 6, 9]]
p *ary.transpose
# => [1, 4, 7]
# => [2, 5, 8]
# => [3, 6, 9]
p array # => [[1, 2, 3], [4, 5, 6], [7, 8, 9]]

配列からハッシュを作る(おまけ)

array = ["apple", 50, "banana", 100, "orange", 150]
hash = Hash[*array]
p hash # => {"apple"=>50, "banana"=>100, "orange"=>150}

オブジェクト指向スクリプト言語 Ruby リファレンスマニュアル

逆引きRuby – 逆引きRuby

配列 – 逆引きRuby