ざっくりん雑記

プログラミングで忘れそうなことをひたすらメモる

Ruby - 配列を列として扱う

配列は列としてみなすことができる

まわりくどいので、ズバッと言うとキュースタックというデータ構造としてみなすこともできる。 このキューやスタックは対等的なデータ構造と言えるが、どちらも

  • 要素を追加し
  • 追加した要素を取り出す

といった操作は共通している。

これをArrayクラスはメソッドとして持っている。

キュー

キューは、最初に格納した要素が、一番最初に取り出される、つまりFIFO(First-in First-out)なデータ構造。

はじめに、キューメソッドとして用意されているのは要素を追加する、要素を取り出すのみなのを意識すると理解しやすいです。

具体的に説明すると、

f:id:azuuun:20160413005731p:plain

まずこのような配列があったとします。 既に要素としてAから順番にDまで格納されています。

ここに、新たに要素を格納するとします。

f:id:azuuun:20160413005740p:plain

するとこのように、Dの後ろに新たな要素がINします(追加されます)。

今度はデータを取り出してみます。 FIFOの原則として、最初に格納したものを最初に取り出す、が前提なので、何が取り出されるかというと、

f:id:azuuun:20160413005743p:plain

このようにAがOUTします(Aが取り出されます)。

最終的には以下の様な配列になります。

f:id:azuuun:20160413005746p:plain

これが、キューです。

スタック

キューの対等的なスタックは、最後に入れたものが最初に取り出される、つまりLIFO(Last-in First-out)なデータ構造です。

これも図でみるとわかりやすいです。

まず、先程と同様にAから順にDまで追加したスタックがあります。原則として、一番上のものしか取れない構造になっていることに注意して下さい。

f:id:azuuun:20160413011036p:plain

ここに新たに要素をINします(追加します)。

f:id:azuuun:20160413011039p:plain

すると一番上に、新たな要素であるEが積み上がる形になります。

f:id:azuuun:20160413011042p:plain

次にデータを取り出してみたいと思います。LIFOの原則なので、ここでは一番最後に追加したEが最初に取り出されます。

f:id:azuuun:20160413011045p:plain

キューとスタックまとめ

キュー

f:id:azuuun:20160413012337p:plain

スタック

f:id:azuuun:20160413012340p:plain

Rubyでどう書くか

キュー

sushi = %w(まぐろ サーモン いくら とびっこ)
p sushi.push('うに')    # うにをIN
p sushi.first                # 最初に入れた要素を参照する
p sushi.shift              # 最初の要素(まぐろ)を取り出す
p sushi
["まぐろ", "サーモン", "いくら", "とびっこ", "うに"]
"まぐろ"
"まぐろ"
["サーモン", "いくら", "とびっこ", "うに"]

スタック

sushi = %w(まぐろ サーモン いくら とびっこ)
p sushi.push('うに')   # うにをIN
p sushi.last                # 最後に入れた要素を参照する
p sushi.pop               # 最後に入れた要素(うに)を取り出す
p sushi
["まぐろ", "サーモン", "いくら", "とびっこ", "うに"]
"うに"
"うに"
["まぐろ", "サーモン", "いくら", "とびっこ"]

参考

たのしいRuby 第5版

たのしいRuby 第5版

Ruby - 配列を集合として扱う

インデックスでいじるだけが配列じゃない

配列を操作するとき、どれを取り出すか、どこからどこまでを置き換える、どこに挿入するか、といったインデックスを意識したようなものが多い印象がある。

しかし、配列のArrayクラスは、「インデックス付きオブジェクト」の集まりに過ぎず、集合としての配列という、インデックスを意識しない配列の使い方もあることもある。

「インデックスを意識しない配列の使い方」とは、[1,2,3][3,1,2][1,3,2]も全て同じ集合を表している、考えることが出来る、ということ。

なので、インデックスを意識した操作は、Arrayクラスの持ったメソッドの一部でしかない。

集合の演算

基本的に、集合の演算というと、AND(共通集合)とOR(和集合)である。

  • AND(共通集合)
    • 2つの集合どちらにも含まれる要素を抽出し 新たな集合を作る
  • OR(部分集合)
    • どちらか一方に含まれる要素を抽出し 新たな集合を作る

以上の演算は、Rubyのコードで表すと

  • AND(共通集合)=> array1 & array2
  • OR(部分集合)=> array1 | array2

となる。

また、Rubyでは補集合(ある集合からその集合に属していない要素を抽出する)がない。それは、Arrayクラスに全体集合に相当するものが定義されていないからで、その代わりに、ある集合からある集合の差を求める差の演算が可能。

  • 差の演算 => array2 - array1

具体的な例

array1 = %w(1 2 3 4 5 6 7 8 9 10)
array2 = %w(2 4 6 8 10)

p (array1 & array2)
p (array1 | array2)
p (array1 - array2)
["2", "4", "6", "8", "10"]
["1", "2", "3", "4", "5", "6", "7", "8", "9", "10"]
["1", "3", "5", "7", "9"]

|+

集合を結合させるメソッドである|(OR)と+は、似てるようで、一部振る舞いが違うことに注意。

  • |(OR)
    • 2つの集合で被った要素はその要素は1つのみ含まれる
  • +
    • 2つの集合で被った要素はその数だけ含んでいく

具体的な例

array1 = %w(1 2 3 4)
array2 = %w(2 4)

p (array1 | array2)
p (array1 + array2)
["1", "2", "3", "4"]
["1", "2", "3", "4", "2", "4"]

参考

たのしいRuby 第5版

たのしいRuby 第5版

Ruby - 配列におけるインデックス

要素の取り出し方いろいろ

要素を取り出す方法は、さまざまある。

  • array[n]
  • array[n..m] , array[n...m]
  • array[n, length]

簡単な例として以下に示す。

season = ['はる', 'なつ', 'あき', 'ふゆ']

p season[0] # はる
p season[0..3] # はる なつ あき ふゆ (配列)
p season[0, 2] # はる なつ (配列)
"はる"
["はる", "なつ", "あき", "ふゆ"]
["はる", "なつ"]

または、これらをメソッドに置き換えても書ける

  • array.at(n)
  • array.slice(n)
  • array.slice(n..m)
  • array.slice(n, length)
p season.at(0) # はる
p season.slice(3) # ふゆ
p season.slice(0, 2) # はる なつ (配列)
"はる"
"ふゆ"
["はる", "なつ"]

あまりメソッドで取り出す方法というのは行わないっぽい。

要素を置き換える

一つの要素を置き換える

まず、一つの要素のみを置き換えたい場合はかんたんにarray[index] = valueというかたちで代入する感じで置き換えることができる。

direction = ['', '西', '', '']

direction[0] = 'east'
direction[3] = 'north'

p direction
["east", "西", "南", "north"]

複数要素を置き換える

直感的に、複数要素を置き換えることができる。

direction[1..2] = ['west', 'south']
p direction
["東", "west", "south", "北"]

要素を挿入する

今ある要素に変更を加えず、配列に新たな要素を追加したい場合に、挿入操作を行う。

あまり直感的ではないかもしれないが、挿入の考え方として、0個の要素と置き換えるとみなして、コードを書く。つまり[n, 0]とするとインデックスがnの要素の前に挿入される。

一つの要素を挿入する

direction = ['', '西', '', '']
direction[1, 0] = ['東と西のまんなか']
p direction
["東", "東と西のまんなか", "西", "南", "北"]

複数要素を挿入する

こちらも、似たような感じで行えばよくて、挿入する配列の要素を増やせば増やした分だけ挿入される感じ。

direction = ['', '西', '', '']
direction[1, 0] = ['東西 その1', '東西 その2']
p direction
["東", "東西 その1", "東西 その2", "西", "南", "北"]

とびとびの要素をかいつまんで、配列にする

冒頭で書いた要素の取り出し方は、連続した要素番号だけ対応できた。しかし、複数のインデックスを指定して、それを一つの配列にする、といったことはできなかった。

そういったことをしたい場合はarray.value_at(n1, n2, ...)メソッドを利用する。

sushi = %w(まぐろ サーモン いくら うに かに えんがわ)
p sushi.values_at(0,2,4)
["まぐろ", "いくら", "かに"]

うまく取り出すことができている。

参考

たのしいRuby 第5版

たのしいRuby 第5版

Ruby - 配列の作り方いろいろ

Rubyでの配列の作り方

Array.new

array = Array.new
p array
array = Array.new(3)
p array
array = Array.new(5, 'Ruby')
p array
  • 何も指定しない
    • そのまま0個の配列ができる
  • 引数を1つだけ(数値)
    • その引数の数だけnilの要素が入った配列ができる
  • 引数を2つ
    • 1つの目の引数:要素数を指定
    • 2つの目の引数:格納したい値 で配列ができる
[]
[nil, nil, nil]
["Ruby", "Ruby", "Ruby", "Ruby", "Ruby"]

%w, %i

要素に空白が含まれていない、つまりそれぞれの区切りが明確になっている場合のみ、使える %w, %i

neta = %w(まぐろ サーモン えび かに うに)
p neta

neta2 = %i(まぐろ サーモン えび かに うに)
p neta2
["まぐろ", "サーモン", "えび", "かに", "うに"]
[:まぐろ, :サーモン, :えび, :かに, :うに]

%wは文字列の配列をつくりたいときに、%iは文字列がシンボルの配列となる。

to_a

配列の作り方としては、あまりメジャーでないがこれでもできなくはない、的なもの。 to_aは多くのクラスで定義されているメソッドでそれぞれのオブジェクトを配列に変換してくれる。

sushi_hash = {
    :maguro => ['まぐろ', 100],
    :salmon => ['サーモン', 120],
    :egg => ['たまご', 150]
}

sushi_array = sushi_hash.to_a

p sushi_array
[[:maguro, ["まぐろ", 100]], [:salmon, ["サーモン", 120]], [:egg, ["たまご", 150]]]

例ではハッシュを配列に変換している。

文字列split

あらゆる情報がカンマで句切られた一つの文字列をsplitメソッドで分割した結果が配列になるパターン。 わりと使われる手法。

person = "寿司太郎,男,まぐろが好き,2016-4-12"
profile = person.split(',')
p profile
["寿司太郎", "男", "まぐろが好き", "2016-4-12"]

参考

たのしいRuby 第5版

たのしいRuby 第5版

Ruby - 配列やハッシュの繰り返し each

配列の要素をいい感じに取り出して利用する

eachメソッドは「イテレータ」という種類のメソッドで、以下のような構文

配列.each do |変数|
    繰り返したい処理
end

または

配列.each{|変数|}
    繰り返したい処理
end

最初の例では、each以降のdo ~ endの部分はブロックと呼ばれる部分で、こういった構文のため一般にブロック付きメソッドとも呼ばれる。ふたつ目の例はdoを省略したかたちで、基本的にこちらほうが見やすそう。

|変数|という部分では、配列から1つずつ取りだす際に使う変数名を指定することができる。その変数をブロック内で利用することになる。なのでわかりやすい命名をしたい。

基本的な使い方の例

基本は配列もハッシュも同じような構文で、ハッシュの場合は変数を2つ設定できる。以下にハッシュの場合を示す。

neta = {
    :maguro => 'まぐろ',
    :salmon => 'サーモン',
    :tamago => 'たまご'
}

neta.each do |key, value|
    puts "#{key}:#{value}"
end
$ruby array_prac.rb
maguro:まぐろ
salmon:サーモン
tamago:たまご

いろんな使い方

ブロック的に使わないでかんたんに書きたいとき

neta.each{|en, ja| puts "#{en}を日本語で, #{ja}と言う!"}
$ruby array_prac.rb
tunaを日本語で, まぐろと言う!
salmonを日本語で, サーモンと言う!
eggを日本語で, たまごと言う!

ハッシュの深さがある場合

変数指定に括弧を使えば、いい感じにやってくれる。

neta = {
    :tuna => ['まぐろ', 100],
    :salmon => ['サーモン', 200],
    :egg => ['たまご', 300]
}

neta.each{|id, (name, price)| puts "#{id}: #{name}, #{price}"}
$ruby array_prac.rb
tuna: まぐろ, 100
salmon: サーモン, 200
egg: たまご, 300

参考

たのしいRuby 第5版

たのしいRuby 第5版

qiita.com

PHP - print_r()とvar_dump()について

print_r()var_dump()は、渡された内容を見やすい形式で出力する。文字列や数値の場合はecho, print()と同様に単純に文字列として出力する。

配列の場合は、以下のように出力する。

<?php

$a = array('name' => 'azunobu', 'age' => 20, 'location' => 'Iwate');
print_r($a);
var_dump($a);

出力

Array
(
    [name] => azunobu
    [age] => 20
    [location] => Iwate
)

array(3) {
  ["name"]=>
  string(7) "azunobu"
  ["age"]=>
  int(20)
  ["location"]=>
  string(5) "Iwate"
}

オブジェクトの場合は、以下のように出力する。

<?php
class Sample {
    var $name = 'azunobu';
}

$o = new Sample;
print_r($o);
var_dump($o);

出力

Sample Object
(
    [name] => azunobu
)

object(Sample)#1 (1) {
  ["name"]=>
  string(7) "azunobu"
}

print_r()とvar_dump()の違い

まず、print_r()論理値やNULLだとうまく表示してくれない。

print_r(true);    // "1"を出力
print_r(false);    // ""を出力
print_r(null);    // ""を出力

一方、var_dump()は、論理値やNULLであっても表示してくれる。

var_dump(true);    // "bool(true)"と出力
var_dump(false);    // "bool(false)"と出力
var_dump(null);    // "bool(null)"と出力

以上のことから、デバッグ時に使うとすれば、人間的に読みやすい形式で出力してくれるvar_dump()のが使い勝手が良さそう。

なお、出力された値をブラウザで確認する際は、ソースを見たほうが改行がうまく効いて見やすい。Chromeであればページの適当なところを右クリックし ページのソースを表示で表示できる。

参考

プログラミングPHP 第3版

プログラミングPHP 第3版

PHP - ヒアドキュメント

複数行にまたがる文字列を出力したいとすると、文字列を連結したり、以下のように

<?php

echo '照りつける 太陽 照り焼けちまいそう\n';
echo 'ハードボイルドだろ? パネェだろ?\n';
echo 'キモい カワイイ 賛否両論 NO MORE WAR\n';
...

echoしまくる感じになるが、ちょっと面倒くさい。

ヒアドキュメントを使う

ヒアドキュメントを用いれば、複数行にまたがる文字列を手軽に書ける。

$str = <<< "EndOfQuote"
照りつける 太陽 照り焼けちまいそう
ハードボイルドだろ? パネェだろ?
キモい カワイイ 賛否両論 NO MORE WAR
サブカル 女子 凝視 酢飯飛び散る
Let's go to the animation
寿司くん!
EndOfQuote;

var_dump($str);

出力

string(260) "照りつける 太陽 照り焼けちまいそう
ハードボイルドだろ? パネェだろ?
キモい カワイイ 賛否両論 NO MORE WAR
サブカル 女子 凝視 酢飯飛び散る
Let's go to the animation
寿司くん!
"

改行も含まれている。

<?php

printf(<<< "Template"
%s is %s.
Template
, "寿司くん", "Sushi");

出力

寿司くん is Sushi.

書き方

<<< [識別子]というトークンが、ヒアドキュメントの開始を示す。 <<<[識別子]の間には半角スペースが1つ必要。文字列を書き終えたら、改行し識別子を示すことで、文字列の終端を示す。

また、PHP 5.3.0 以降では、ヒアドキュメントの宣言をダブルクォートで囲めるようになった。

ダブルクォーテーション、シングルクォーテーション、空白などが素直に出力される。

寿司くん

参考

プログラミングPHP 第3版

プログラミングPHP 第3版

PHP: 文字列 - Manual