remove_every_nth :: Int -> [a] -> [a]
remove_every_nth n = foldr step [] . zip [1..]
where step (i,x) acc = if (i `mod` n) == 0 then acc else x:acc
Esto es lo que hace la función:
zip [1..]
se utiliza para indexar todos los elementos de la lista, por lo que, por ejemplo, zip [1..] "foo"
se convierte en [(1,'f'), (2,'o'), (3,'o')]
.
La lista indexada se procesa con un right fold que acumula cada elemento cuyo índice no es divisible por n
.
Aquí hay una versión un poco más larga que hace esencialmente lo mismo, pero evita las asignaciones de memoria extra de zip [1..]
y no necesita calcular el módulo.
remove_every_nth :: Int -> [a] -> [a]
remove_every_nth = recur 1
where recur _ _ [] = []
recur i n (x:xs) = if i == n
then recur 1 n xs
else x:recur (i+1) n xs
en lugar de '' zip' y mod' que es un poco caro, por qué no usar 'cycle' [ 1..n] y comparar con 1? – Peaker
'remove_every_nth n = map snd. filter ((/ = 0). (\ 'mod \' n). fst). zip [1 ..] ' – Alvivi
@Peaker: Gracias por la sugerencia. No estoy seguro de cómo utilizarías 'cycle' sin usar' zip', pero mejoré un poco la eficiencia de una manera diferente. – shang