Rubyまとめver3

環境:Windows10Pro64bitバージョン1909、Ruby2.5

※おことわり – ほぼ備忘録として書いてます。誤解、ウソ、間違いは申し訳ございません。

少し離れると忘れてしまう。忘れないくらい可能な限り覚えることを少なくしたいと思いました。

まずはRubyの入門書を最低1冊は読んでいることを前提としています。

本記事は以下の「Rubyまとめver2」をさらにまとめたものです。

  1. 【この記事の使い方】
  2. 少ないことは良いことだ!?
  3. 「いやいや、ググればよくない?」
    1. ググれば解決です
    2. WordPressで自分マニュアルのすすめ
  4. 考え方
    1. 怠慢上等、冗長上等
    2. プログラマーへのあこがれと勘違い
    3. gemと外部ライブラリと標準ライブラリ
    4. 数冊の入門書程度の知識を前提で本記事は書いてます
    5. 悪魔のささやき
    6. とにかく数字列と配列でナントカする
  5. String(Numeric、Integer含む)
  6. Array
  7. Arrayの特徴「ループ」
    1. 【例】select
  8. 個人的にちょっと説明が必要なArray#zipについて
  9. 意外と使えるArray#flatten
  10. ひとまずStringとArrayのきほんを終了して、ここからは追加情報です
    1. 【万能メソッドの5つ引数表現】
    2. 【Arrayクラスのpopとshiftを使って配列のアクセス方法の勉強をする】
    3. 【もっとArrayオブジェクトのデータ追加、削除を例にしてアクセスの達人になる!?】
    4. データの追加と削除の本質って?
  11. 探索
    1. 【探索メソッドString】
    2. 【探索メソッドArray】
  12. CRUD
    1. 【StringオブジェクトのCRUD】
    2. 【ArrayオブジェクトのCRUD】
  13. 余談と感想と雑記
    1. 【扱う主なデータ】
    2. 【正規表現のおそろしさ笑】
    3. 【冗長の効用?】
    4. 【副作用】
    5. 【復習】
    6. 【基本使わないけど実験して挙動が面白かったString#inspect】
    7. 【ハッシュは?】
    8. 主観的なおかつ直感的にしっくりくるものたち
    9. 「汎用的なメソッドを利用して、頻度の多い記述でなんでも出来るようにしたい」?
    10. 実際処理するデータ
    11. Filey読み書き
  14. どういう基準で削減したか?なぜ大幅に削減したか?何を削減したか?
    1. 【参考】
    2. 【例】Array#pop
    3. 【例】Array#shift
    4. 【例】String#upcase,downcase
    5. 【例】String#chop
    6. 【例】String#chomp
    7. 【例】Array#insert
    8. 【例】Array#min,max,minmax
    9. 【例】Array#sum
    10. 【例】String#squeeze
    11. 【例】Hash#keys,values
    12. 【例】Array#first, last
    13. 【例】String#slice
    14. 【例】「=~」

【この記事の使い方】

  1. メモ帳かワードかなんかにコピペする
  2. プリントアウトする。縮小OK、複数ページOK。複数部作っておきます。
  3. 赤入れして線を引いていく。これらを繰り返す。

をおすすめします。

前半は能書きなので、具体的な記述から読みたい人はこちら


少ないことは良いことだ!?

後述してますが、Rubyをやっている期間はRuby脳になっているのでとてもいい感じです。Rubyスキルが一時的に上がっているからです。

そこからちょっと用があって、HTML、CSS、Bootstrap、Javascript、jQuery、PHP、マクロ、SQL、Webデータベース、TCP/IPなどに数ヶ月費やしてRubyに戻ってくると、言い過ぎかもしれませんがRuby脳がスッカラカンになります。そもそも私のスペックの問題かもしれません。

ほかをいじって帰ってくると、やっぱりRubyはラクなのでこれからも使っていきたいと思っています。しかし、同じようなことが毎回あってはちょっと人生無駄にしてしまう気がしましたので以下の対応を考えました。

  • 完全に頭に入れるか
  • すぐに情報にアクセスできるようにするか
  • Ruby脳に切り替える、または想起させるスイッチを作成する

これらを構築したほうがいいと思いました。

たくさんのメソッド、記述方法、構文などを覚えたほうが選択肢の幅が増えることは確かです。覚えられるなら覚えたほうがいい!これは絶対です。あくまでも「覚えられるなら」です。人生なんでもそうですが…笑。記憶力が良くて、それを利用する気持ちがあれば人生をイージーに過ごせるひとつの秘訣です。


「いやいや、ググればよくない?」

ググれば解決です

その通りです。ググればそれで解決です。

しかし他の記事でも書いていますが、頭の中にあるほうが情報のアクセスは圧倒的に速いです。月とすっぽんくらい差があります。これは人生のすべてにおいてです。

おいしい店を検索するより、雑誌で目にした内容を記憶していたほうが速いです。自分のメモ帳を見たほうが速いときもあります。

Ruby脳がなくなったとき、同じことをググるのが面倒になります。

「これ前やったじゃん…」って。

要は効率が悪く二度手間でバカなんですね。これは人それぞれですが。「バカ」は自分に言っています。(やはり私のスペックの問題か悲笑)

「俺、私はとにかくググる。別に手間でもないし、空中(ネット)から情報をいつでも引っ張れるのはいいことだ!」というのもその通りです。

自分の言葉ではっきりと目的、説明が出来ることが重要です。これはプログラムを書くときも重要です。コメント入れとか。

個人的には冗長でもコードに無駄があってもソラでコードを書けることがいまの目的です。私の作成するプログラムは事務作業を無人化したり、簡単なWebシステムだったり、めんどくさいことを自動化する程度のものですから。

WordPressで自分マニュアルのすすめ

もうひとつ。ググって情報が空中にあって、いつでもどこでも答えが取り出せるのはいいことです。しかし、一度やったことに関しては回答スピードを速くしたいと思います。だからWordPressに記録しておくことをおすすめします。

自分がすぐ取り出せるように自分の言葉で書いておくことは、CPUとメモリとハードディスクの関係に似ていると思いませんか?そして少しだけマネタイズできればハッピーですね。

自分マニュアルの作成をおすすめします。WordPressめっちゃ簡単ですよ!

記録することは料理でもそうだし、ダイエットでも、エクセルも、逆上がりの上達方法(動画?)も全部大事です。大きく言えば人類の財産になり得ます。


考え方

怠慢上等、冗長上等

メソッドをたくさん覚えるより、覚えることを少なくして、汎用的な知識をフル活用して、なんとかゴールにたどり着ければOKという考えです。すいません。

個人的に、「少ない基礎」をしっかり固めるのとやりたいことを実現するまでの過程や考え方に集中したほうが性に合っているかもしれないです。

もし制作物に需要があるなら費用をかけてリファクタリングすればいいって思います。

「そんなに利用されていて需要があるなら、逆にリファクタリングしないといけません!」ってことです。そのときはカネ払ってやらせればいいんです!「Write, Code!!」ってね。言い方乱暴ですね。ムカつきますね。確か映画ソーシャルネットワークの誰かのセリフでありませんでしたっけ?

自分は次のプロジェクトにさっさと移りましょう!

プログラマーへのあこがれと勘違い

いままで「プログラマーってアイディア豊富でみんなクリエイターなんだな!なんでも自分で作れんだな!すげぇな!」と思っていました。しかし、それはほんとにごくわずかのようです。

開発畑で働いていないのでそれを知るのに時間がかかりましたが、超有名某ビッグアプリ・サービス開発者の講演会に参加するチャンスがあり、スーパープログラマーと話をする機会がありました。大事なところだけ伝えますが「タイプライターがほぼだよ」とのことです。

だから、もしかしたら自論の「リファクタリングはカネでやらせる」は強ち間違っていないような気がしてきました。

gemと外部ライブラリと標準ライブラリ

「requireするもの」と思ってください。

これらに関しては、リファレンスに忠実に従うか、Google検索結果の使えるコードをコピペして、少し変更するくらいで最初はいいと思っています。

数冊の入門書程度の知識を前提で本記事は書いてます

本サイトでRubyまとめver1、ver2の記事を書きましたが、やはりRuby以外の開発から帰ってくると、自分で書いておきながら復習するのにかなり時間がかかります。そもそも自分で書いといて読む気になりません。そんな記事誰が読むでしょう?本記事はこの記事を参考にして削れるところを吟味して書いています。きっとこの記事もリライト、アップデートします。

悪魔のささやき

「たくさん削減しよう!2位じゃダメですか?」という心意気で書き始めましたが、ちょいちょい削減出来損なったものがいくつかあります。「いや、これきっと大事な時に使うから取っておけって!」と悪魔がささやくのです。ついでに天使も同調して「そうだよそうだよ!とっておいたほうがいいよ!」と便乗してきます。

とにかく数字列と配列でナントカする

数字と文字列を合わせて「数字列」って言うことにしました。数字と文字列はクラスは違いますが、毎回2つ書くのがめんどくさいです。

この辺りから具体的な記述に入っていきます。長々とすいませ。後日、チート版を作ろうと思っています。

ちなみに以下の表をご覧ください。

略語意味
strString、文字列
num, iNumeric、Integer、数字
reg正規表現、RegularExpression
arrayArray、配列
hashHash、ハッシュ

としています。

続きまして、いよいよ(?)StringとArrayについて記載します。


String(Numeric、Integer含む)

[_Utf-8ハチとJis_\r\n].class.methods.respond_to?("")

最初からワケワカメですね。

このワケワカメ文字列からこちらで勝手に用意した以下の答えを思い出してくれると幸いです。メソッドや知識を想起するワケワカメ文字列ということです。

classメソッドより前に関して、少なくとも以下の12個のメソッドを読み取ってほしいです。

【[]は配列化】

  • chars
  • lines
  • split

【アンダーバーと\r\nは空白文字・改行文字・最後文字削除】

  • strip
  • lstrip
  • rstrip
  • chomp
  • chop

【utfとjis】

  • encode

【全角半角8とハチ】

  • unicode_normalize(:nfkc)

【大文字小文字】

  • upcase
  • downcase

続いてArrayです。


Array

[[2, 3, 1], [1, 2, 3], "str", "str", "a", nil, "c"]<<

また最初からワケワカメですね。

こちらで勝手に用意した以下の答えを想起してくれると幸いです。少なくとも以下の10個のメソッドを読み取ってほしいです。

【配列の中に配列はネスト】

  • flatten

【順番が揃ってないシャッフル】

  • shuffle

【順番通りのソート】

  • sort
  • reverse

【strが2つは重複】

  • uniq

【strから想起する字列化】

  • join
  • to_s
  • inspect

【nilを削除する】

  • compact

【<<】

  • array << data
  • (pushでもいいですよ!内緒。)

Arrayの特徴「ループ」

このセクションはとてもよく使います。マストです。ここにも悪魔のささやきがありましたが、最低限以下のメソッドは抑えましょう。

  • each
  • with_index(num)
  • map
  • select(reject)
  • each_slice(num)
  • zip

詳しい使い方はこちら↓

基本eachの中でifの処理を自由に記述することで「map」「select」「reject」などを代替できます。探索にも利用できます。

他の「with_index(num)」や「each_slice(num)」、「zip」もできそうですが、こっちは覚えたほうが圧倒的に速いです。これでもかなり削減したので覚えてしまいましょう。

【例】select

selectは、「条件に当てはまったものだけの配列を返します。破壊可。」です。よって「reject」も削減してもいいかもです。

array.select! do |ele|
  #ifは要りません。条件式だけ書きます。
end

この式全体が空中に配列を一時作成します。よって保存しないとすぐ消えます。保存方法はselect!で元の配列を破壊するか変数定義するかです。

この考え方はselectに限らずmap、grep、scan等もそうです。

array = ["a", "b", "cat", 1, "d", 2, "e"]

#eachとifでselect

    newarray = []

    array.each do |ele|
      if ele.class == String
        newarray << ele
      end
    end

    p newarray

#select

    newarray = array.select do |ele|
      ele.class == String
    end

    p newarray

個人的にちょっと説明が必要なArray#zipについて

zipメソッドは2つの配列を1つにし、ペア配列を作ります。「ペア配列」という言葉はいま思いつきました。

個人的には2つの配列の各データを比較するときに使います。

しかし、1点注意が必要でした。

簡単に言うと「レシーバーのほうがデータ数が少ないとデータをとりっぱぐれる可能性があります。」

意味不明ですね。とにかくzipメソッドの挙動を見てみしょう!

#普通のzip
array_1 = [1, 2, 3, 4]
array_2 = [6, 7, 8, 9]
array_zip = array_1.zip(array_2)
p array_zip

ペアの2次元配列が作成されましたね。結果は表示しませんよ。コードはコピペでもいいですが、必ず手元で実行してコンソールで確認しましょう笑。上達への一歩です。

比較作業をするときはこのzip配列をeachとかで回してifとか使って処理します。

さて、「注意点」についてです。

下記では「10」という数字が表示されません。

array_1 = [1, 2, 3, 4]
array_2 = [6, 7, 8, 9, 10]
array_zip = array_1.zip(array_2)
p array_zip

レシーバーを逆にすると「10」が見えてきます。

array_1 = [1, 2, 3, 4]
array_2 = [6, 7, 8, 9, 10]
array_zip = array_2.zip(array_1)
p array_zip

個人的な性格もあるかもですが、操作するデータはすべて見えたほうがいいので、データ数に違いがあるならデータ数の多いほうをレシーバーにしてzipメソッドを実行したほうが良さそうです。


意外と使えるArray#flatten

flattenメソッドはネスト配列の[]を取っ払う効果があります。ネストがなくなった普通の(1次元)配列に変更することができます。引数に数字を指定することで次元を制御できます。ですが、ポリシーとしてそれはいまは覚えない候補です。

使い道1

配列と配列を連結したり、追加する「array << [1, 2, 3]」の場合、最後ら辺が2次元配列になってしまいます。

flattenすると解消できます。

使い道2

探索メソッドが利用しやすくなります。「探索」については後述します。

例えば、配列をgrep(/ry/)したい場合

ネスト配列の中に「sorry」があってもgrepはネスト内を拾いません。grepでヒットさせたければ、flattenを使い1次元配列にしてからgrepを使う必要があります。

array_nest = ["lily", "melly", ["sorry", "chelly"], "benly"]
p array_nest.grep(/ry/) #ヒットしませんね…
p array_nest.flatten.grep(/ry/) #ヒットしました!

ちなみに任意の文字列の存在確認だけなら、配列を文字列にして探索すればいいです。 もちろん1次元配列ならgrepでもOKです。

「to_sまたはinspectしてからのscanまたはindex」が利用できます。


ひとまずStringとArrayのきほんを終了して、ここからは追加情報です

ここまでStringとArrayの基礎メソッドをまとめました。

ここから読み進めるにあたり、知っておいたほうがいい情報を記載します。

【万能メソッドの5つ引数表現】

これ重要です。これを覚えておかないと多くのメソッドを覚えることになります(?)。

たくさん覚えることで悪いことは絶対にないですが、この5つの引数パターンがいくつかのメソッドで応用が可能だからです。

5つの引数とStringとArrayがあるので、5×2ですが、Arrayでは引数が数字系だけなので、2を引いて全部で8個です。まぁビジュル的に表を思い出せばいいですね。

[1][1..3][1, 2][“String”][/RegEx/]
String
Array××

引数3番目について

  • [1, 0]
    自分自身の前を示す。ABCで「Bの前」というと、Aではなく、AとBの間を示す。
  • [1, 1]
    自分自身だけを示す。これって[1]と同じでは?
  • [1, 2]
    例だと自分自身を含めて後ろへ2つの範囲を示す。

【Arrayクラスのpopとshiftを使って配列のアクセス方法の勉強をする】

popとshiftを使えばすごく簡単に配列のデータを飛ばせます!

しかし、ここはあえてpopとshiftを使わずに配列の先頭と最後のデータを飛ばしてみましょう!

その記述過程で配列アクセスの方法を学びましょう。

deleteとdelete_atという削除メソッドがありますが、今回はcompactというメソッドを使います。

「nilしてcompact」を覚えれば「deleteはああで、delete_atはこうで、あれ逆か?あれどっちだっけ?(調べる…)」などがなくなります。

【pop「配列の最後を飛ばす」】

popを使えば「array.pop」で終了です。しかし、次のように記述してみました。

#最後のデータへアクセスする方法

array = ["a", "b", "c", "d", "e"]

#こっちのほうが圧倒的に記述が簡単
puts array[-1]

#こっちはlengthメソッドを覚えることができ、さらに「引数に式って入るんだー」を学べます
puts array[array.length - 1]

データにアクセスしたら「nilしてcompact」です。削除したいものをnilにしてからcompactでnilを削除します。

array = ["a", "b", "c", "d", "e"]
array[-1] = nil #最後のデータをnil
p array.compact #破壊しなくても、
array.compact! #破壊してもどちらでもいいです。
p array

【pop(num)「最後から複数のデータを飛ばす」】

いまさらですが、配列のアクセス方法はこちらが参考になります。

Array#[] (Ruby 2.7.0 リファレンスマニュアル)

https://docs.ruby-lang.org/ja/latest/method/Array/i/=5b=5d.html

popを使えば「array.pop(3)」で終了です。しかし、次のように記述してみました。

array = ["a", "b", "c", "d", "e"]
array[-3..-1] = nil
p array.compact

ここで失敗談をひとつ。

まぁリファレンスをよく読んでいないだけなんですけど笑。「後ろから3つを選択したい」と思って「array[-1..3]やarray[-1..-3]」と書きました。わかります?両方とも後ろから前に向かって範囲を選択しています。これはダメです。

「..」を使って範囲指定する場合は「前から後ろへ範囲を選択する」ことが重要です。

考えてみれば、私の失敗のほうが凝ってますよね笑。

「後ろから3番目はシンプルに-3」でいいわけで、後ろ3つの指定したいなら「-3から最後まで」要は「-3..-1」となります。とても直感的です。(いや、直感的じゃないと思ったから間違えたんでしょ笑?)

本質的考え方として「位置を指定する」を覚えればいいですね!

「X..Y」はXもYも、とにかく位置を示すということですね。はい、わかりませんね泣。

〇..〇ということです。XとYの関係が「X < Y」であることが大事です。「範囲指定は小から大、前から後ろへ」ということです。うん、これもわかりません。もう少し日本語を学びましょう。

【shift「配列の最初を飛ばす」】

array.shiftで終了です。しかし、次のように記述してみました。popができれば考え方は同じです。

「位置を指定してnilしてcompact」です。

array = ["a", "b", "c", "d", "e"]
array[0] = nil
p array.compact

【shift(num)「配列の最初の複数のデータを飛ばす」】

先頭3つを削除する。array.shift(3)で終了です。しかし、次のようにも記述できます。

array = ["a", "b", "c", "d", "e"]
array[0..2] = nil
p array.compact

【もっとArrayオブジェクトのデータ追加、削除を例にしてアクセスの達人になる!?】

というより反復記載!?ですかね。

pushとunshiftを覚えておいて損はありません。そして、popとshiftとunshiftとpushでどれがどれだか混乱しなければ覚えておいて損はありません。中でもshiftとunshiftはワケワカメになるのではないでしょうか?

この記事は数日にわたって書いてますが、いい加減記憶してもいいはずなのに、まだunshitとshiftで混乱します。というかもう覚えようと思っていません。

「popは最後を指で弾く(pop)」というふうに覚えていまし、「pushはただ追加」とシンプルに覚えられます。

上記で学んだRubyの配列データへのアクセスの基本と、自分が何をしたいかを明確に持てれば、かんたんにあなたのやりたいことにたどり着くことができます。

  • 「後ろを消したい」という明確な目的があるなら、配列の最後尾または最後から複数にアクセスまたは指定して「nilしてcompact」ですね。
  • 「先頭を消したい」という明確な目的があるなら、shift…ん?unshift?どっちだっけ?まぁいいや。配列の先頭または先頭複数にアクセスまたは指定して「nilしてcompact」ですね。
  • 「データをとにかく追加したい」という明確な目的あるなら後ろにくっつけるだけでOK。追加データが複数あるならeach使って「push」か「<<」を繰り返します。複数を一気に追加したいならpushに引数を入力するか、「<<」に配列を渡します。
  • データを「先頭に」追加したい。shift…ん?unshift?どっちだっけ?まぁいいや。「array[0, 0] = [1, 2, 3]」で追加できます。
  • 疑問。array[array.length] = [1, 2, 3]は2次元だけど、array[0, 0] = [1, 2, 3]は1次元。なぜだ?まぁいいや。

逆に混乱してきましたか?

「こんなに混乱するならpush、pop、shift、unshift、insert、concatとかいろいろ覚えたほうがいいのでは?」と思うでしょうか?私もそう思います。

しかし、どうしても忘れてしまうんですね。

Rubyを10日間やってJavascriptにひと月引越して、またRubyに戻ってくると同じこと調べるんですね。これがすごい無駄なわけです。(いや、明らかに記憶力の問題でしょ悲。)

だから覚えることを極限まで抑えたいんです。

  1. 配列アクセスの達人(万能メソッド)
  2. nil & compact(ブランド名っぽい?ドルチェ&ガッバーナ的な?)
  3. <<(内緒でpushも。)

これら3つでなんとかいける気がします。

データの追加と削除の本質って?

先頭削除も部分削除も「削除は削除」でしょ?

pop、shift…ん?unshift?どっちだっけ?、あとslice(部分削除)などの多くのメソッドを「絶対に覚えないといけない!」わけではないと思います。それなら配列へのアクセス方法の達人になって、データ操作をできるようになればいいと思いました。

とにかく忘れてしまうんです。プログラミング向いてないよな。

削除と追加についてもうちょっと言います。

インデックス番号ではなく、ある文字列を指定して削除したいならeachで回してifで当てはまったらnilにしてcompactします。ほかには削除対象データを抜いた新しい配列を作る処理でもいいですね。あとselectやmapを使っても出来そうですね。あとは「index(“str”)」で開始位置を特定し、あとはnilしてcompactです。

push、shift…ん?unshift?どっちだっけ?まぁいいや、insert、「<<」構文などがありますが、配列へのアクセスを上達させて「[] = 」の万能メソッドで追加すればいいです。あと最後尾に「<<」を使って「配列を追加」したときは2次元配列になるのでflattenを覚えておけばいいと思います。位置にこだわらず、ひとつずつデータを追加するなら「<<」だけ覚えればいいです。

あと削除のところでも触れましたが、インデックス番号ではなく、ある文字列を指定してその前後にデータを追加したいなら探索をして位置やパターンマッチを指定して追加すればOKです。

array = ["a", "b", "cat", "d", "e"]

#"cat"の位置を探します
start = array.index("cat") #ちなみ"ca"などの部分検索は出来ません。

array[start, 0] = "lion" #"cat"の前に追加
#array[start, 1] = "lion" #"cat"を置換
#array[start + 1, 0] = "lion" #"cat"の後に追加

p array

#アクセス方法の達人になれば、前、交換(置換)、後ろなど自由自在です。

トレードオフ

ところで「覚えることは少なくしたい」という贅沢ですが、この世はトレードオフです。何かが犠牲になります。

ここまで「pop, push, shift, unshift, insert, slice」などを出来るだけ使わないで同じ効果を発揮させようとしてきました。しかし、逆に覚えなきゃいけないことも新しく増えました。

  • 「削除はnilしてcompact」
  • 「追加はほとんどinsert」
  • 2次元配列解消はflatten
  • インデックス番号の取得はArray#index(“String”)
  • 配列数はlength

以上を覚える必要があります。


探索

探索メソッドについて。

ここまでチラホラ書いてますよね。構成下手ですいません。

  • レシーバーオブジェトの種類を知っていること(Stringか?Arrayか?それ以外か?)
  • メソッドの引数に使えるものをしっていること

覚えなくてもトライして失敗して逆を試せばいいと思う。大事なことは、トライアンドエラーを繰り返しおこなうことです。

ここでの「探索」の定義は、「任意の文字列」または「正規表現」でのパターンマッチ探索を紹介しています。

【探索メソッドString】

メソッド引数戻り値特記
index()“str” or /reg/開始位置番号複数のマッチがあっても最初のものだけ
scan( )“str” or /reg/配列マッチした数ぶん、同じデータの配列を返す
match()“str” or /reg/MatchDataオブジェクトパターンマッチの有無
str[]“str” or /reg/引数に指定した値万能メソッド!?
slice()“str” or /reg/引数に指定した値探索というより抽出だが、
マッチしなければnilを返すので存在確認ができる。
探索も抽出もどっちもイケるよねということ。

※「slice」は「str[]」があれば使わないかもしれません。いまのところRubyプログラミングで「sliceじゃなきゃだめ」ということがありませんでした。

ほかに詳しい説明はRubyまとめver2を確認をお願い致します。

【探索メソッドArray】

メソッド引数戻り値特記
index()“str”インデックス番号複数のマッチがあっても最初のものだけ。部分マッチは評価されない。
※引数はstrのみ。
grep( )“str” or /reg/配列引数は正規表現がオススメ。ネスト配列の場合、ネスト部分の評価を行わない。

grepのほうが一般的なイメージの”スキャン”に近いと思います。

本記事の内容使えばStringとArrayを行き来できるようになりました。互いに変換が出来るということです。そうすることでお互いのメソッドを利用することが出来ます。少々手間はかかるかもしれませんがとても魅力的なことです。


CRUD

もう一度この表を表示します。

この5つの引数表現は応用が効くので覚えておいて絶対損はないです。本記事ではこの5つを覚えないと全く意味がわからない内容と言っても過言ではありません。

位置を取得するのに超重要です。

[1][1..3][1, 2][“String”][/RegEx/]
String
Array××

【StringオブジェクトのCRUD】

CRUD考え方
追加・挿入正規表現や万能メソッドを使い文頭、文末に追加したり、
探索メソッドで開始位置番号を確認し、位置を指定してデータを挿入したりする。
位置の指定かパターンマッチを利用しデータの追加を行う。
置換メソッドgsubを追加メソッドとして利用することもできます。
抽出・探索探索メソッドを利用し、パターンマッチや位置を探します。
部分抽出を行うこともできます。
置換・更新sub、gsubメソッドの利用、または万能メソッドを利用し、置換・更新を行います。
一度、配列に変換し、配列を操作するという方法もあります。
削除基本的な考え方として削除対象文字を””で置き換えるという手法を選択します。
万能メソッドやsub、gsub、または他の方法で置換を行う。
また「slice!(5つの引数)メソッド」で部分削除も可能です。

【ArrayオブジェクトのCRUD】

ここまで読み進めているとすでに読まなくてもわかるとおもいますが、(私の刷り込み)復習を兼ねて何度も書きます。

CRUD考え方
追加・挿入「<<」を使いデータを追加する。
追加する位置を指定したいのなら、Arrayの探索をおこない、
位置を確認し、データを追加・挿入する。
pushメソッドとinsertメソッドを覚えていたらそれを使ってもいい。
抽出・探索抽出に関してはただの配列へのアクセスである。
探索するのであれば前述の探索を参考にgrepやindexを使用し値取得を行う。
置換・更新シンプルな置換としては、こちらもただ配列データへのアクセスを行い、
データを置換するだけです。
インデックス番号や文字列の一部しかわからない場合は、
文字列への変換や前述の探索を試みます。
削除popなどを覚えていればそれを使えばいい。
基本的には削除対象の位置または範囲を特定し、nilを置換し、compactでnilを削除します。

each、map、ifを用いた記述をすることで、各配列データに対して一気に自由に処理を行うことが可能です。要は考え方です。ここらへんがプログラミングの面白いところでもありますね。


余談と感想と雑記

【扱う主なデータ】

  • 変数
  • 数字列
  • 配列
  • ハッシュ
  • boolean(true, false)
  • newオブジェクト

「newオブジェクト」はgemや外部ライブラリ、標準ライブラリをnewしたときにできるものです。インスタンス化というのでしょうか?これらに関してはリファレンスに従って機械的に利用していきます。

素人プログラマーとしてはプログラミングとは「数字列と配列・ハッシュを扱うことなのでは?」と思います。それ以外のオブジェクトはリファレンスや検索を駆使して実行してみるのがいいと思います。

【正規表現のおそろしさ笑】

正直いままで避けていましたが(記号とかが嫌で)、正規表現はコスパが良すぎです。少し勉強すればできることがかなり増えます。考え方に幅が出てきます。

正規表現を使えばたいていのメソッドを省略できる!?

本記事のテーマなので何度も言います。メソッド覚えたほうが絶対いいです。10より100、100より1000です。コードは短いし、記述もラクです。

もしメソッドを覚えられないのなら別の工夫が必要です。コードが長くなっても構いません。コードが長くなることのメリットを後述してます。簡単に言うと「結果が同じでも自力で思考して考えて導き出せたことには意味がある」ということです。

「if、each、数字列・配列操作、正規表現でいろいろできそうだな」とわかってから、いろいろ覚える気持ちがなくなりました。もちろんコードは長くなります。私はプログラマーでもないし、プログラマーになりたいわけではないです。アイディアを形にしたいだけです。やることやって後はラクしたいだけです。まずは成果物を作ることが目的です。

【冗長の効用?】

メソッドを覚えて使うと無条件で動作します。例えばpopコマンド(メソッド)を知っておけば、動作原理は知らなくても配列の最後を飛ばせます。popはpopの動きだけをします。しかし、「popコマンドではない手段で配列の最後を飛ばす」というアプローチをとると、個人的な感覚ですが「プログラミング的、ロジカル的、論理的(同じか笑?)思考」が養える気がします。

理由は「それって…要はこれと同じだよね?こうしたらいいんじゃないか?」と自分で答えを導く過程をたどるからです。

考えることでいろんなアイディアや応用を想起するきっかけになるのではないでしょうか?

【副作用】

  • コードが長くなります
  • 可読性が悪くなります。コメントを充実させても厳しいかもです。おそらく10日後に自分で書いたものを読み解くにも嫌気がさすかもです。
  • 覚えることが少ないと、他人のコードを見たときに「なんだこれ!」と思うことが多くなります。シンプルに知らないからです。例えば省略記法や別の記述方法を見たときです。まぁそのときは「しょうがないな。私にはオーバースペックだ」と合理化するしか気持ちを落ち着かせる方法が無いと思いますが。
  • チームは作れない。というより入れてくれない悲笑。仲間外れ。とにかく独学なので個人開発に限られます。

【復習】

例:いままで配列の後ろを削除したいときはpopメソッドを使っていました。

popを使うなとは言っていません。覚えることを少なくするなら工夫が必要ですということです。覚えることが少ないと効率が悪くなることがあります。それでも覚えることを少なくして、ソラで書けることを優先したいかどうかです。popを使ったほうがコードが簡潔で可読性は高くなります。こっちのほうが絶対いいに決まってます。

  • 削除は「対象をnilしてcompact」
  • 追加は「すべて位置指定してinsert扱い」
  • 抽出や探索は「探索メソッドを使って任意のデータを取得」
  • 置換や更新も「探索メソッドを使って任意のデータや位置を取得し、シンプルにデータを上書き」
  • 「配列アクセスの達人」になるとすごく汎用的
  • 万能メソッドと5つの引数を覚えること
  • 探索を覚えること
  • StringとArrayでなんとかしようと思うこと
  • 正規表現を嫌わず、積極的に利用すること
  • オシム監督が求めたポリバレントな選手(メソッド、記述方法、構文のこと)を応用すること

※ちなみに覚えることを少なくしたいと言うてますけど、insert、pop、shift、unshiftなどをあまり使った記憶がない。そもそも覚えなくてもいいのか?作るプログラムによるのか?

【基本使わないけど実験して挙動が面白かったString#inspect】

insepectとto_sがほぼ同じとは知らなったです。Arrayにto_sで文字列化できるのも知りませんでした。to_sは数字を文字列にするものだと思っていましたから。だから素人プログラマーとしてはinspectは必要ないと思いました。inspectとto_sのどっちを覚える?と聞かれたら迷わず「to_s」をとります。セットで「to_i」を覚えられるからです。

しかし、inspectとto_sが「完全に同じ効果」ならどっちかは存在しなくてもいいはずです。そんな非効率なこと世の中に存在しないでしょう。天才たちが作っているのですから。百聞は一見に如かずです。

inspectは「見やすい形に変えてくれる」ようです。

puts "\n"
puts "\n".to_s
puts "\n".inspect
p "\n"
#p使えばいいか…笑。
#でもこれはおもしろい↓
puts array.to_s.inspect
puts array.inspect.to_s
p array.inspect.to_s

【ハッシュは?】

「ハッシュが全然話題に上がってないぞ!」と思いました。

例えば「.has_key?()」と「.has_value?()」というメソッドがあります。
しかし、使用方法が限定されます。それほど調べていませんが、引数に正規表現は使えないようです。部分検索ができないです。かなり調べないと使えない、またはわからないのであれば、素人プログラマーは深堀しません。それがポリシーです。

私たちは「せっかちで、いま、すぐ、かんたん」がいいのですから。

よって、「.has_key?()」も「.has_value?()」も「検索結果の有無を知りながら検索をする」という無駄が発生します?そんな印象を受けました。

hash = {name: "taro", age: 34, tel: "011-219-0037"}
p hash.has_value?(/011-219-003/)
#=>false

hash = {name: "taro", age: 34, tel: "011-219-0037"}
p hash.values.grep(/011-219-003/)
#=>["011-219-0037"]

私たち素人プログラマーにとって、StringとArrayという武器を手に入れた今、ハッシュを一度、配列か文字列に変換してから探索したほうが良さそうです。私達は文字列と配列を自由自在に操れるのですから。

ちなみにですがハッシュのメソッドで覚えていたらお得な速いメソッドは以下です。

  1. to_sまたはinspect
    全部文字列にすればscan、index、matchなどが使用できます。
  2. keysとvalues
    これらは配列を返しますが、チェーンメソッドでそのままgrepを使えば正規表現で探索ができます。

ちなみにハッシュも配列同様、each、map、ifを用いた記述をすることで、一気に自由に処理を行うことが可能です。要は考え方です。ここらへんがプログラミングを面白いところですね。

主観的なおかつ直感的にしっくりくるものたち

  • nil?とempty? → 存在確認
  • even?とodd? → 偶数奇数
  • sizeとlengthとcount → 数、長さ
  • keysとvalues → ハッシュから配列を作成

「汎用的なメソッドを利用して、頻度の多い記述でなんでも出来るようにしたい」?

アンカリング?バイアス?自分拘束?

これを言うと元も子もないのですが…。

例えば本記事ではindexメソッドをたくさん使っていますが、自分で気付かないうちに「indexメソッドを使ってどうにかしよう!」という気持ちがあるのだと思います。偏りは仕方ないと思います。しかし、可能性を狭めてしまうのはもったいないです。ある程度、ソラで書けるようになったら、全体をもう一度見直したいと思います。

実際処理するデータ

素人プログラマーが処理できるものといえば数字列ぐらいではないでしょうか?あと少しの画像。

画像、音、動画、ドキュメントなどのファイルは自力でどうにかできるものだと思いません。やはり何かしらのツール、ライブラリ、パッケージなどを使うのが当たり前ではないでしょうか?

画像ならブラウザのtype=”file”やimagemajickなどですし、PDFなら各言語に備わっているライブラリでしょうか。動画や音ファイルはそのまま使うしかないと素人プログラマーは思います。変換、処理などは自分でどうにかせずにすぐ検索すると思います。

よって素人プログラマーの目的は、まず「画面で利用できるツールやアプリ」を作成することだと思います。しかし、ロボットキットなどを購入して、ハードから入るのもいいと思います。モーターを動かして遠隔で照明のスイッチをOFFにできたら、それはもう魔法だと思います。

パソコンひとつで開発したい場合、まずはWebアプリケーションや事務作業効率化などを研究してみるといいと思います。

Filey読み書き

  • File.read(“filename.filetype”)
  • File.write(“filename.filetype”, “書き込むもの”)

open、closeなどを使って読み書きする方法が紹介されていることが多いと思いますが、私みたいに怠慢で処理が非効率で冗長な場合は上記の2点と追記の書き方だけでいいです。

追記

File.open("filename.filetype","a") do |file|
  処理
end

どういう基準で削減したか?なぜ大幅に削減したか?何を削減したか?

Rubyまとめver2 | OKE2GOUを書いてから、しばらくして反省をしてみる。

主観的に頻度、代用、自力対応などを考え、コスパの悪いものはないかを頻度を重要視してみました。

【参考】

「library _builtin (Ruby 2.7.0 リファレンスマニュアル)」
https://docs.ruby-lang.org/ja/latest/library/_builtin.html

【例】Array#pop

Googleで「配列の最後を消したい」と検索したのではないでしょうか?
popを使わずに汎用的な方法で「配列の最後を削除したい」を実現させるにはどうすればいいでしょうか?

※汎用的とは言っても、やはりいくつかのメソッドを覚える必要があります。

ちなみに最初に言いますが、popを使ったほうが圧倒的にコード量が少なく、記述も圧倒的に速いです。

断言できます。popを使いましょう!(矛盾してません笑?)

また「pop(3)」のように引数に数を指定すれば複数のデータの削除が簡単にできます。

ちなみにもうひとつ。popは「最後を弾く!」で暗記してます。

#方法1
array = ["a", "b", "c", "d"]
last = (array.length - 1) #変数lastがインデックス番号
array[last] = nil
p array.compact

#方法2
array = ["a", "b", "c", "d"]
array[-1] = nil
p array.compact

popを使わない方法なら「.compact」を覚えないといけませんね。compactは配列内のnilを消し去るメソッドです。

配列内のデータ削除には「nilしてcompact」という手法を使います。これ重要です。

【例】Array#shift

shiftを忘れていないことと、unshiftとshiftを混乱していなければ、shiftを使ったほうがラクです。

shiftは先頭データを削除したい時に使用します。こちらも「nilしてcompact」を使います。とにかく配列内のデータ削除には「nilしてcompact」という手法を使います。これ重要です。

array = ["a", "b", "c", "d"]
array[0] = nil
p array.compact

【例】String#upcase,downcase

Rubyまとめver2 | OKE2GOUの記事ではこの2つのメソッドのほかにswapcaseとcapitalizeを覚えるメソッドとして書いていました。しかし、「覚えなくてもなんとかいける」と思ったので外しました。

正規表現、置換、chars、if、eachなどのいずれか、または組み合わせでswapcase、capitalizeと同じ結果を実現できます。

もちろんswapcaseとcapitalizeを知っていれば速いです。「先頭だけ大文字にしたいなぁ!」という状況があって、capitalizeを知っていればすぐです。

このあともきっと何度も出てくると思いますが、覚えられることは良いことです!森羅万象記憶できることはめちゃめちゃ良いことです。

付け足しですが、前提条件によってどうするか変わりますね。例えばこういうことです。

「abcdefga」という文字列があり「aがあるかどうか知らんけど、aがあれば大文字にする」なのか「aがあることを知っている、さらにaは2つあるけど、最初ではないaを大文字にする」なのか、前提条件によってプログラムを書く姿勢が変わります。

#先頭をaと知っていて大文字にする。あくまでもひとつの例です。
str = "abcdefg"
p str.gsub(/^./,  "A")

#とにかく最初のaを大文字にする。文字列のどこにあるかは知らない
str = "effmbrke4rtgewadfgedfg"
posi = str.index("a") #最初のaの位置を調べる
str[posi] = "A"
p str

#その他にもいろんな状況、条件が考えられますね!

ここら辺は頻度が重要になってくると思います。頻度少のものに対して少ない私の脳の記憶領域を使ってしまっていいものなのか?場合によってはupcaseもdowncaseを利用頻度は低いです。再削減候補ですね。

【例】String#chop

chopは文字列の最後の文字を削除するものです。

目的を整理します。わたしの目的はchopを使おうが使わないが「とにかく最後の文字を削除する」です。

「必ず4文字の特定のメソッドを利用して文字列の最後の文字を削除すること」であれば答えは「chop」です笑。

それではいきましょう!というかこういうことです↓。考え方が大事です。

| 目的 | メソッド | Noメソッド |
| – | – | – |
| 文字列の最後を削除する | chop | 正規表現「.$」をgsubで”空文字”に。「charsしてpopしてjoin」
「str[-1] = “” or nil」など。charsやgsub、pop、joinは後述しますが、覚えたほうがいいメソッドと位置付けています。 |

※「str[] = “”」は逆引き辞典に「万能メソッド」と記述があったような気がします。こちらの本です。私の読んだRuby本の中でトップ3に入ります。すごくおすすめです。

Rubyまとめver2 | OKE2GOUの内容も多くはこの逆引き本をピックアップしたものです。

ところで…。

Q「本記事で覚えるべきStringのメソッド12個の中にchopが入っています。だけどなんで削減例で使っているの?」

A「はい、申し訳ありません。私の文章構成力の問題です。最初はchopいらないかな~という考えで書き始めたのですが、なんかchopあったほうが楽かもと途中で思いました。chompとセットで覚えられるし一石二鳥。でも、もう不要例でこっちを先に書き始めちゃったので書いちゃえ!ということで書いてしまいました。矛盾、怠慢ですね。しかし、chopを違う方法で実現しようとしている部分は応用が効く考え方ではないでしょうか?いいわけですが、結構重要な考え方だと思っています。疑問を持って違うアプローチを試すというのは、プログラミング、IT以外にも重要だと思います。」

【例】String#chomp

chopがいらないとなるとchompもいらなくなる。でも知っていたら圧倒的に速い。だけど正規表現やgsubで何とかなりそうだ。これも上記の「chop」と同様です。

覚えるメソッドにリストアップされています。

【例】Array#insert

正直、配列データ同士の間にデータを追加することってあります?

データ追加はほとんどpushするくらいですし、insertする状況といえば…例えば配列が複数行の文章を表現している場合「この文とこの文の間には、この文を入れたほうが絶対よくなる!」とかそんな場面でしょうか。プログラミングできる小説家なのでしょうか笑?

Array#indexだけを覚えておき、データの開始位置を取得して、データを追加します。

配列操作の「追加、挿入、置換、更新」はすべてinsertの応用で考えることができます。これ重要です。「位置を取得して、そのあとどうしたいか?」です。

#あいだに「い」を入れます
array = ["あ", "う"]
posi = array.index("う") #posi→位置
array[posi, 0] = "い" #破壊
p array

#insert
#絶対こっちのほうがラク
array = ["あ", "う"]
array.insert(1, "い")
p array

しかし、insertを覚えることができるなら覚えたほうが圧倒的に速いです。でもinsertの頻度が少なければ多くは覚えられないな…記憶力…悲笑。要は「insert」を覚えていても引数の書き方まで覚えていられるかです。たまに出てくると「あれ?引数1と引数2には何を?どっちに何を?指定するんだっけ?」となります。

トレードオフ…。

【例】Array#min,max,minmax

最小値と最大値、欲しいですか?

そんなに最小値と最大値が欲しいならsortして最初と最後をとればいいと思います。

min、max、minmaxという言葉自体はやさしいし、直感的です。本記事内にあるsum、shuffle、uniq、first、lastなどもそうですね。

最後のインデックス番号の計算「array.length – 1」が面倒ならsortしてreverseして最初をとればいい。また負の数が嫌いじゃないならarray[-1]でもOKです。

narray = [4, 1, 3, 6, 2, 9, 3, 5, 6]

#方法1
p narray.sort.first #最小値
p narray.sort.reverse[0] #最大値

#方法2
p narray.sort[0] #最小値
p narray.sort[-1] #最大値

方法1のほうが手が込んでますね笑。

しれ~っと「.first」メソッド使ってますね。言わなくてもどんな効果があるか想像できると思います。こういう直感的なメソッドは覚えようとしなくても覚えてしまいます。逆は「.last」です。

【例】Array#sum

頻度が低いのでeachで回して合計を出せばいいと思います。覚えていたら使えばコード量が圧倒的に少なく済みます。

n = [1, 2, 3, 4]
p n.sum

n = [1, 2, 3, 4]
sum = 0
n.each do |i|
    sum += i
end
p sum

#100まで数えたら?
sum = 0
(1..100).each do |i|
  sum += i
end
p sum

【例】String#squeeze

このメソッドも悪魔のささやきがありました。よくスクレイピングしたHTMLにスペースがたくさんあるものに出くわします。しかし、gsubや正規表現、stripとかで何とかなりそうです。

【例】Hash#keys,values

  • keys→キーだけの配列を返す
  • values→バリューだけの配列を返す

mapやeachで自作可能。でも「.keys」や「.values」くらいなら直感的なので知っててもいいかもしれませんね。コードが長いと今度はラクしたい気持ちが芽生えます。覚えておいた方がラクだと思います。

しかし、この2つのメソッドも覚えるメソッドにリストアップされています。

【例】Array#first, last

知ってても知らなくてもいいかもしれません。知っていれば記述の煩わしさが減るので知って損はないです。それは何でもそうですね笑。徳川将軍全員知っていても損はないですしね。

Array[0]でfirstだし、Array[Array.length – 1]、またはArray[-1]でlastになる。

【例】String#slice

万能メソッドstr[“str”または/reg/]を使えば、sliceを使わず部分削除も部分抽出もできると思います。しかし、「slice」という言葉のほうが直感的であればsliceを採用してもいいと思います。

puts str[/abc/]
puts str.slice(/abc/)

puts str["abc"]
puts str.slice("abc")

【例】「=~」

文字列と正規表現を比較し、マッチ部分の開始位置インデックス数字を表示するものだが、「マッチ部分の開始位置」を知りたいなら、index(“string”または/reg/)でいいのでは?と素人プログラマーは思ってしまいます。

str = "abcindexdefg"
p str =~ /index/
p str.index(/index/)

以上。