最近、このサイトで練習しているのですが、なかなか面白い。
今回は論理演算子についての問題を解きました。
x,yの入力に対して、使用する論理演算[ 論理積、論理和、含意、排他、等価 ]を引数として引数の論理演算法を使用してxとyの関係を表すといったものです。
関係といっても、"1"か"0"です。
簡単に論理演算について説明すると、
論理積:両方"1"なら"1"
論理和:少なくともどちらかが"1"
含意:xが真のとき、yが偽の場合以外"1"
排他:両方の値が異なるときに"1"
等価:両方が等しければ"1"
といった感じで、実際に私(初心者)が最初に書いたのがこちら
まぁ普通に考えれば、こうなります。(冗長....)
しかし、上級者はこうなります。
なにがなんやら。。。
というわけで、理解するために、ここからはこの上級者の方のプログラムを解説していこうとおもいます。(できるのか...?)
まず、"lambda"
これは”無名関数”といいます。数学の式でλを使うことがありますが、あのラムダです。
なぜ無名関数というのかと言いますと、
特別にその値を関数名に代入しない限り名前がつかないからです。
使用法といたしましては..例えば、
func(x,y):
return x**y
という関数を"lambda"を用いて書くと、
func = lambda x,y:x+y
となります。先ほどの”関数名”とはfuncの部分ですね。
このラムダ式の利点は、この名前からくるように、
特別に関数として定義する必要がないというところにあります。
配列の中身を変数にしたい場合でも関数を用いると、なんだか複雑になるものも
ラムダ式だとこんな感じにかけます。
sample=[(lambda x: x+1),(lambda x: x+2)]
出力:
sample[0](1) = 2
みたいな感じになります。わざわざ関数を定義する必要がないのでシンプルで便利です。また、別の便利な使用方法があればいつか紹介したいと思います。
これで
初めの lambda x,y,o: で3つの引数を取るというのはわかりました。
では次に、「1&~」 ですが、
&: and条件 =論理積
~:ビット反転
ビット反転に関しては、本来、1なら0に、0なら1に反転するのですが、
Pythonの仕様では
「元の数に1を加えて、符号を反転させたもの」
となっているそうです。なぜだ....よくわかりません。
そして、"dimpleqonx"は一旦飛ばし、
index()は、配列の中でカッコ内に指定した要素を持つインデックスを返すものです。
例えば、
list = ["A","B"]
print list.index("B") #出力: 1
といった感じです。値が存在しなければ、エラーとなりますが、今回は無視。
そして、今回のその値というのが
o[1]
だと。
というのも、oとしてやってくるものは今回指定されており、
初めに貼り付けたものにあるように"o"には論理演算法が書かれています。
ということは、例えば、
o = "disjunction"
のとき、
o[1] = "i"
となりますね。
ということは、一旦無視した"dimpleqonx"について考えてみると
"dimpleqonx".index(o[1]) = 1
となりますね。
次に、
>>y>>x>>y
ですが、これは右シフト演算子(>>)が使用されております。
左辺の数値を右辺の数値だけ右へシフトします。
これで全体の解説は完了しているので、確かめてみましょう。
論理和の場合、x=0,y=0以外は真(つまり"1")となるはずです。
まず、x = 0,y = 0のときビットシフト部分は、
1>>0>>0>>0 →0 #(01→01→01→01 =1)
ですよね。
そして、
~1 (= -2)
そして、
1&(-2) (= 0) :偽
となります。他のパターンでは真となるのか? は各々で確かめてみてください。(面倒なので 笑)
これで解説は終了します。
方法論としては理解できましたが、これを一発で思いつくというのは
無理だ.....と思いました。
まず、ビットシフトしていけばうまい具合に論理演算の結果と同じになるという風に
頭が回らない。。というか前提とする知識がなさすぎる,,,
自分よりも明らかに上級の人が同じ問題を解いたときに、どのくらい短い行でプログラムを書いているかをみると、いかに自分が冗長なプログラムを書いているかを身にしみて感じます。
数学でも、公式を知っていれば秒で解ける問題も、力づくで解くと無駄に時間がかかるのと同じですね。