2015-09-29 2 views
2

Так в работе над проектом Haskell, я в конечном итоге написание следующей функцииСуществует ли стандартное название для этой операции?

reGrid :: [[[a]]] -> [[a]] 
reGrid [] = [] 
reGrid xs | any null xs = [] 
      | otherwise = (concat $ map head xs) : reGrid (map tail xs) 

Для тех, кто не говорит Haskell, это принимает список матриц, и объединяет соответствующие строки в новый матрица.

Его появление несколько раз в этом проекте, и я чувствую, что это какая-то общая операция, которую я пропустил.

Существует ли стандартное название для этой операции? Поиск Hoogle для

[[[a]]] -> [[a] 

Не имеет ничего полезного.

ответ

2

У вас есть куча вещей, и вы хотите превратить их в одну вещь. Обычный способ сделать это с какой-то складкой. Итак, давайте начнем с, что:

regrid [] = [] 
regrid xs = foldr go (repeat []) xs 

Теперь предположим, что у вас есть одна матрица и у вас также есть результат повторного гриддинга остальное. Как вы можете объединить их? Ну, вы хотите объединить строки вместе, пока не закончится, что звучит как задание для zipWith. Так положить все вместе,

regrid = foldr (zipWith (++)) [] 

Это не одна стандартная функция, но она короткая и не обезьяна вокруг с частичными функциями. Однако он имеет проблему эффективности, если список длинный. Чтобы исправить это, вы можете переключиться на левую складку, но правильность строчки будет сложной. Я могу это написать позже.

+0

Именно то, что я искал. Следует отметить, что ваше начальное значение должно быть списком списков, равным по длине входному списку, иначе он фактически не попадет ни в одну из строк, то есть 'let reGrid2 xs = foldr (zipWith (++))) (replicate (length xs) []) xs'. – user2085282

+0

@ пользователь2085282, исправно, но по-разному. – dfeuer

4

Ваша функция очень похожа (но не идентичны) это одна:

reGrid' = map concat . transpose 

Например, мой QuickCheck свойство \xs -> reGrid xs == reGrid' xs превращает эту разницу:

*Main> reGrid [[[]],[]] 
[] 
*Main> reGrid' [[[]],[]] 
[[]] 

Короче говоря, ваша версия будет «отрезать» больше вещей, которые вам действительно могут понравиться (или нет). Для более яркого примера:

*Main> reGrid [["abc"],[]] 
[] 
*Main> reGrid' [["abc"],[]] 
["abc"] 

Вы можете судить сами, неважно, имеют ли они случаи, когда они отличаются друг от друга.