2013-03-21 12 views
9

Czy istnieje funkcja biblioteczna w Haskell, która pozwoli mi sprawdzić, czy lista jest kolejno zamawiana? na przykład. [1,2,3,4] jest ważny, [1,2,3,10] jest nieważny.Sprawdzanie, czy lista jest zamawiana kolejno

Zasadniczo mogę mieć listę, która obejmuje od 3 do 5 elementów i próbuję sprawdzić, czy lista jest porządkowana kolejno.

moja próba (nie jestem pewien, czy to właściwa droga do niego zbliżyć, wydaje się być zbyt wiele powtórzenie)

isSucc:: [Integer] -> Bool 
isSucc[]   = True 
isSucc(x:y:zs)  = 
    if (x+1) == y 
    then True && isSucc(y:zs) 
    else isSucc(y:zs) 

Po mam tej pracy funkcji, zamierzam na temat korzystania do filtrowania list list (Zachowaj listę tylko na liście i tylko wtedy, gdy jest zamawiana kolejno)

Odpowiedz

8

Nie ma w tym żadnej standardowej funkcji.

Oto stałą wersję swojej funkcji, co ogólne, usunięcie zbędnych warunków i dodając brakujące te:

isSucc :: (Enum a, Eq a) => [a] -> Bool 
isSucc [] = True 
isSucc (x:[]) = True 
isSucc (x:y:zs) | y == succ x = isSucc $ y:zs 
isSucc _ = False 
13

Możesz użyć sztuczki zipWith f xs (drop 1 xs), aby zastosować f do kolejnych par elementów listy. (Zauważ drop 1 zamiast tail, ponieważ ten ostatni nie jeśli lista jest pusta!)

Jeśli zastąpić f z <= dostaniesz listę Bool wartości. Teraz sprawdź, czy wszystkie one są True.

isSucc xs = and $ zipWith (<=) xs (drop 1 xs) 
+0

Sposób na błędne zrozumienie pytania!Powinno być jasne, jak zmienić 'f', aby zrobić to, co chcesz. – MathematicalOrchid

+0

Nigdy nie myślałem o zrobieniu kropli 1 w zamian. Wydaje się lepszym rozwiązaniem do wdrożenia, ale czy "spadek 1 xs" będzie droższy w porównaniu do '(x: xs)'? – rlhh

+3

W rzeczywistości, 'tail' jest w porządku, gdy jest używany z' zipWith' w tym przypadku, jako przypadek porządku 'zipWith' ocenia jego argumenty. Ale to nie przypadek, że ocenia swoje argumenty w tej kolejności. – Carl

5

wolę używać trochę rozwiązanie bardziej czytelny niż ten, który jest oferowany przez MathematicalOrchid .

Przede wszystkim będziemy określenia funkcji utylitarnych parami, które mogą być przydatne w wielu różnych okolicznościach:

pairwise xs = zip xs $ tail xs 

lub bardziej nowoczesny sposób:

import Control.Applicative ((<*>)) 

pairwise = zip <*> tail 

a następnie używać go z pozostałe kombinatory:

isSucc xs = all (\(x,y) -> succ x == y) $ pairwise xs 
+1

To rozwiązanie nie robi tego, co chce OP, i jest błędne w taki sam sposób jak w @MatemachicalOrchid. Zobacz mój komentarz do jego odpowiedzi: http://stackoverflow.com/questions/15542328/checking-to-see-if-a-list-is-orded-successively/15542475#comment22025580_15542475 –

+0

Iaroslav, masz całkowitą rację. Będę edytować odpowiedź. – Shaggie

+0

Uwielbiam sposób, w jaki użyłeś instancji aplikacji Applicative do komponowania z '<*>'. Nadal próbuję owinąć mi głowę w głowę) Mindbending stuff! –

0

Ther e to kolejny sposób,

isOrdered :: (Enum a, Eq a) => (a -> a -> Bool) -> [a] -> Bool 
isOrdered op (a:b:ls) = op a b && isOrdered op (b:ls) 
isOrdered op _ = True 

Zatem

isSucc = isOrdered ((==) . succ) 
+0

To jest niepoprawne - OP chce sprawdzić, czy elementy są kolejne, nie tylko, że są zamówione. Możesz to poprawić za pomocą 'isSucc = isOrdered ((==). Succ)' – kputnam

+0

OK, dzięki za komentarz, nie mam tego wyrafinowania. – zurgl

+0

Cieszę się, że każdy pojedynczy plakat źle odczytał pytanie w taki sam sposób jak ja. :-) – MathematicalOrchid

0

Jeśli chcesz sprawdzić, czy wszystkie kolejne różnice są równe jeden, można użyć

isIncreasingByOne :: (EQ a, Num a) => [A] -> Bool isIncreasingByOne = wszystko (== 1) (zipWith (-) (Xs ogona) XS)

ten działa na rodzaje numerycznych (stąd Num a constra int), w tym Float i Double. Łatwo to również dostosować, jeśli chcesz sprawdzić, czy sekwencja rośnie o więcej niż 5 naraz.

Powiązane problemy