Как Вы записали бы этот отрывок Clojure в Ruby и/или Haskell?

Я работал над шаблоном Rails и пытался написать немного кода, который позволяет мне заполнять таблицу, или несколько столбцов ул. отмечает "от начала до конца", и "слева направо" через однако много столбцов я указываю. Я просто приобретаю навык 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))))) 

С этим битом кода я могу затем сделать следующее:

(table (range 10) :cols 3)

Распечатанный это было бы похоже так:

0    1    2 
3    4    5 
6    7    8
9

И более хитрый:

(table (range 10) :cols 3 :direction 'down)

Похож так:

0    4    8    
1    5    9    
2    6        
3    7        
10
задан Don Stewart 19 April 2011 в 01:39
поделиться

5 ответов

Я бы, наверное, написал что-то подобное на Haskell, используя пакет Data.List.Split от Hackage:

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] ]

Некоторые из этого , как и тип Direction и трюк транспонировать , были получены из ответа Джкрамера. Я бы не стал использовать ключевые аргументы для чего-то вроде этого в Haskell (на самом деле у него нет таких вещей, но вы можете имитировать их, используя записи, как в ответе Эдварда Кметта), но я ставлю эти аргументы первыми, потому что это более полезно с частичным применением ( defaultTable = таблица по горизонтали 1 ). Функция splitEvery просто разбивает список на списки подходящего размера; остальная часть кода должна быть простой.Функция table возвращает список списков; чтобы получить строку, функция showTable вставляет символы табуляции и новые строки. (Функция intercalate объединяет список списков, отделяя их от заданного списка. Это аналогично Perl / Python / Ruby join , только для списков, а не только строк.)

4
ответ дан 3 December 2019 в 22:35
поделиться
import Data.Array

stride :: Int -> Int -> Int
stride count cols = ceiling (fromIntegral count / fromIntegral cols)

type Direction = Int -> Int -> Int -> Int -> Int

right :: Direction
right count cols x y = y * cols + x

down :: Direction
down count cols x y = x * stride count cols + y

data Options = Options { cols :: Int, direction :: Direction }

options :: Options
options = Options 1 right

table :: Options -> [a] -> Array (Int,Int) (Maybe a)
table (Options cols dir) xs
    = listArray newRange (map f (range newRange))
    where count = length xs
          rows = stride count cols
          newRange = ((0,0),(rows-1,cols-1))
          f (y, x) 
              | ix < count = Just (xs !! ix)
              | otherwise = Nothing
              where ix = dir count cols x y

Это дает нам довольно идиоматическое приближение вашего исходного запроса с дополнительными аргументами:

*Main> table options { cols = 3 } [1..10]
listArray ((0,0),(3,2)) [Just 1, Just 2, Just 3
                        ,Just 4, Just 5, Just 6
                        ,Just 7, Just 8, Just 9
                        ,Just 10,Nothing,Nothing]

*Main> table options { direction = down, cols = 3 } [1..10]
listArray ((0,0),(3,2)) [Just 1,Just 5,Just 9
                        ,Just 2,Just 6,Just 10
                        ,Just 3,Just 7,Nothing
                        ,Just 4,Just 8,Nothing]

Я оставил промежуточные результаты в форме массива, поскольку вы указали, что вы их планировали отформатировать как таблицу или теги ul.

1
ответ дан 3 December 2019 в 22:35
поделиться

Я не могу прочитать код clojure (я никогда не использовал этот язык), но, основываясь на примерах, вот как я бы сделал это в Ruby.

def table array, cols, direction
   if direction==:down
      if array.size%cols != 0
         array[(array.size/cols+1)*cols-1]=nil
         #putting nil in the last space in the array
         #also fills all of the spaces before it
      end
      newarray=array.each_slice(array.size/cols).to_a
      table newarray.transpose.flatten(1), cols, :across
   elsif direction==:across
      array.each_slice(cols) do |row|
         puts row.join("  ")
      end
   else
      raise ArgumentError
   end
end
4
ответ дан 3 December 2019 в 22:35
поделиться

Вот кое-что, что я быстро взломал на Haskell. Я уверен, что это багги и может быть оптимизировано, но это что-то для начала:

import System.IO
import Data.List

data Direction = Horizontal | Vertical

main = do
    putStrLn $ table [1..9] 3 Horizontal
    putStrLn "---"
    putStrLn $ table [1..9] 3 Vertical


table xs ncol direction =
    case direction of
        Horizontal -> format (rows strings ncol)
        Vertical -> format (columns strings ncol)
    where
        format = intercalate "\n" . map (intercalate " ")

        strings = map show xs

        rows xs ncol =
            if length xs > ncol
                then take ncol xs : rows (drop ncol xs) ncol
                else [xs]

        columns xs = transpose . rows xs

Выход:

1 2 3
4 5 6
7 8 9
---
1 4 7
2 5 8
3 6 9
2
ответ дан 3 December 2019 в 22:35
поделиться

Мое решение ruby ​​

def table(values)
  elements = values[:elements]
  cols = values[:cols]
  rows = (elements.count / cols.to_f).ceil

  erg = []

  rows.times do |i|
    cols.times do |j|
      erg << elements[values[:direction] == 'down' ? i+(rows*j) : j+i*(rows-1)]
      if erg.length == cols
        yield erg
        erg = []
      end        
    end
  end
  yield erg
end

Использование и вывод:

table(:elements => [0,1,2,3,4,5,6,7,8,9], :cols => 3) do |h,i,j|
  puts h.to_s << " " << i.to_s << " " << j.to_s
end

puts "---"

table(:elements => [0,1,2,3,4,5,6,7,8,9], :cols => 3, :direction => "down") do |h,i,j|
  puts h.to_s << " " << i.to_s << " " << j.to_s
end

0 1 2
3 4 5
6 7 8
9  
---
0 4 8
1 5 9
2 6 
3 7 
2
ответ дан 3 December 2019 в 22:35
поделиться
Другие вопросы по тегам:

Похожие вопросы: