【Python】The session is unavailable because no secret key was set.
概要
以下のエラーが発生したため対処。
The session is unavailable because no secret key was set.
本題
Flaskでsession変数を扱う際は、以下のようにする。
from flask import session // 略 session['user_id'] = "hogehoge"
しかしながら、secret key
を設定していないとエラーが発生する。
そのためsession
変数を扱うより前の場所でsecret key
を設定する。
if __name__ == "__main__": app.secret_key = 'secret key'
これで解決
参考
【Go】逆ポーランドを出力
概要
いまさらですが逆ポーランドを出力するものを書く。 元ネタは改訂第4版 C言語によるはじめてのアルゴリズム入門。
本題
逆ポーランドを出力するためには、数値と演算子の優先度を比較しながらstackに値を一時格納する。 逆ポーランドの出力が確定した部分からpolishへ格納していく。
豆知識として、Goは*p++
のようなポインタの演算ができないことを知った。また、polish[sp2++]
のようにindexでインクリメントを利用することは、インクリメントがコンパイラに式ではなく文として解釈されるためできないことも知った。
以下ソースコード。
package main import ( "fmt" ) var stack [10]string var polish [10]string func main() { formula := "a+b-c*d/e" sp1, sp2 := 0, 0 // 優先順位テーブル pri := map[string]int{ "a": 3, "b": 3, "c": 3, "d": 3, "e": 3, "+": 1, "-": 1, "*": 2, "/": 2, "": -1, } for _, v := range formula { for pri[string([]rune{v})] <= pri[stack[sp1]]{ popAndPush(&sp1, &sp2) } sp1++ stack[sp1] = string([]rune{v}) } // stackにたまっているものをpolishへ for sp1 > 0{ popAndPush(&sp1, &sp2) } fmt.Println(polish) } func popAndPush(sp1 *int, sp2 *int){ *sp2++ polish[*sp2] = stack[*sp1] *sp1-- }
出力結果
[ a b + c d * e / -]
参考
mapの作り方(今回使っていないけど)
mapについて(今回使っていないけど)
【Go】順リストを書く
概要
いまさらですが順リストを書く。 元ネタは改訂第4版 C言語によるはじめてのアルゴリズム入門。
本題
以下ソースコード。
old.pointer = n
の次にold = n
とあるのですが、これってoldの指すアドレスを変えるってことなんだな、と理解するまでに苦労した。オブジェクトとして考えてはいけない。
package main import ( "fmt" ) type node struct { name string tel string pointer *node } func main() { var head *node = new(node) var old *node = head for{ n := new(node) fmt.Println("name tel") fmt.Scanf("%s %s", &n.name, &n.tel) old.pointer = n old = n if(!next()){ show(head.pointer) break } } } func show(n *node) { fmt.Println("/////順リスト/////") for{ if(n == nil){ break } fmt.Printf("%s %s", n.name, n.tel) fmt.Println("") n = n.pointer } } func next() bool { continue_str := "" for{ fmt.Println("continue? [y/n]") fmt.Scanf("%s", &continue_str) if(continue_str == "y"){ return true } if(continue_str == "n"){ return false } } }
結果
name tel
と聞かれるので適当な文字列を半角スペース区切りで2つ入力する。
continueの旨を聞かれるのでy/nで回答。
yをすると、もう一度name tel
と聞かれる繰り返し。
nをすると作られたリストが表示される。
name tel a 1 continue? [y/n] y name tel b 2 continue? [y/n] y name tel c 3 continue? [y/n] n /////順リスト///// a 1 b 2 c 3
【Go】逆順リストを書く
概要
いまさらですが逆順リストを書く。 元ネタは改訂第4版 C言語によるはじめてのアルゴリズム入門。
本題
以下ソースコード。
package main import ( "fmt" ) type node struct { name string tel string pointer *node } func main() { var head *node = nil for{ n := new(node) fmt.Println("name tel") fmt.Scanf("%s %s", &n.name, &n.tel) n.pointer = head head = n if(!next()){ show(n) break } } } func show(n *node) { fmt.Println("/////逆順リスト/////") for{ if(n == nil){ break } fmt.Printf("%s %s", n.name, n.tel) fmt.Println("") n = n.pointer } } func next() bool { continue_str := "" for{ fmt.Println("continue? [y/n]") fmt.Scanf("%s", &continue_str) if(continue_str == "y"){ return true } if(continue_str == "n"){ return false } } }
結果
name tel
と聞かれるので適当な文字列を半角スペース区切りで2つ入力する。
continueの旨を聞かれるのでy/nで回答。
yをすると、もう一度name tel
と聞かれる繰り返し。
nをすると作られたリストが表示される。
name tel aaa 000 continue? [y/n] b continue? [y/n] y name tel bbb 111 continue? [y/n] n /////逆順リスト///// bbb 111 aaa 000
【Go】キューを書く
概要
いまさらですがキューを書きます。 元ネタは改訂第4版 C言語によるはじめてのアルゴリズム入門です。
本題
以下ソースコード。
package main import ( "fmt" ) const MAXSIZE = 5 // キューの最大長 var queue [5]int var head int = 0 // キューの先頭 var tail int = 0 // キューの最後尾 func main() { var n int = 0 for { fmt.Print("queuein(i) or queueout(o)?") var operator string fmt.Scanf("%s", &operator) if(operator == "queuein" || operator == "i"){ fmt.Print("number: ") fmt.Scanf("%d", &n) if(queuein(n) == -1){ fmt.Println("キューがいっぱいです") } } if(operator == "queueout" || operator == "o"){ if(queueout(&n) == -1){ fmt.Println("キューは空です") } } show() } } func queuein(n int) int { if(head != (tail + 1) % MAXSIZE){ queue[tail] = n tail = (tail + 1) % MAXSIZE return 0 } return -1 } func queueout(n *int) int { if(head != tail){ *n = queue[head] fmt.Println("out: ", *n) head = (head + 1) % MAXSIZE return 0 }else{ return -1 } } func show() { fmt.Println("/////current queue/////") for i, v := range queue { if(i == head){ fmt.Print("*") } if(i == tail){ fmt.Print("~") } fmt.Printf("%d ", v) } fmt.Println("") fmt.Println("") }
結果 *がついた部分はキューの先頭で、~がついた部分はキューの末尾。 queuein(i) or queueout(o)? と質問されるので、 queueinかiを入力すればキューに入れ、queueoutかiを入力すればキューから取り出すことができる。 queueinの場合はキューに入れる数値の入力を求められる。 queueoutの場合はキューから取り出した値を表示する。
queuein(i) or queueout(o)?i number: 1 /////current queue///// *1 ~0 0 0 0 queuein(i) or queueout(o)?i number: 2 /////current queue///// *1 2 ~0 0 0 queuein(i) or queueout(o)?i number: 3 /////current queue///// *1 2 3 ~0 0 queuein(i) or queueout(o)?i number: 4 /////current queue///// *1 2 3 4 ~0 queuein(i) or queueout(o)?i number: 5 キューがいっぱいです /////current queue///// *1 2 3 4 ~0 queuein(i) or queueout(o)?o out: 1 /////current queue///// 1 *2 3 4 ~0 queuein(i) or queueout(o)?o out: 2 /////current queue///// 1 2 *3 4 ~0 queuein(i) or queueout(o)?o out: 3 /////current queue///// 1 2 3 *4 ~0 queuein(i) or queueout(o)?o out: 4 /////current queue///// 1 2 3 4 *~0 queuein(i) or queueout(o)?o キューは空です /////current queue///// 1 2 3 4 *~0
【Go】スタックを書く
概要
いまさらですがスタックを書きます。 元ネタは改訂第4版 C言語によるはじめてのアルゴリズム入門です。
本題
以下ソースコード。
package main import ( "fmt" ) const MAXSIZE = 5 // スタックの最大長 var stack [5]int var sp int = 0 // スタックポインタ func main() { var n int = 0 for { fmt.Print("push(o) or pop(i)?") var operator string fmt.Scanf("%s", &operator) if(operator == "push" || operator == "o"){ fmt.Print("number: ") fmt.Scanf("%d", &n) if(push(n) == -1){ fmt.Println("スタックがいっぱいです") } } if(operator == "pop" || operator == "i"){ if(pop(&n) == -1){ fmt.Println("スタックは空です") } } show() } } func push(n int) int { if(sp < MAXSIZE){ stack[sp] = n sp++ return 0 } return -1 } func pop(n *int) int { if(sp > 0){ sp-- *n = stack[sp] fmt.Println("poped: ", *n) return 0 }else{ return -1 } } func show() { fmt.Println("/////current stack/////") for i, v := range stack { if(i == (sp - 1)){ fmt.Printf("*") } fmt.Printf("%d ", v) } fmt.Println("") fmt.Println("") }
使い方
push(o) or pop(i)?
でpushしたい場合はpush
かo
を入力、popしたい場合はpop
かi
を入力。
pushの場合はnumberが聞かれるので数値を入力する。
そうすると、現在のスタックの状態が表示される。
なお*
が付いている部分は現在のスタックポインタの位置。
popした際は、どの値がpopされたかを表示する。
出力結果
push(o) or pop(i)?o number: 1 /////current stack///// *1 0 0 0 0 push(o) or pop(i)?o number: 2 /////current stack///// 1 *2 0 0 0 push(o) or pop(i)?o number: 3 /////current stack///// 1 2 *3 0 0 push(o) or pop(i)?o number: 4 /////current stack///// 1 2 3 *4 0 push(o) or pop(i)?o number: 5 /////current stack///// 1 2 3 4 *5 push(o) or pop(i)?o number: 6 スタックがいっぱいです /////current stack///// 1 2 3 4 *5 push(o) or pop(i)?i poped: 5 /////current stack///// 1 2 3 *4 5 push(o) or pop(i)?i poped: 4 /////current stack///// 1 2 *3 4 5 push(o) or pop(i)?i poped: 3 /////current stack///// 1 *2 3 4 5 push(o) or pop(i)?i poped: 2 /////current stack///// *1 2 3 4 5 push(o) or pop(i)?i poped: 1 /////current stack///// 1 2 3 4 5 push(o) or pop(i)?i スタックは空です /////current stack///// 1 2 3 4 5
【Laravel】Eager-Loadingでlimitを使ってはいけない
概要
いけないというか、Eager-Loadingでlimitを利用する際は挙動をちゃんと理解していないと思わぬ動作をする。
本題
以下のようなテーブルがあった際に、Bookに紐づくChapterをEager-Loadingを利用して、それぞれの本の最後の章を取得したい場合を考える。
Books -------------- | id | name | |----|-------| | 1 | book1 | | 2 | book2 | | 3 | book3 | ------------- Chapters ------------------------------ | id | book_id | chapter_num | |----|---------|-------------| | 1 | 1 | 1 | | 2 | 1 | 2 | | 3 | 2 | 1 | | 4 | 2 | 2 | | 5 | 3 | 1 | ------------------------------
そのためにまず、Book-Chapterのテーブル結合を行う。
public function lastChapter() { return $this->hasMany(Chapter::class) ->orderBy('chapter_num', 'desc'); }
$books = Book::with(['lastChapter',])->get()
ここで、私は最後の章だけを取得したいが、現在のlastChapter
ではchapter_num
順に並び替えられているだけなので、
limit(1)
を付与すれば、各Bookの最終章を取れるのではないか、と考えたのでlimit(1)
を付与した。
public function lastChapter() { return $this->hasMany(Chapter::class) ->orderBy('chapter_num', 'desc') ->limit(1); }
しかしながら、limit(1)
を付与すると3つのBook中2つのBookのlastChapter
が空っぽだった。
ここで、Eager-Loadingの挙動について調べてみると、
Eager-Loadingによりlimit(1)
を付与する前のlastChapter
は以下のように変換される。
SELECT * FROM `chapters` WHERE `chapters`.`book_id` IN ('1', '2', '3') ORDER BY `id` DESC
なんと、内部的にはjoinしているのではなく、Chaptersのテーブルから含まれるBookのidをIN句で取得していた。 なるほど、ということはBooksとChaptersをjoinするのではなく、BooksとChaptersを別々に取得して 各Collectionオブジェクトを結合しているらしい。
そのため、limit(1)
を付与すると以下のクエリが発行されるが、Chaptersのデータが1行しか取れずに、
Booksの結果CollectionとChaptersの結果Collectionで結合できるのが1行のデータ分しか結合できないため、
3つ中2つのBookのlastChapter
が空っぽになるというわけだ。
SELECT * FROM `chapters` WHERE `chapters`.`book_id` IN ('1', '2', '3') ORDER BY `id` DESC limit 1
そのため、最終章を取得するためにはEager-Loadingは利用せずにクエリビルダーを使って最適なクエリを自前で記述するか、 Eager-Loadingを利用して最終章以外のデータも取得されてしまうが、それを受け入れて以下のように処理するのが良いだろう。
foreach($books as $book){ $book->lastChapter->first() }