2011-03-13 17 views
6

Jak usunąć każdy n-ty element ciągu?Usuń każdy n-ty element ze stringa

Zgaduję, że używałbyś funkcji drop w pewien sposób.

Jak to upuszcza pierwsze n, jak można to zmienić, tak że po prostu spada n-ty, a następnie n-ty po tym i tak dalej, a nie wszystkie?

dropthem n xs = drop n xs 

Odpowiedz

2
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
+0

Zamiast '' mod' zip' i który jest nieco drogie, to dlaczego nie użyć 'cycle' [ 1..n] i porównać z 1? – Peaker

+0

'remove_every_nth n = map snd. filter ((/ = 0). (\ 'mod \ n). fst). zip [1 ..] ' – Alvivi

+0

@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

2

łączyć ze sobą take i drop do osiągnięcia tego celu.

take 3 "hello world" = "hel" 
drop 4 "hello world" = "o world" 
+0

Popełniłem błąd w moim poście, mam to teraz i to usuwa n-tą wartość z mojej listy. Chciałem usunąć każdą n-tą wartość z mojej listy, więc zgaduję, że muszę dodać rekursję? lub filtrować? – Lunar

+0

@Lunar, co masz na myśli, mówiąc o "każdej n-tej wartości"? – luqui

+0

np 4 „thisiscool” da „thiiscol” swoją usuniętą co 4 element z ciągiem – Lunar

4
-- groups is a pretty useful function on its own! 
groups :: Int -> [a] -> [[a]] 
groups n = map (take n) . takeWhile (not . null) . iterate (drop n) 

removeEveryNth :: Int -> [a] -> [a] 
removeEveryNth n = concatMap (take (n-1)) . groups n 
7

proste. Weź (n-1) elementy, a następnie pomiń 1, spłucz i powtórz.

dropEvery _ [] = [] 
dropEvery n xs = take (n-1) xs ++ dropEvery n (drop n xs) 

Albo pokazuje stylu ze względu na sprawność w

dropEvery n xs = dropEvery' n xs $ [] 
    where dropEvery' n [] = id 
      dropEvery' n xs = (take (n-1) xs ++) . dropEvery n (drop n xs) 
1

Lubię następujące rozwiązanie:

del_every_nth :: Int -> [a] -> [a]  
del_every_nth n = concat . map init . group n 

Po prostu trzeba zdefiniować funkcję group które grupy na liście w części długości n. Ale to całkiem proste:

group :: Int -> [a] -> [[a]] 
group n [] = [] 
group n xs = take n xs : group n (drop n xs) 
+0

hlint zasugeruje używanie 'concatMap' zamiast' concat. mapa " –