或るプログラマの開発日記

日々の勉強したことの備忘録なんかに使っていきます

sortとsort!の違い

どうも、パイソンです。

今日は、Rubyでsortのやり方を調査した時の内容をメモしておきます。

sortとsort!

ref.xaio.jp


ruby sort」とググッたら出てきたリファレンスを眺めてると、並び替えをするメソッドにもsortと、sort!という2通りがある模様。

はぁ、、?「!」に何の意味があるんじゃ?ということで確認してみると、、

「!」はメソッド名の一部です。慣用的に、 同名の(! の無い)メソッドに比べてより破壊的な作用をもつメソッド(例: tr と tr!)で使われます。

https://docs.ruby-lang.org/ja/2.1.0/doc/symref.html

ということらしい。

要は「!」付きのメソッドはオブジェクトに作用するから気を付けましょうねー。的なノリなんだろうか。。

そこで、試しに書いて見たのがこんなプログラム。

numbers1 = [2, 6, 5, 4, 9, 8, 10, 3, 7, 1]

p numbers1.sort  #=>[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
p numbers1       #=>[2, 6, 5, 4, 9, 8, 10, 3, 7, 1]

numbers2 = [2, 6, 5, 4, 9, 8, 10, 3, 7, 1]

p numbers2.sort! #=>[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
p numbers2       #=>[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

ま、確かにsort!のほうはオブジェクトそのものを書き換えてるんだなーというのが分かりました。

「!」無しのメソッドは安全?

そんなことなら、「!」無しのメソッドは元のオブジェクトを編集したらあかんのかい!という疑問も浮かんでくるもの。

が、そんな事は無かった。どうも「!」の有無はあくまで目安的な物に過ぎないというのが現状である模様。

参考URL

qiita.com

あくまで、こんな慣習があるんですよー、という程度に覚えておこう。

Rubyの文字列連結メモ

どうも、パイソンです。

今日は、Rubyの文字列連結で少しハマった事をメモしておきます。

Rubyの文字列連結演算子

まずは、基本から。

Rubyで文字列を連結する方法には、+演算子を使う方法と、<<演算子を使う方法があります。

#文字列連結テスト
str1 = "ABC" + "DEF"
puts str1 #"ABCDEF"と出力
str2 = "abc" << "def"
puts str2 #"abcdef"と出力

+演算子と<<演算子の違い

どちらも文字列を連結しているだけのように見えますが、

  • +演算子は連結した新たなオブジェクトを返す。
  • <<演算子は左辺のオブジェクトを直接書き換える。

という点で違いがあります。

いろんなサイトで調べてみたところ、「+演算子は処理速度が遅い。<<演算子は処理速度が速いけどオブジェクトを破壊するので気をつけましょう。」という感じのようです。

何に気をつけるの?

じゃぁ、オブジェクトを書き換える事で実際どんな事が起きるの?ということで少しサンプルを組んでみました。処理内容は、"A","B","C"の文字をn個繋げてできる全ての文字列の組み合わせを出力するというものです。

#+演算子で連結するVer
def func1(str, depth)
  if depth == 0
    puts str
    return
  end
  ["A", "B", "C"].each do |c|
    func1(str + c, depth -1)
  end
end

puts "func1を実行してみた結果"
func1("", 2)

実行結果

func1を実行してみた結果
AA
AB
AC
BA
BB
BC
CA
CB
CC


このプログラムの+演算子を<<に変更してみましょう。

#<<演算子で連結するVer
def func2(str, depth)
  if depth == 0
    puts str
    return
  end
  ["A", "B", "C"].each do |c|
    func2(str << c, depth -1)
  end
end

puts "func2を実行してみた結果"
func2("", 2)

実行結果

func2を実行してみた結果
AA
AAB
AABC
AABCBA
AABCBAB
AABCBABC
AABCBABCCA
AABCBABCCAB
AABCBABCCABC

と、まあ前の結果とは大違いの結果。。

要は再帰処理を使ってオブジェクトをスタックに積んでるつもりが、<<演算子を使ったのでひたすら一点のオブジェクトを書き換えてただけでした、というオチ。

雑感

当初Rubyおぼえたての私は、「<<のほうが早いんじゃん!」と単純に考えてましたが、やはりそれぞれの違いを理解して状況に応じ適切に使い分けるようにしないといけませんね。

Twitterはじめました

どうも、パイソンです。

ブログ連携用にツイッター始めてみることにしました。

基本ブログ連携用ですが、なんか思いついたさいにつぶやくこともありますので、フォローしてくださったら嬉しいです。


んで、当面の活用方法としては、、

twitter.com

コイツを試して見るのが面白いかも。なんて思っております。



あー、でもなんかアイコンが無いとだいぶさみしい感じがするなー。(-_-;)
さっさと、なんかいいアイコン探しておこう。

では、また。

Rubyで小数の割り算を試してみる

どうも、パイソンです。

今回は、勉強がてらRubyの小数の割り算について少しどのような仕様なのかというのを実験しましたので、ここにメモしておきます。

Rubyでの小数割り算

まずは、各項の型で挙動が変わるかの確認。

プログラム

puts 10 / 3
puts 10.0 / 3
puts 10 / 3.0
puts 10.0 / 3.0

実行結果

3
3.3333333333333335
3.3333333333333335
3.3333333333333335

で、整数割る整数は端数が切り捨てられた整数で答えが返ってくる模様。

そして、小数が絡むと小数が返ってくるのは想定通りでしたが、よく見ると10.0/3.0で答えは、3.3333333333333335となんとも奇怪なものに?

調べてみた結果

stackoverflow.com

この結果もやはり浮動小数点にまつわる問題が誤差の原因。

因みに、Javaでも同様の確認をしてみたところ、

プログラム

public class Main {
	public static void main(String[] args){
		System.out.println(10.0 / 3.0);
	}
}

実行結果

3.3333333333333335

と相成りました。

雑感

お手軽にRuby勉強してみるつもりが、何故か今や浮動小数点演算の復習になっとる。。(*_*)

Rubyで0.1を10回足しても1.0にはならない件

どうも、パイソンです。

前回の記事で、小数の足し算について取り上げました。

osishow3.hateblo.jp

すると、Rubyでは小数の計算が正確にできるのかなー?という疑問が沸いてみたので、少し実験してみることにしました。

0.1を10回足すとどうなる?

CやらJavaやらでプログラムを組んだことがある人なら、0.1を10回足して1になるかというのは興味深い内容かとは思います。

で、早速実装してみます。

プログラム

x = 0.0
10.times do
  x += 0.1
end
puts x


実行結果(version 2.2.3p173)

0.9999999999999999

え、、やっぱりならないんだ。。

調べてみた結果

qa.atmarkit.co.jp

この件について、調べてたらどうも昔のバージョンは1.0になってたけど今はならないとの事。

うーん、、昔のバージョン使ってた人はこの言語仕様変更にどう対応したんだろうという疑問が残りましたが、やはり小数の計算についてはきちんと考慮してプログラミングしないといけないなーと再認識しました。

メモメモφ(・ω・

「3.9+5.1=9.0」は間違い?Ruby先生に聞いてみる

どうも、パイソンです。


さて今日は少し前にネットで話題になってた問題と取り上げて見ようかと思います。

「3.9+5.1=9.0」は間違い?


lineblog.me

ネットの話題というのは流行るのも廃るのも早いので、もうかなり昔の話題だという印象をもってましたが半年ぐらい前に結構盛り上がってた様ですね。要は小学校の算数のテストで 3.9 + 5.1 の答えを「9.0」と書いたところ先生から減点されたという話です。

ネットでの論調では「9.0で減点はおかしい!」という内容が多かったような印象があります。

まあ、仮に自分が小学校時代にこんな減点喰らったら絶対納得いってないでしょう。

Rubyくんはどう答える?

で、この問題。「小数の足し算」というのは単純そうに見えて、実はプログラマにとって結構な落とし穴が潜んでたりする内容でもあります。そこで今回ブログネタがてらRubyくんにこの数式を解いてもらうことにしました!

プログラム

answer = 3.9 + 5.1
puts answer

実行結果(version 2.2.3p173)

9.0


おー!なんと件の小学生と同じ答えを返してきた!!Σ( ̄□ ̄

Ruby先生の採点結果

じゃ、今度は出した答えをどうRuby先生が評価するかを実験。

answer = 3.9 + 5.1
puts answer

if answer == 9.0 then
  puts "答え9.0はマルです。"
else 
  puts "答え9.0はバツです!!" 
end

if answer == 9 then
  puts "答えは9なのでマルです。"
else 
  puts "答えは9じゃないのでバツです!!" 
end

実行結果(version 2.2.3p173)

9.0
答え9.0はマルです。
答えは9なのでマルです。


Ruby先生:「9でも9.0でも、どっちでもええやん!」


結論:ruby先生は優しい!ヽ(´∀`*)ノ

余談

C先生やJava先生の場合はこうはならんだろーなー。。(ー'`ー;)

RubyでFizzBuzz問題を解く

どうも、パイソンです。

ネットを探索してると、初歩的なプログラム問題としてFizzBuzz問題なるものが超有名であるとありました。

いや、実際10年以上プログラマやってるが初めて聞いたぞ。。(;^_^A

ということで、今回ブログのネタがてら少し調べて見ることにしました。

FizzBuzzとは

プレイヤーは円状に座る。最初のプレイヤーは「1」と数字を発言する。次のプレイヤーは直前のプレイヤーの次の数字を発言していく。ただし、3で割り切れる場合は「Fizz」(Bizz Buzzの場合は「Bizz」)、5で割り切れる場合は「Buzz」、両者で割り切れる場合(すなわち15で割り切れる場合)は「Fizz Buzz」(Bizz Buzzの場合は「Bizz Buzz」)を数の代わりに発言しなければならない。発言を間違えた者や、ためらった者は脱落となる。

Fizz Buzz - Wikipedia

これをプログラムで出力しなさいというのが、FizzBuzz問題だということ。

確かにこの問題、プログラミングの初歩である、「条件分岐」、「繰り返し」の要素が理解出来ていないと解けないので、基本が出来ているかどうかを試すには程よい問題ですね。

プログラミングを教える題材として、HelloWorldの次ぐらいの例題として使えます。

時期柄、新人研修なんかの演習問題としても丁度良いかも。

Rubyでの実装

早速、勉強中のRubyで実装してみました。

(1..100).each do |x|
  if x % 15 == 0 then
    puts "FizzBuzz"
  elsif x % 3 == 0 then
    puts "Fizz"
  elsif x % 5 == 0 then
    puts "Buzz"
  else 
    puts x
  end
end

実行結果

1
2
Fizz
4
Buzz
Fizz
7
8
Fizz
Buzz
11
Fizz
13
14
FizzBuzz
16

#(中略)

89
FizzBuzz
91
92
Fizz
94
Buzz
Fizz
97
98
Fizz
Buzz

雑感

この問題の解き方として、「剰余演算子(%)禁止」とか、最小文字数で実装するとか色んな楽しみ方があるようです。色んな解き方を考えて見るのもプログラミングの楽しさですね。(^-^)