import Data.Function import qualified Data.List as L import qualified Data.Map as M sp :: Char sp = '_' alignColumn :: [String] -> [String] alignColumn = L.transpose . f . L.transpose . addsp where addsp xss = map add xss where maxlen = foldr (\x a -> if length x > a then length x else a) 0 xss add xs = xs ++ replicate (maxlen - length xs) sp f [] = [] f xss = g $ do is <- groupOfIndex $ head xss let (ys:yss) = insertSP xss is return $ ys : f yss g [] = [] g xs = L.minimumBy (compare `on` length) xs insertSP :: [String] -> [Int] -> [String] insertSP xss1 is = f xss1 pre where pre = zipWith (\k _ -> if elem k is then Nothing else Just sp) [0..] (head xss1) f [] cs | all (== Nothing) cs = [] | otherwise = foldr (\x acc -> maybe sp id x : acc) [] cs : [] f (xs:xss) cs = (map fst ys) : f xss (map snd ys) where ys = zipWith g xs cs where g x Nothing = (x, Nothing) g x (Just c) = (c, Just x) groupOfIndex :: String -> [[Int]] groupOfIndex xs = map (spi++) . M.elems . fst . foldl f (M.empty, 0) $ xs where spi = L.findIndices (==sp) xs f (acc,i) x | x == sp = (acc, i+1) | otherwise = (M.insertWith (++) x [i] acc, i+1) main :: IO () main = do run ["1","1"] run ["1","2"] run ["12", "21"] run ["11", "12"] run ["113", "114"] run ["123", "134"] run ["1212", "1322", "1122"] run ["123", "113", "1323"] run ["1234", "4321", "1122"] -- run ["12121313432121233", "21322312443213443"] where run xs = do mapM_ putStrLn xs putStrLn . unlines $ alignColumn xs