each_with_indexを使って任意の数字を特定する

 「each_with_index」とはRubyで使えるメソッドです。繰り返し処理と同時にその要素が何番目に処理されたのかが分かるようになります。

 では任意の数字が何番目に格納されているかを確認できるプログラムを作っていきます。インデントは整っていないのでそこはご了承ください。下記の配列を用います。

input = [2, 6, 7, 14, 15, 21, 29, 38, 42, 51, 60, 78, 81, 84, 95, 102]

 

 以下の流れで説明していきます。

  1. each_with_indexを使う
  2. 任意の値を指定できるようにする
  3. 引数を使って条件分岐
  4. 特定の情報だけ表示されるようにする

 

1. each_with_indexを使う

 ではまずeach_with_indexを使ってみたいと思います。

input = [2, 6, 7, 14, 15, 21, 29, 38, 42, 51, 60, 78, 81, 84, 95, 102]

input.each_with_index do |num, i|
puts "#{num}#{i}番目にあります"
end

 上記のコードを実行すると結果は下記のようになります。

2は0番目にあります
6は1番目にあります
7は2番目にあります
14は3番目にあります
15は4番目にあります
21は5番目にあります
29は6番目にあります
38は7番目にあります
42は8番目にあります
51は9番目にあります
60は10番目にあります
78は11番目にあります
81は12番目にあります
84は13番目にあります
95は14番目にあります
102は15番目にあります

 ここから特定の値だけを取り出す処理を考えていきたいと思います。またブロック変数は0から始まるため、iに+1を加える必要がありそうです。

 

2. 任意の値を指定できるようにする

 任意の値を決めてその値が何番目にあるかを確認できるようにクラスを用意しました。これを今度は「15は5番目にあります」だけ表示されるようにしていきます。

def search(num_target, input)
input.each_with_index do |num, i|
puts "#{num}#{i+1}番目にあります"
end
end


input = [2, 6, 7, 14, 15, 21, 29, 38, 42, 51, 60, 78, 81, 84, 95, 102]
search(15, input)

 

 

3. 引数を使って条件分岐

 実引数「15」を受け取った仮引数「num_target」が、「num」と同じ値だった時に何番目にあるかが表示されるように下記のようにコードを書き直しました。また配列に含まれていない値だった場合の処理も書いてみました。

def search(num_target, input)
input.each_with_index do |num, i|
if num_target == num
puts "#{num}#{i+1}番目にあります"
else
puts "その数は配列に含まれていません"
end
end
end


input = [2, 6, 7, 14, 15, 21, 29, 38, 42, 51, 60, 78, 81, 84, 95, 102]
search(15, input)

 すると実行結果は以下のようになりました。

その数は配列に含まれていません
その数は配列に含まれていません
その数は配列に含まれていません
その数は配列に含まれていません
15は5番目にあります
その数は配列に含まれていません
その数は配列に含まれていません
その数は配列に含まれていません
その数は配列に含まれていません
その数は配列に含まれていません
その数は配列に含まれていません
その数は配列に含まれていません
その数は配列に含まれていません
その数は配列に含まれていません
その数は配列に含まれていません
その数は配列に含まれていません

 

 

 

4. 特定の情報だけ表示されるようにする

 「15は5番目にあります」だけを表示させたいためreturnを使ってみました。

def search(num_target, input)
input.each_with_index do |num, i|
if num_target == num
puts "#{num}#{i+1}番目にあります"
return
else
puts "その数は配列に含まれていません"
end
end
end


input = [2, 6, 7, 14, 15, 21, 29, 38, 42, 51, 60, 78, 81, 84, 95, 102]
search(15, input)

 そうすると実行結果は以下のようになりました。

その数は配列に含まれていません
その数は配列に含まれていません
その数は配列に含まれていません
その数は配列に含まれていません
15は5番目にあります

 現状のコードだと4番目までの値も確認されているようです。そこで、「その数は配列に含まれていません」というワードをeach_with_indexの外に追いやりました。

def search(num_target, input)
input.each_with_index do |num, i|
if num_target == num
puts "#{num}#{i+1}番目にあります"
return
end
end
puts "その数は配列に含まれていません"
end


input = [2, 6, 7, 14, 15, 21, 29, 38, 42, 51, 60, 78, 81, 84, 95, 102]
search(13, input)

 これでやっと意図した実行結果を得られるようになりました。

 

 

以上です

 

 

 

二重ハッシュを紐解く

 二重ハッシュのデータから特定の情報だけを取り出す方法を書きたいと思います。

users = [
{user: {profile: {name: '佐藤', age: 22}}},
{user: {profile: {name: '鈴木', age: 30}}},
{user: {profile: {name: '田中', age: 40}}},
]

 ここから、名前、もしくは年齢だけ取り出したい時にどうするかについて説明します。

 

  1. eachを使う
  2. キーを連続して指定する
  3. digを使う

 

 上記の流れで説明します。

 

 

1. eachを使う

 まずユーザーの情報を全部取り出すようにしたいと思います。当然ながら、下記のコードではエラーが起きてしまいます。

puts users[:user]

 そこでeach文を使ってみることにします。

users.each do |u|
puts u[:user]
end

 このような記述をした場合、下記のような出力結果になります。

{:profile=>{:name=>"佐藤", :age=>22}}
{:profile=>{:name=>"鈴木", :age=>30}}
{:profile=>{:name=>"田中", :age=>40}}

 

 

2. キーを連続して指定する

 これで後は名前もしくは年齢だけを出力させたいので、連続してキーを指定します。

users.each do |u|
puts u[:user][:profile][:age]
end

 このような記述をすることで年齢だけが出力されるようになります。

22
30
40

 

 

3. digを使う

 別解としてdigメソッドを使うこともできます。

users.each do |u|
puts u.dig(:user, :profile, :name)
end

 これで今度は名前だけが出力されるようになります。

佐藤
鈴木
田中

 

 

 以上です。

 

約数の総和を算出する

 ある整数の約数の総和を算出するプログラムを作ってみました。また一定の条件下での約数の和も出せるようにしていきたいと思います。コードのインデントは整っていないのでごめんなさい。

 

  1. 約数を表示させる
  2. 約数を足し合わせる
  3. 1000以下の約数の和を出してみる
  4. 条件の指定を決められるようにする

 

 以上の流れで進めていきます。

 

1. 約数を表示させる

 まず約数を表示させるプログラムから作ってみようと思いました。とりあえず割り切れる値を出す際は「%」が使えそうですね。

def divisor(num)
i = 1
while i <= num
a = num % i
if a == 0
puts i
end
i += 1
end
end

puts "整数を入力してください"
num = gets.to_i
divisor(num)

 gets.to_iで入力した値をnumとして、1からnumまで繰り返し割り算をし続けて割り切れた場合はその時のiの値を出力するようにしてみました。45を入力した場合は1から45まで割り算をして、割り切れた値である「1、3、5、9、15、45」だけが出力されました。

 

2. 約数を足し合わせる

 では約数の合計を出したいと思います。割り切れた時だけ配列に値を格納していき、sumを使って配列の合計を出すやり方にしてみました。また変数名をもう少し分かりやすいようにしてみました。

def divisor(num)
divisible =
i = 1
while i <= num
divisible_or = num % i
if divisible_or == 0
divisible << i
end
i += 1
end
puts divisible.sum
end

puts "整数を入力してください"
num = gets.to_i
divisor(num)

 これで45を入力した場合は「1、3、5、9、15、45」の合計である78が出力されるようになりました。

 

3. 1000以下の約数の和を出してみる

 では今度は約数の総和とは別に、特定の条件における約数の和も出せるようにしたいと思います。それでは、まず具体的な数字を使って試してみます。1000以下の約数の和も出せるプログラムを作ってみます。

def divisor(num)
divisible =
divisible_1000_less =
i = 1
while i <= num
divisible_or = num % i
if divisible_or == 0
puts i
divisible << i
if i <= 1000
divisible_1000_less << i
end
end
i += 1
end
puts "約数の総和は#{divisible.sum}です"
puts "1000以下の約数の和は#{divisible_1000_less.sum}です"
end

puts "整数を入力してください"
num = gets.to_i
divisor(num)

 可読性や変数名のネーミングセンスには問題があるかもしれませんが、これでひとまず1000以下の約数の和も出せるようになりました。iが1000以下だった場合は別の配列にもiを格納するようにして合計を出しています。

 例えば12600を入力した場合、「48360」という約数の総和と、「10405」という1000以下の約数の和が算出されます。

 

4. 条件の指定を決められるようにする

 上記のコードでは1000以下に条件が限定されてしまっているため、今度は自分で条件を指定できるようにします。またついでに約数の数も出せるようにしてみました。

def divisor(num, range)
divisible =
divisible_range = []
i = 1
while i <= num
divisible_or = num % i
if divisible_or == 0
puts i
divisible << i
if i <= range
divisible_range << i
end
end
i += 1
end
puts "約数の数は#{divisible.length}です"
puts "約数の総和は#{divisible.sum}です"
puts "#{range}以下の約数の和は#{divisible_range.sum}です"
end

puts "約数の総和を出したい整数を入力してください"
num = gets.to_i
puts "求めたい約数の和の範囲を指定してください"
range = gets.to_i
divisor(num, range)

 これで問題なくコードを実行できました。実行結果は以下のようになります。

約数の総和を出したい整数を入力してください
45
求めたい約数の和の範囲を指定してください
15
1
3
5
9
15
45
約数の数は6です
約数の総和は78です
15以下の約数の和は33です

 可読性はもっと高められそうですが、とりあえずここまでにしておきます。

 

 

 

 

 

 

 

 

 

 

4乗的ガウスを解く

 1から40までの整数の4乗の和をプログラムで算出してみました。コードのインデントが整っていないのはご了承ください。

 

 1⁴ + 2⁴ + 3⁴ + ........ + 40⁴

 こんな感じの計算ですね。

 

  1. 具体的な数字で試してみる
  2. 40回繰り返し処理をしてみる
  3. 40回足した総和だけを出す
  4. Whileで試してみる

 

 上記の流れで説明していきます。

 

 

1. 具体的な数字で試してみる

 まずは原始的に少ない数字で解いてみます。以下のコードを実行すると「98」が出力されました。1の4乗は1、2の4乗は16、3の4乗は81なので、これを40回分記述しても解けそうです。

num = 1**4 + 2**4 + 3**4
puts num

 

2. 40回繰り返し処理をしてみる

 40回手作業で足し算していくのは大変なので繰り返し処理をしてみました。

num = 0
40.times do |i|
num += (i+1)**4
puts num
end

 これで実行結果から総和が「21781332」であることがわかります。

 

3. 40回足した総和だけを出す

 ただし上記のコードだと40回分の足し算の結果が全て実行結果として算出されます。40回足した総和だけが実行結果に出るように書き換えてみました。

num = 0
40.times do |timesCount|
n = timesCount + 1
num += n**4
if n == 40
puts num
end
end

 これで「21781332」だけが実行結果として算出されるようになりました。

 

4. Whileで試してみる

 上記のコードで実装完了ですが、これが最適なコードとは言えなさそうです。勉強のため他の記述の仕方も試してみることにしました。ネットで4乗的ガウスを調べてみたところ、whileを使っている人が多そうでした。

n = 1
num = 0
while n <= 40
num += n**4
if n == 40
puts num
end
n += 1
end

 これで同じく「21781332」だけが実行結果として算出されるようになりました。こっちの方がスッキリしているかもしれませんね。

 

 

 まだまだ勉強不足ですが、これからもっと勉強して瞬時のひらめきで可読性の高いコードを書けるようにしていきたいと思います。

 

 

 

 

 

 

 

 

逆数の和を算出する

 逆数の和を算出する問題を解いたので記録しておきます。ブログの仕様上インデントが整っていないのでそこはご了承ください。

 

1/1 = 1

1/1 + 1/2 = 1.5

1/1 + 1/2 + 1/3 = 1.8333...

 

 このような形で1からNまでの整数の逆数の和を出していき、その逆数の和が7を超える最小の値Nを出したいと思います。

 めちゃめちゃ非効率なやり方ではありますが、論理が飛躍しないように地道に複数のやり方を試してみました。

 

 以下の流れで話を進めていきます。

  1. 小数点を含める
  2. とりあえずN=20で試してみた
  3. 強引に答えを出してみた
  4. コードを美しくする

 

 

1. 小数点を含める

 まず具体的な数字で試してみると

num = 1/1 + 1/2 + 1/3 + 1/4
puts num

 実行結果は「1」となってしまいました。どうやら小数点がなくなってしまうみたいです。そこで「to_f」を使ってみると、実行結果は「2.08333...」となり、小数点も含まれるようになりました。

num = 1/1.to_f + 1/2.to_f + 1/3.to_f + 1/4.to_f
puts num

 ただこんなことをしなくても「1」を「1.0」に変えるだけでも小数点が含まれるようになりました。「整数÷整数=整数」という仕様になっているようなので小数点をつけてあげると良いみたいです。

num = 1.0/1 + 1.0/2 + 1.0/3 + 1.0/4
puts num

 

 

2. とりあえずN=20で試してみた

 先ほどは1、2、3と自分で具体的な数字を書いて試しましたが、今度はその数字を「n」にして試してみました。|n|というブロック変数は0から始まるので(n + 1)にしています。

num = 0
20.times do |n|
num += 1.0/(n + 1)
puts num
end

 この実行結果はこのようになりました。

1.0
1.5
1.8333333333333333
2.083333333333333
2.283333333333333
2.4499999999999997
2.5928571428571425
2.7178571428571425
2.8289682539682537
2.9289682539682538
3.0198773448773446
3.103210678210678
3.180133755133755
3.251562326562327
3.3182289932289937
3.3807289932289937
3.439552522640758
3.4951080781963135
3.547739657143682
3.597739657143682

 N=20で逆数の和は「3.597...」ですし、足していく逆数はどんどん小さくなるため、逆数の和が7を超える最小の値はかなり大きい数字になりそうです。勘では当てられそうにありません。

 

3. 強引に答えを出してみた

 もちろんここから原始的に答えを導くことも可能だと言えます。とりあえず1万回繰り返し処理をしてみて、逆数の和が7を超えた時に繰り返し処理をストップさせてみました。また、何回目でストップしたかが分かるようにブロック変数の中身を「timesCount」にしてみました。ブロック変数は0から始まるため、+1をした上で回数を出力させています。

num = 0
10000.times do |timesCount|
n = timesCount + 1
num += 1.0/n
if num >= 7
puts num
puts n
return
end
end

 実行結果は以下のようになりました。N = 616の時に初めて逆数の和が7になるようです。答え自体は合っていると思います。

7.001274097134162
616

 

 

4. コードを美しくする

 答えを出すことだけが目的ならば上記までのやり方でも構わないと思います。しかしとりあえず1万回繰り返してみたというのは、不適切な「仕組み化」だと言えます。

 ということで10000.timesではなくwhileを使ったものを試すことにしてみました。

num = []
sum = 0
n = 0
while sum < 7
n += 1
a = 1.0/n
num << a
sum = num.sum
end
puts num.length

 これでどうでしょうか。先ほどと同じく「616」という値が算出されました。合計が7を超えるまで繰り返し処理を行うようにして、配列に値を追加しながら合計を出すようにしていきました。配列を使っているのでlengthメソッドでNの値を出すようにしています。

 

 

 

 いかがでしたでしょうか。理解力を深めるために、論理を飛躍させずに地道に答えを導いてみました。僕は勉強不足であるため、もっと適切なコードはあるはずです。こういうやり方が使えるということを教えていただけたら嬉しいです。

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

ネットワークの仕組み

 「プロトコル」とは何だという疑問から、ネットワークの仕組みの1部をまとめてみました。あくまでもアバウトな解釈であるため、ここから説明することで間違えている内容があればご指摘いただけるとありがたいです。まずだいたいのイメージを掴むために、紹介する各用語の親子構造を僕なりに文字の大きさで示してみました。

 

インターネット(環境)

World Wide Web(技術)

ハイパーテキスト(文書)

ハイパーリンク(参照)

 

ーーーーーーーーーーーーーーーーーーーー

 

プロトコル(ルール)

TCP(ルールの1種)

IP(ルールの1種)

HTTP(ルールの1種)

 

ーーーーーーーーーーーーーーーーーーーー

 

IPアドレス(インターネット上の住所)

DNS(分かりやすくする技術)

URL(分かりやすくなった住所)

ドメイン(分かりやすくなった住所の1部)

 

ーーーーーーーーーーーーーーーーーーーー

 

厳密にはこんな親子構造ではありませんが、だいたいこんなイメージでいいかなと思っています。では以下の手順でそれぞれを説明してみたいと思います。

 

  1. Webとは
  2. プロトコルとは
  3. DNSとは

 

1. webとは

 まずインターネットとは、世界中のコンピュータや情報機器がお互いに接続された「環境」のことです。この環境の中で使われている技術こそがWorld Wide Webという「技術」です。

 略してWebという技術は、コンピュータを使って文書と文書を結びつける仕組みのことです。このHTMLで記述された文書のことをハイパーテキストと言います。そしてこのハイパーテキストの中に埋め込まれるリンクのことをハイパーリンクと言います。

 

2. プロトコルとは

 このネットワークのに接続された機器同士に定められた通信の「ルール」のことをプロトコルと言います。このプロトコルの種類の中にHTTP通信やTCP/IPなどがあります。

 このプロトコルの種類は4つの階層構造に分けて分類できます。最も上の層である、アプリケーションごとのやりとりを規定するものの1つにHTTPがあります。そしてそれよりも下の層にあり、インターネット通信で中心的な役割を果たすのがTCPとIPです。

 HTTPについては下記の記事で詳しく説明しています。

kim-shun.hatenablog.com

 

3. DNSとは

 上記で示したHTTP通信によってクライアントとサーバー間で通信ができます。この際、サーバーを特定するために使われるインターネット上の住所のことをIPアドレスと言います。

 そしてこのIPアドレスを、人間が覚えやすい文字列に変換したもののことをドメインと言います。ドメインは「○○.com」の部分を指します。

 さらにドメインを含んだ「https://www.○○.com」のようなもののことを「URL」と言います。

 この時にドメインIPアドレスに変換する仕組みのことを「DNSと言います。

 またサーバーを特定する際はIPアドレスだけでなくポート番号も用いられます。マンションに例えるとIPアドレスは住所の番地までであり、ポート番号は部屋番号だと言えます。

 

 

 以上です。あくまでも僕自身の頭を整理するためにまとめてみました。理解を深めてもう少しわかりやすく説明できそうになったらまた新しく記事にまとめたいと思います。

 

 

 

 

 

 

 

クローンしたアプリをGitで管理する方法

 クローンしたアプリをGitで管理する方法を紹介します。

 まず以下の手順でクローンしたアプリを使えるようにします。

ターミナル

% git clone https://github.com/アプリ名.git
% cd アプリ名
% bundle install
% yarn install
% rails db:create
% rails db:migrate

 そして下記のコマンドを実行します。

ターミナル

% ls -a | grep .git
% rm -rf .git
% git init

 grep .gitのコマンドで.gitを含む文字列を検索できます。またlsに-aオプションを用いていることによって隠しディレクトリも表示されるようになっています。.gitを確認した後は-rfオプションをつけたrmコマンドでリポジトリ情報を削除します。

 git initでローカルリポジトリを作成し、GitHub Desktopでクローンしたアプリを追加して、「Publish Repository」をすればリモートリポジトリに反映されます。

 

以上です。