見出し画像

Retro-gaming and so on

WARNING!!!! RE: 番外編 12歳からはじめるゼロからのPython 5章まで



 楽勝すぎて勉強にならんな~とか思ってたら「繰り返し」のサンプルとして「バブルソート」登場。う・・これはちゃんとやらないと・・

うん、これはね。

こんなコードは書いちゃいけないって例なんだ。

分かるかしら?

ここだ。

list = [79, 89, 90, 32, 35, 65, 76, 21, 45, 78, 22]
 ↑
「ビルトイン関数名である」list再定義してやがる・・・・・・。
そのコード走らせた後、タプルをリストに変更してみてご覧。変更出来ない、ってなるから。
ビルトイン関数の名前を変数名にしちゃあいけない、とか常識なんだけどな。
他にもトンマなヤツは和を取る時、アキュムレータの名前をsumとか名付けて、やっぱsum関数ぶっ壊したりするわけ。
もちろん、インタプリタをリロードすれば元に戻る。でもこんなコード書いちゃいけないし、ましてや12歳の子に教えてもいけないんだ。
一体著者は何を考えてるんだろう。

以前言った事覚えてるでしょうか?
結局ね、最悪な事に、こういう技術系の書籍ってのは同人誌と変わらないんです。
著者もうっかり筆を滑らせてlstって書くつもりをlistって書いちゃったかもしんない。
でもある程度キチンとしてる編集者なら、著者の原稿貰って自分で原稿通り打ってく、つまりマジに12歳でも分かるのかチェックしてたらこういうミスは減るだろう。
問題はIT系出版社に実はマトモな編集がいないって事だ。
だからこういう事が起きる。

しかもこのコードはまだテクニカルな問題がある。
ここだ。

temp = list[j]
list[j] = list[j+1]
list[j+1] = temp

なんだこれは、とか思う。これもC言語のやり方なんだよな。
こういう二つの変数の中身の値を交換するのをスワッピングつーんだけど。夫婦交換のアレと同じ単語だな(笑)。
C言語の変数ではスワッピングが不可能なので、一時変数temp(temporaryに由来)に一時的に値を保存してチェンジする、って良くやるわけよ。
ところがだ
Pythonだと次のように簡単に値のスワップが出来る。

>>> lst = [79, 89, 90, 32, 35, 65, 76, 21, 45, 78, 22]
>>> lst[0], lst[1] = lst[1], lst[0] # ここでスワップ
>>> lst
[89, 79, 90, 32, 35, 65, 76, 21, 45, 78, 22] # 0番目の値と1番目の値が交換されてる
>>>

つまり、こんなバカな書き方

temp = list[j]
list[j] = list[j+1]
list[j+1] = temp

はしない。
これで済むから、だ。

list[j], list[j+1] = list[j+1], list[j]

大体、このコード見る限り、printに使ってるdispって変数も意味不明。
どうしてそのままリストで出力しないんだろう。何の不都合もないのに。
これで充分な筈なんだ。

lst = [70, 89, 90, 32, 35, 65, 76, 21, 45, 78, 22]
for k in range(len(lst) - 1, 0, -1):
 for j in range(k):
  if lst[j] > lst[j + 1]:
   lst[j], lst[j + 1] = lst[j + 1], lst[j]
  print(lst)

これでこういう出力が得られるんで当分問題はないでしょ。

[70, 89, 90, 32, 35, 65, 76, 21, 45, 78, 22]
[70, 89, 90, 32, 35, 65, 76, 21, 45, 78, 22]
[70, 89, 32, 90, 35, 65, 76, 21, 45, 78, 22]
[70, 89, 32, 35, 90, 65, 76, 21, 45, 78, 22]
[70, 89, 32, 35, 65, 90, 76, 21, 45, 78, 22]
[70, 89, 32, 35, 65, 76, 90, 21, 45, 78, 22]
[70, 89, 32, 35, 65, 76, 21, 90, 45, 78, 22]
[70, 89, 32, 35, 65, 76, 21, 45, 90, 78, 22]
[70, 89, 32, 35, 65, 76, 21, 45, 78, 90, 22]
[70, 89, 32, 35, 65, 76, 21, 45, 78, 22, 90]
[70, 89, 32, 35, 65, 76, 21, 45, 78, 22, 90]
[70, 32, 89, 35, 65, 76, 21, 45, 78, 22, 90]
[70, 32, 35, 89, 65, 76, 21, 45, 78, 22, 90]
[70, 32, 35, 65, 89, 76, 21, 45, 78, 22, 90]
[70, 32, 35, 65, 76, 89, 21, 45, 78, 22, 90]
[70, 32, 35, 65, 76, 21, 89, 45, 78, 22, 90]
[70, 32, 35, 65, 76, 21, 45, 89, 78, 22, 90]
[70, 32, 35, 65, 76, 21, 45, 78, 89, 22, 90]
[70, 32, 35, 65, 76, 21, 45, 78, 22, 89, 90]
[32, 70, 35, 65, 76, 21, 45, 78, 22, 89, 90]
[32, 35, 70, 65, 76, 21, 45, 78, 22, 89, 90]
[32, 35, 65, 70, 76, 21, 45, 78, 22, 89, 90]
[32, 35, 65, 70, 76, 21, 45, 78, 22, 89, 90]
[32, 35, 65, 70, 21, 76, 45, 78, 22, 89, 90]
[32, 35, 65, 70, 21, 45, 76, 78, 22, 89, 90]
[32, 35, 65, 70, 21, 45, 76, 78, 22, 89, 90]
[32, 35, 65, 70, 21, 45, 76, 22, 78, 89, 90]
[32, 35, 65, 70, 21, 45, 76, 22, 78, 89, 90]
[32, 35, 65, 70, 21, 45, 76, 22, 78, 89, 90]
[32, 35, 65, 70, 21, 45, 76, 22, 78, 89, 90]
[32, 35, 65, 21, 70, 45, 76, 22, 78, 89, 90]
[32, 35, 65, 21, 45, 70, 76, 22, 78, 89, 90]
[32, 35, 65, 21, 45, 70, 76, 22, 78, 89, 90]
[32, 35, 65, 21, 45, 70, 22, 76, 78, 89, 90]
[32, 35, 65, 21, 45, 70, 22, 76, 78, 89, 90]
[32, 35, 65, 21, 45, 70, 22, 76, 78, 89, 90]
[32, 35, 21, 65, 45, 70, 22, 76, 78, 89, 90]
[32, 35, 21, 45, 65, 70, 22, 76, 78, 89, 90]
[32, 35, 21, 45, 65, 70, 22, 76, 78, 89, 90]
[32, 35, 21, 45, 65, 22, 70, 76, 78, 89, 90]
[32, 35, 21, 45, 65, 22, 70, 76, 78, 89, 90]
[32, 21, 35, 45, 65, 22, 70, 76, 78, 89, 90]
[32, 21, 35, 45, 65, 22, 70, 76, 78, 89, 90]
[32, 21, 35, 45, 65, 22, 70, 76, 78, 89, 90]
[32, 21, 35, 45, 22, 65, 70, 76, 78, 89, 90]
[21, 32, 35, 45, 22, 65, 70, 76, 78, 89, 90]
[21, 32, 35, 45, 22, 65, 70, 76, 78, 89, 90]
[21, 32, 35, 45, 22, 65, 70, 76, 78, 89, 90]
[21, 32, 35, 22, 45, 65, 70, 76, 78, 89, 90]
[21, 32, 35, 22, 45, 65, 70, 76, 78, 89, 90]
[21, 32, 35, 22, 45, 65, 70, 76, 78, 89, 90]
[21, 32, 22, 35, 45, 65, 70, 76, 78, 89, 90]
[21, 32, 22, 35, 45, 65, 70, 76, 78, 89, 90]
[21, 22, 32, 35, 45, 65, 70, 76, 78, 89, 90]
[21, 22, 32, 35, 45, 65, 70, 76, 78, 89, 90]
>>>

どうしても文字列にしたいのならjoinを使えばいいんだよな。

lst = [70, 89, 90, 32, 35, 65, 76, 21, 45, 78, 22]
for k in range(len(lst) - 1, 0, -1):
 for j in range(k):
  if lst[j] > lst[j + 1]:
   lst[j], lst[j + 1] = lst[j + 1], lst[j]
  disp = " ".join([str(i) for i in lst])
  print(disp)

っつーかよ、C言語的disp変数なんぞ冒頭で宣言して、それに加算する、なんつー破壊的変更するからケツでdisp = ""なんて再定義しなきゃいけなくなるわけだ。だってdisp変数を壊しながら使ってる、って事だからな。

70 89 90 32 35 65 76 21 45 78 22
70 89 90 32 35 65 76 21 45 78 22
70 89 32 90 35 65 76 21 45 78 22
70 89 32 35 90 65 76 21 45 78 22
70 89 32 35 65 90 76 21 45 78 22
70 89 32 35 65 76 90 21 45 78 22
70 89 32 35 65 76 21 90 45 78 22
70 89 32 35 65 76 21 45 90 78 22
70 89 32 35 65 76 21 45 78 90 22
70 89 32 35 65 76 21 45 78 22 90
70 89 32 35 65 76 21 45 78 22 90
70 32 89 35 65 76 21 45 78 22 90
70 32 35 89 65 76 21 45 78 22 90
70 32 35 65 89 76 21 45 78 22 90
70 32 35 65 76 89 21 45 78 22 90
70 32 35 65 76 21 89 45 78 22 90
70 32 35 65 76 21 45 89 78 22 90
70 32 35 65 76 21 45 78 89 22 90
70 32 35 65 76 21 45 78 22 89 90
32 70 35 65 76 21 45 78 22 89 90
32 35 70 65 76 21 45 78 22 89 90
32 35 65 70 76 21 45 78 22 89 90
32 35 65 70 76 21 45 78 22 89 90
32 35 65 70 21 76 45 78 22 89 90
32 35 65 70 21 45 76 78 22 89 90
32 35 65 70 21 45 76 78 22 89 90
32 35 65 70 21 45 76 22 78 89 90
32 35 65 70 21 45 76 22 78 89 90
32 35 65 70 21 45 76 22 78 89 90
32 35 65 70 21 45 76 22 78 89 90
32 35 65 21 70 45 76 22 78 89 90
32 35 65 21 45 70 76 22 78 89 90
32 35 65 21 45 70 76 22 78 89 90
32 35 65 21 45 70 22 76 78 89 90
32 35 65 21 45 70 22 76 78 89 90
32 35 65 21 45 70 22 76 78 89 90
32 35 21 65 45 70 22 76 78 89 90
32 35 21 45 65 70 22 76 78 89 90
32 35 21 45 65 70 22 76 78 89 90
32 35 21 45 65 22 70 76 78 89 90
32 35 21 45 65 22 70 76 78 89 90
32 21 35 45 65 22 70 76 78 89 90
32 21 35 45 65 22 70 76 78 89 90
32 21 35 45 65 22 70 76 78 89 90
32 21 35 45 22 65 70 76 78 89 90
21 32 35 45 22 65 70 76 78 89 90
21 32 35 45 22 65 70 76 78 89 90
21 32 35 45 22 65 70 76 78 89 90
21 32 35 22 45 65 70 76 78 89 90
21 32 35 22 45 65 70 76 78 89 90
21 32 35 22 45 65 70 76 78 89 90
21 32 22 35 45 65 70 76 78 89 90
21 32 22 35 45 65 70 76 78 89 90
21 22 32 35 45 65 70 76 78 89 90
21 22 32 35 45 65 70 76 78 89 90
>>>

disp変数の存在なんざ実は全くの無駄だ。
僕が書きなおしたコードにはリスト内包表記が使われてるんで、「いきなりこんなの使うのは難しい」とか言うかもしんない。
でも僕に言わせればリストで出力すれば済むのにわざわざ文字列に変換する方がおかしくねぇか、って事だ。
配列そのまま出力出来ないのはC言語だろう。C言語のおかしな流儀をPythonに持ち込むな、と。

もう分かりましたね?
はい、この著者、恐らくC言語脳です。そして多分そこまでPythonの事は知らないでしょう。
ちょっとでもPythonマジメに勉強したらこんなバカな事はやらんのだ。
多分「子供にCを教えるのは難しいから、ちょろっとPythonでC言語を教えよう」ってバカな事を考えて書いたんじゃねーか?
書き間違いじゃないよ。「PythonでC言語を教えよう」としてるんだろ。
アホか

ここで星田さんにTips。
実際こういう本は多いんだ。
で、こういう本を読む時のポイント。
「俺ならもっと短く書ける!」と意気込んで読む事(笑)。
もう、こんなフザケたコード載せてるんだから読者への挑戦と言って良い(笑)。星田さんは挑戦状を叩きつけられたんだ(笑)。
だから批判的にコードを読め。リファクタリングしろ。
絶対星田さんの方がその本の著者を上回った「綺麗なPythonコードを」書ける筈。
何故なら星田さんはLisperだからだ。

それとね、アルゴリズムの話。
ぶっちゃけた事を言うとね。有名なアルゴリズムなら大体Wikipediaに載ってるんだよ(笑)。例えばバブルソートなんかもここに載ってる
んでね、そういうの必要になった時、例えばWikipediaに載ってるような疑似コードとか、別の言語で書かれたヤツを「翻訳出来るか否か」の方がむしろ大事なのね。暗記よりも「解釈力」だ。
まずそれが1つ。
2つ目。実際ね、プロもアルゴリズム全部知ってるわけじゃないの。そうじゃなくって種本があるわけよ(笑)。アルゴリズム辞典、みてぇなの。この本が有名だし、あと、isamさんが持ってるみたいだけど、こういう本とか。
学生じゃないんだから、テストを気にする必要はない。従って暗記をするより、もしまとまったものが欲しかったらそういう種本を入手しよう。暗記するよか全然マシな筈。
その3。これは僕のケース。
アルゴリズムモノって大体C、ないしはPascalで書かれてるケースが多くて、読めばなるほど、なんだけど冗長なものが多いんだよな。
そこで。僕の場合だと一番キレた奴らが多い言語、Haskellで書かれたアルゴリズムを探しちゃう(笑)。殆どのケースでHaskellの奴らは最短のコードをでっち上げちゃうんだ。
Lispの場合だと、これもキレた奴らが多いんだけど、ANSI Common Lispなんかは「破壊的変更を辞さない」って人が多いせいで、別な意味ではCとかPascalのコードと変わんないのも多いわけ。スマートさがない。
大体、Lispの奴らってスマートさよりもマクロでの力技を好んでたりするんで(笑)、そういう意味でもアテにならんのだよな(笑)。関数書かないでマクロ書くのは反則だろうと(笑)。「最強言語」もこういう場合は問題なんだよ(笑)。

例えばね、このバブルソートだと。Haskellの奴らはこんなコードを書いてる

def bubbleSort_aux(lst):
 try:
  x, y, xs = lst[0], lst[1], lst[2:]
   if x > y:
    return [y] + bubbleSort_aux([x] + xs)
   else:
    return [x] + bubbleSort_aux([y] + xs)
 except IndexError:
  return lst

def bubbleSort(lst):
 if lst == []:
  return []
 else:
  t1 = bubbleSort_aux(lst)
  return bubbleSort(t1[:-1]) + [t1[-1]]

どう?C言語脳で書かれたコードより美しくない?自然に再帰してるしね。
Haskellは必ずしも書ける必要はないけど、このテのアルゴリズムを書く場合、「教科書となるくらいの」お手本が、アッチコッチにゴロゴロしてんのよ。
それがHaskell自体の・・・っちゅうよりHaskellのコードの強さ、なのよね。
ただ、再帰入ってるでしょ?Pythonだとそれはいただけないので。人力で最適化します。
すると次のようになる。

def bubbleSort_aux(lst):
 acc = []
 try:
  while True:
   x, y, xs = lst[0], lst[1], lst[2:]
   if x > y:
    lst, acc = [x] + xs, [y] + acc
   else:
    lst, acc = [y] + xs, [x] + acc
 except IndexError:
  return acc + lst

def bubbleSort(lst):
 acc = []
 while lst != []:
  t1 = bubbleSort_aux(lst)
  lst, acc = t1[:-1], [t1[-1]] + acc
 return acc

人力で最適化してもこっちの方が綺麗なんじゃないかしら。結果全般的にコンパクトですしおすし。

いずれにせよ、アルゴリズムに関してのオススメは次の3つの一つ。

  1.  Wikipediaをアンチョコとして頼る(特に、実は英語版が良く書かれてる)。
  2.  実際アンチョコとして売られている本を入手する。
  3.  Haskellで書かれたソースを探す。大体のケースでHaskellで書かれたアルゴリズムが最短だ。
だから「暗記」せんでも構いません。
  • Xでシェアする
  • Facebookでシェアする
  • はてなブックマークに追加する
  • LINEでシェアする

最近の「RE: 番外編」カテゴリーもっと見る

最近の記事
バックナンバー
人気記事