10分でコーディングをやってみた
10分でコーディング | プログラミングに自信があるやつこい!!
まずRubyでやってみた。
(予想通り)10分以上かかる。StringとかArrayとかのマニュアルにちゃんと目を通しておかないと、自分の頭に浮かんだ解法とそれをどうRubyで表現できるか(or できないから他の方法を考えるか)が決まらなくてもどかしい。
class Cards def self.deal(num_players, deck) #players = Array.new(num_players, "") players = (0...num_players).map { "" } i = 0 deck.each_char do |card| idx = i % num_players players[idx] << card i += 1 end num = deck.length / num_players players.map { |cards| cards[0, num] } end end describe Cards do describe "#deal" do it "deals evenly for each player" do Cards.deal(3, "123123123").should == ["111", "222", "333"] end it "deals evenly and discards extra cards" do Cards.deal(4, "123123123").should == ["12", "23", "31", "12"] end it "deals all cards to 1 player" do Cards.deal(1, "012345012345012345").should == ["012345012345012345"] end it "deals no cards when cards are not many enough" do Cards.deal(6, "01234").should == ["", "", "", "", "", ""] end it "deals no cards when there is none" do Cards.deal(2, "").should == ["", ""] end end end
感想とか
- 最初からテスト書いてやった。時間が余計にかかるかデバッグが楽になって時間が短縮できるか微妙だけど、テストがあった方が気楽にかける。(そもそも10分で終わらせる気はあんまりなかったとも言う)
- Array.new(num_players, "")とやると、配列の各要素が同じ文字列オブジェクトを指すことに気づかずはまる。
- カウンターださいから消したい。
- Cardsクラス意味ないね。まぁいいか。
そもそも最初に頭に浮かんだ解法は
- カード"123123123"を3人に配りたい
- 先頭から3つずつに切っていく ["123", "123", "123"]
- 各要素の0番目、1番目、3番目を取って出来上がり ["111", "222", "333"]
というもの。
これをGaucheでやってみると
#!/usr/bin/env gosh (use srfi-1) (use util.list) (use gauche.test) (define (deal num-players deck) (let* ((sliced (slices (string->list deck) num-players)) (cards (filter (lambda (s) (= (length s) num-players)) sliced))) (map list->string (map (lambda (i) (map (cut ref <> i) cards)) (iota num-players))))) (test* "deals evenly (no extra cards)" '("111" "222" "333") (deal 3 "123123123")) (test* "deals evenly (discards extra cards)" '("12" "23" "31" "12") (deal 4 "123123123")) (test* "all cards to 1 player" '("012345012345012345") (deal 1 "012345012345012345")) (test* "no cards to all players" '("" "" "" "" "" "") (deal 6 "01234")) (test* "empty deck" '("" "") (deal 2 ""))
感想とか
- slices 便利
- map 多すぎてやっぱり微妙かもしれない
追記
よく考えたらzipが使える。そのかわりif文が増えるのであまり短くはならないけど。
(define (deal num-players deck) (if (< (string-length deck) num-players) (make-list num-players "") (let* ((sliced (slices (string->list deck) num-players)) (cards (filter (lambda (s) (= (length s) num-players)) sliced))) (map list->string (apply zip cards)))))
同じことをHaskellで
import Data.List (transpose) deal :: Int -> String -> [String] deal numPlayers deck | numPlayers > length deck = replicate numPlayers "" | otherwise = transpose $ slices' numPlayers deck slices :: Int -> [a] -> [[a]] slices n [] = [] slices n xs = case splitAt n xs of (y,ys) -> y : slices n ys slices' :: Int -> [a] -> [[a]] slices' n xs = filter (\x -> n == length x) $ slices n xs main = mapM_ (\ (n:deck:[]) -> print $ deal (read n) deck) [ ["3", "123123123"] -- ["111","222","333"] , ["4", "123123123"] -- ["12","23","31","12"] , ["1", "012345012345012345"] -- ["012345012345012345"] , ["6", "01234"] -- ["", "", "", "", "", ""] , ["2", ""] -- ["", ""] ]
RailsでRESTfulにposts/:year/:month/:dayするにはどうしたらいいんだろう (続き)
前の記事の続き。
id:tkawa さんがコメントで教えてくれてとっくに解決していましたが、
http://api.rubyonrails.org/classes/ActionDispatch/Routing.html
の「Pretty URLs」によると、
match '/articles/:year/:month/:day' => 'articles#find_by_id', :constraints => { ... }
のように書けばいいようです。
routes.rbに「:action」を書いてしまうのがレガシーでRESTfulではないということで、「posts/:year/:month/:day」はRESTfulと言っていいと思いますよ。
この前、Rails3 cheat sheets http://blog.envylabs.com/2010/12/rails-3-cheat-sheets/ にも同じ方法が載っているのを見つけたので改めてまとめておきます。
# これは有効なrouting # OPTIONAL PARAMETERS match '/posts(/:yy(/:mm))' => "posts#index" class PostsController < ApplicationController def index # params[:yy] # params[:mm] end end # CONSTRAINTS match '/:year' => "posts#index", :constraints => {:year => /\d{4}/, :ip => /192\.168\.1\.\d{1,3}/}
結局、下のコードがLegacyとされているのは、全てのコントローラーがアクセスできるようになってしまう問題があるためで、「RESTfulではないから」と思ったのはただの読み違いだったということでした。
# こっちはLegacyなrouting # LEGACY ROUTE match '/:controller(:/:action(/:id(.:format)))'