2015/05/27


問題1

scriptencoding utf-8

"forループ、whileループ、および再帰を使用して、リスト内の数字の合計を計算する
"3つの関数を記述せよ。

functions:problem1_1()
  let l = [3,5,1,2,9]
  let s = 0
  for i in l
    let s += i
  endfor
  return s
endfunction

functions:problem1_2()
  let l = [3,5,1,2,9]
  let s = 0
  let i = 0
  while i < len(l)
    let s += l[i]
    let i += 1
  endwhile
  return s
endfunction

functions:_problem1_3(s, l)
  if len(a:l)
    return a:s + a:l[0+ s:_problem1_3(a:sa:l[1:])
  endif
  return a:s
endfunction

functions:problem1_3()
  let l = [3,5,1,2,9]
  return s:_problem1_3(0, l)
endfunction

if s:problem1_1() != 20
  throw "プログラマ失格: s:problem1_1"
endif

if s:problem1_2() != 20
  throw "プログラマ失格: s:problem1_2"
endif

if s:problem1_3() != 20
  throw "プログラマ失格: s:problem1_3"
endif

問題2

scriptencoding utf-8

" 交互に要素を取ることで、2つのリストを結合する関数を記述せよ。例えば
" [a, b, c]と[1, 2, 3]という2つのリストを与えると、関数は [a, 1, b, 2, c, 3]
" を返す。

functions:_problem2(lhs, rhs)
  let r = []
  for i in range(len(a:lhs))
    call add(r, a:lhs[i])
    call add(r, a:rhs[i])
  endfor
  return r
endfunction

functions:problem2()
  let lhs = ["a""b""c"]
  let rhs = [123]
  return s:_problem2(lhs, rhs)
endfunction

if s:problem2() !=# ["a"1"b"2"c"3]
  throw "プログラマ失格: s:problem2"
endif

問題3

scriptencoding utf-8

" 最初の100個のフィボナッチ数のリストを計算する関数を記述せよ。定義では、フィ
" ボナッチ数列の最初の2つの数字は0と1で、次の数は前の2つの合計となる。例えば最
" 初の10個のフィボナッチ数列は、0, 1, 1, 2, 3, 5, 8, 13, 21, 34となる。

functions:fib(n)
  let r = [01]
  let i = 2
  while i < a:n
    call add(r, r[i-1+ r[i-2])
    let i += 1
  endwhile
  return r
endfunction

functions:problem3()
  return s:fib(100)
endfunction

if s:problem3() !=# [0112358132134558914423337761098715972584418167651094617711286574636875025121393196418317811514229832040134626921783093524578570288792274651493035224157817390881696324598610233415516558014126791429643349443770140873311349031701836311903297121507348075269767778742049125862690252036501107432951280099533162911738626757127213958386244522585143371736543529616259128672987995672202604115480087559202504730781961405273953788165574703198421061020985772317167680177565277778900352884494557021285372723460248141117669030460994190392490709135308061521170129498454011879264806515533049393130496954492865721114850779780503416454622906707552793970088475789443943237914641447233402467622123416728348467685378890623731439066130579072161159199194853094755497160500643816367088259695496911122585420196140727489673679891637638612258110008777836610193117799794160047141892880067194370816120466004661037553030975401138047463464291220016041512187673819740274219868223167319404346349900999055168070885485832307283621143489848422977135301852344706746049218922995834555169026]
  throw "プログラマ失格: s:problem3"
endif

問題4

scriptencoding utf-8

" 正の整数のリストを与えられたとき、数を並び替えて可能な最大数を返す関数を記述
" せよ。例えば、[50, 2, 1, 9]が与えられた時、95021が答えとなる。

functions:compare(lhs, rhs)
  return a:rhs . a:lhs < a:lhs . a:rhs ? -1 : 1
endfunction

functions:problem4()
  let l = [50219]
  return join(sort(l, function('s:compare'))'')
endfunction

if s:problem4() !=# 95021
  throw "プログラマ失格: s:problem4"
endif

問題5

scriptencoding utf-8

" 1,2,…,9の数をこの順序で、"+"、"-"、またはななにもせず結果が100となるあらゆ
" る組合せを出力するプログラムを記述せよ。
" 例えば、1 + 2 + 34 - 5 + 67 - 8 + 9 = 100となる。

functions:make100(r, b, n) abort
  if a:n == 10
    if eval(a:b) == 100
      call add(a:ra:b)
    endif
  else
    for op in ['+''-''']
      call s:make100(a:ra:b . op . (a:n)a:n+1)
    endfor
  endif
  return ''
endfunction

functions:problem5()
  set maxfuncdepth=200
  let r = []
  call s:make100(r, 12)
  return r
endfunction

for s:l in s:problem5()
  if eval(s:l) != 100
    throw "プログラマ失格: s:problem5"
  endif
endfor
unlet s:l

で、問題3 なのですが Vim script では 32bit int しか扱えないので100個のフィボナッチ数列が数えられません。

プログラマ失格

よってわたくし、プログラマ失格となりました。みなさん今までお世話になりました。

えーっと、良く見たら結果が違ってただけでした。なのでエラーにはならなくなりました...。ですが Vim script が 32bit int 以上が扱えないのを知った上で bigint を1時間以内で実装出来なかった僕はプログラマ失格でしょうか。。。



willnet/gimei - GitHub

gimei は、日本人の名前や、日本の住所をランダムに返すライブラリです。テストの時などに使います。似たようなライブラリにfakerがあります。fakerはとても優れたライブラリで、多言語対応もしていますが、ふりがな(フリガナ)は流石に対応していません。gimei ふりがな(及びフリガナ)に対応しています。

https://github.com/willnet/gimei

オリジナルは ruby gems です。

mattn/go-gimei - GitHub

golang port of gimei

https://github.com/mattn/go-gimei

作者の方に ok を貰ったのでデータも同梱しています。使い方もほぼ同じです。

package main

import (
    "fmt"

    "github.com/mattn/go-gimei"
)

func main() {
    name := gimei.NewName()
    fmt.Println(name)                  // 斎藤 陽菜
    fmt.Println(name.Kanji())          // 斎藤 陽菜
    fmt.Println(name.Hiragana())       // さいとう はるな
    fmt.Println(name.Katakana())       // サイトウ ハルナ
    fmt.Println(name.Last.Kanji())     // 斎藤
    fmt.Println(name.Last.Hiragana())  // さいとう
    fmt.Println(name.Last.Katakana())  // サイトウ
    fmt.Println(name.First.Kanji())    // 陽菜
    fmt.Println(name.First.Hiragana()) // はるな
    fmt.Println(name.First.Katakana()) // ハルナ
    fmt.Println(name.IsMale())         // false

    male := gimei.NewMale()
    fmt.Println(male)            // 小林 顕士
    fmt.Println(male.IsMale())   // true
    fmt.Println(male.IsFemale()) // false

    address := gimei.NewAddress()
    fmt.Println(address)                       // 岡山県大島郡大和村稲木町
    fmt.Println(address.Kanji())               // 岡山県大島郡大和村稲木町
    fmt.Println(address.Hiragana())            // おかやまけんおおしまぐんやまとそんいなぎちょう
    fmt.Println(address.Katakana())            // オカヤマケンオオシマグンヤマトソンイナギチョウ
    fmt.Println(address.Prefecture)            // 岡山県
    fmt.Println(address.Prefecture.Kanji())    // 岡山県
    fmt.Println(address.Prefecture.Hiragana()) // おかやまけん
    fmt.Println(address.Prefecture.Katakana()) // オカヤマケン
    fmt.Println(address.Town)                  // 大島郡大和村
    fmt.Println(address.Town.Kanji())          // 大島郡大和村
    fmt.Println(address.Town.Hiragana())       // おおしまぐんやまとそん
    fmt.Println(address.Town.Katakana())       // オオシマグンヤマトソン
    fmt.Println(address.City)                  // 稲木町
    fmt.Println(address.City.Kanji())          // 稲木町
    fmt.Println(address.City.Hiragana())       // いなぎちょう
    fmt.Println(address.City.Katakana())       // イナギチョウ

    prefecture := gimei.NewPrefecture()
    fmt.Println(prefecture) // 青森県
}

注意点としては漢字の名前に対して読みが複数ある場合もあります。例えば上記の「陽菜」だと「はな」と「はるな」の2つがあります。Stringer の実装は漢字出力にしています。テストの際にお役立て下さい。


2015/05/21


slack から stackoverflow を検索出来る slack-overflow の lingr 版を作ってみた。

karan/slack-overflow - GitHub
https://github.com/karan/slack-overflow
akechi/stackoverflow-lingrbot - GitHub
https://github.com/akechi/stackoverflow-lingrbot

今回はなんとなく gin で書いた。

Gin Web Framework

Low Overhead Powerful API You can add global, per-group, and per-route middlewares, thousands of nes...

https://gin-gonic.github.io/gin/

コード短いのでのっけておく。

package main

import (
    "encoding/json"
    "flag"
    "fmt"
    "net/http"
    "net/url"
    "os"
    "regexp"

    "github.com/gin-gonic/gin"
    "github.com/mattn/go-lingr"
)

type resp struct {
    Items []struct {
        Tags  []string `json:"tags"`
        Owner struct {
            Reputation   int    `json:"reputation"`
            UserID       int    `json:"user_id"`
            UserType     string `json:"user_type"`
            ProfileImage string `json:"profile_image"`
            DisplayName  string `json:"display_name"`
            Link         string `json:"link"`
        } `json:"owner"`
        IsAnswered       bool   `json:"is_answered"`
        ViewCount        int    `json:"view_count"`
        AnswerCount      int    `json:"answer_count"`
        Score            int    `json:"score"`
        LastActivityDate int    `json:"last_activity_date"`
        CreationDate     int    `json:"creation_date"`
        QuestionID       int    `json:"question_id"`
        Link             string `json:"link"`
        Title            string `json:"title"`
    } `json:"items"`
    HasMore        bool `json:"has_more"`
    QuotaMax       int  `json:"quota_max"`
    QuotaRemaining int  `json:"quota_remaining"`
}

var re = regexp.MustCompile(`^stackoverflow(?:\w+) (.+)$`)

func defaultAddr() string {
    port := os.Getenv("PORT")
    if port == "" {
        return ":80"
    }
    return ":" + port
}

var addr = flag.String("addr", defaultAddr(), "server address")

func main() {
    flag.Parse()

    r := gin.Default()

    r.GET("/"func(c *gin.Context) {
        c.String(200"")
    })
    f := func(c *gin.Context) {
        site := c.Params.ByName("site")
        if site == "" {
            site = "stackoverflow"
        }
        var status lingr.Status
        if !c.EnsureBody(&status) {
            return
        }
        urls := ""
        for _, event := range status.Events {
            message := event.Message
            if message == nil {
                continue
            }
            if !re.MatchString(message.Text) {
                continue
            }
            question := re.FindStringSubmatch(message.Text)[1]
            params := url.Values{}
            params.Add("intitle", question)
            params.Add("site", site)
            params.Add("sort""activity")
            params.Add("order""desc")
            res, err := http.Get("https://api.stackexchange.com/2.2/search?" + params.Encode())
            println("https://api.stackexchange.com/2.2/search?" + params.Encode())
            if err != nil {
                println(err.Error())
                continue
            }
            defer res.Body.Close()
            var resp resp
            if err := json.NewDecoder(res.Body).Decode(&resp); err != nil {
                println(err.Error())
                continue
            }
            for _, item := range resp.Items {
                u := item.Link
                if len(u) > 300 {
                    u = fmt.Sprintf("http://%s.com/q/%d", site, item.QuestionID)
                }
                s := fmt.Sprintf("%s\n%s\n", item.Title, u)
                println(s)
                if len(urls+s) > 1000 {
                    break
                }
                urls += s
            }
        }
        c.String(200, urls)
        return
    }
    r.POST("/", f)
    r.POST("/:site", f)
    r.Run(*addr)
}

僕がこういうのを書く時は、一度 JSON を何等かの方法で得て

JSON-to-Go: Convert JSON to Go instantly

JSON-to-Go Convert JSON to Go struct This tool instantly converts JSON into a Go type definition. Pa...

http://mholt.github.io/json-to-go/

このサイトで golang の struct に変換、クライアント処理として stackoverflow の検索処理を実装しながら最後に Web のガワを付けていく。実質20~30分程度で出来た。

困ったのが stackoverflow の日本語版にも対応したのだけど、日本語版は URL にタイトルの日本語が含まれていて平気で1000文字を超える。しかし lingr の API は1000文字までしか発言出来なくて(bot triggered アクションで分割送信なら可能)困った。どうやら URL の日本語部分は無くてもアクセス出来るのが分かったので300文字(適当)超えたらそっちを使う様に対応した。

lingr だと stackoverflow という名前で居ますので invite して「stackoverflow jquery」とか「stackoverflowja ウェブ」とか発言すると反応します。