dno*_*len 10 ruby haskell language-comparisons clojure
我正在研究一个Rails模板,并试图编写一些代码,允许我填充一个表或多列ul标签"从上到下"和"从左到右"跨越我指定的许多列.我刚刚掌握了Ruby,所以我无法理解这一点.我也对这个有用的片段的惯用Haskell版本感到好奇.对Clojure版本的改进表示赞赏:
(defn table [xs & {:keys [cols direction]
:or {cols 1 direction 'right}}]
(into []
(condp = direction
'down (let [c (count xs)
q (int (/ c cols))
n (if (> (mod c q) 0) (inc q) q)]
(apply map vector (partition n n (repeat nil) xs)))
'right (map vec (partition cols cols (repeat nil) xs)))))
Run Code Online (Sandbox Code Playgroud)
有了这段代码,我就可以做到以下几点:
(table (range 10) :cols 3)
Run Code Online (Sandbox Code Playgroud)
打印出来的情况如下:
0 1 2
3 4 5
6 7 8
9
Run Code Online (Sandbox Code Playgroud)
更棘手的一个:
(table (range 10) :cols 3 :direction 'down)
Run Code Online (Sandbox Code Playgroud)
看起来像这样:
0 4 8
1 5 9
2 6
3 7
Run Code Online (Sandbox Code Playgroud)
我可能会使用Data.List.SplitHackage 的包在 Haskell 中写这样的东西:
import Data.List (intercalate, transpose)
import Data.List.Split (splitEvery)
data Direction = Horizontal | Vertical deriving (Eq, Read, Show)
table :: Direction -> Int -> [a] -> [[a]]
table Horizontal cols xs = splitEvery cols xs
table Vertical cols xs = let (q,r) = length xs `divMod` cols
q' = if r == 0 then q else q+1
in transpose $ table Horizontal q' xs
showTable :: Show a => [[a]] -> String
showTable = intercalate "\n" . map (intercalate "\t" . map show)
main :: IO ()
main = mapM_ putStrLn [ showTable $ table Horizontal 3 [0..9]
, "---"
, showTable $ table Vertical 3 [0..9] ]
Run Code Online (Sandbox Code Playgroud)
其中一些内容,例如Direction类型和transpose技巧,源自 jkramer 的答案。我不会在 Haskell 中使用关键字参数来实现类似的东西(它实际上没有这样的东西,但你可以使用 Edward Kmett 的答案中的记录来模拟它们),但我把这些参数放在第一位,因为它对于部分应用程序更有用( defaultTable = table Horizontal 1)。该splitEvery函数只是将列表分成适当大小的列表;其余的代码应该很简单。该table函数返回一个列表的列表;为了获取字符串,该showTable函数会插入制表符和换行符。(该intercalate函数连接列表的列表,将它们与给定的列表分开。它类似于 Perl/Python/Ruby 的join,仅适用于列表而不仅仅是字符串。)