Estou interessado em escrever uma função Haskell eficiente triangularize :: [a] -> [[a]]
que pega uma lista (talvez infinita) e a "triangulariza" em uma lista de listas. Por exemplo, triangularize [1..19]
deve retornar
[[1, 3, 6, 10, 15]
,[2, 5, 9, 14]
,[4, 8, 13, 19]
,[7, 12, 18]
,[11, 17]
,[16]]
Por eficiente, quero dizer que quero que ele seja executado no O(n)
tempo em que n
está o comprimento da lista.
Observe que isso é bastante fácil de fazer em uma linguagem como Python, porque anexar ao final de uma lista (matriz) é uma operação de tempo constante. Uma função Python muito imperativa que realiza isso é:
def triangularize(elements):
row_index = 0
column_index = 0
diagonal_array = []
for a in elements:
if row_index == len(diagonal_array):
diagonal_array.append([a])
else:
diagonal_array[row_index].append(a)
if row_index == 0:
(row_index, column_index) = (column_index + 1, 0)
else:
row_index -= 1
column_index += 1
return diagonal_array
Isso ocorreu porque eu tenho usado Haskell para escrever algumas seqüências "tabl" na Enciclopédia On-line de Sequências Inteiras (OEIS) e quero poder transformar uma sequência comum (unidimensional) em uma (2- dimensional) sequência de seqüências exatamente dessa maneira.
Talvez exista uma maneira inteligente (ou não tão inteligente) de foldr
ultrapassar a lista de entradas, mas não consegui resolver isso.
foldr
você pode gostar unfoldr (Just . combWith comb)
para listas infinitas. Infelizmente, como eu mencionei em minha resposta, combWith
é O (n), portanto, a resposta aceita splitAt
é significativamente mais eficiente.