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
Oto co robi funkcja:
zip [1..]
służy do indeksu wszystkie pozycje na liście, więc na przykład zip [1..] "foo"
staje się [(1,'f'), (2,'o'), (3,'o')]
.
Lista indeksowana jest następnie przetwarzana za pomocą right fold, która gromadzi każdy element, którego indeks nie jest podzielny przez n
.
Oto nieco dłuższa wersja, która w zasadzie to samo, ale unika dodatkowych przydziałów pamięci z zip [1..]
i nie musi obliczać modułu.
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
Zamiast '' mod' zip' i który jest nieco drogie, to dlaczego nie użyć 'cycle' [ 1..n] i porównać z 1? – Peaker
'remove_every_nth n = map snd. filter ((/ = 0). (\ 'mod \ n). fst). zip [1 ..] ' – Alvivi
@Peaker: Dzięki za sugestię. Nie jestem pewien, w jaki sposób używałbyś 'cyklu' bez użycia' zip', ale trochę poprawiłem wydajność w inny sposób. – shang