2013-04-03 14 views
5

więc muszę zrobić to funkcja opisana jakoHaskell- Znajdź element listy i zwraca jego pozycję

invFib :: Integer -> Maybe Integer 

który odbywa liczbą całkowitą i patrzy na nią w ciągu Fibonacciego (jak opisane przez funkcję poniżej)

fibs :: [Integer] 
fibs = 0:1:(zipWith (+) fibs (tail fibs)) 

i zwraca indeks przykład numer:

invFib 0 ~>Just 0

invFib 1 ~>Just 1 lub Just 2

map invFib [54, 55, 56] ~>[Nothing,Just 10,Nothing]

invFib (fibs !! 99) ~>Just 99

Próbowałem czyniąc funkcję, która pobiera listę liczb całkowitych i wypluwa indeksu, ale utrzymuje braku . jakieś pomysły?

to funkcja i wypróbowaną

findNum :: [Integer] -> Integer -> Integer -> Integer 
findNum x:xs y z = if x == y 
       then z 
       else findNum xs y (z+1) 

Edit: funkcja nie zamarza na numery w sekwencji Fibonacciego, także pokazuje tylko wartość 1, gdy 1 jest wpisany

invFib :: Integer -> Maybe Integer 
invFib n = if n < 0 
     then Nothing 
     else fmap fromIntegral (elemIndex n fibs) 
+1

Powinieneś opublikować kod, który wypróbowałeś, jeśli chcesz mu wyjaśnić problem. – Pubby

+1

'findNum' wygląda na dobry początek. Musisz zadać sobie to pytanie: biorąc pod uwagę, że 'fibs' jest nieskończoną listą, jak byś określił, że, powiedzmy,' 54' nie znajduje się na tej liście? – MtnViewMark

Odpowiedz

8

Tak więc kluczem jest to, że fibs jest nieskończony, ale równieżmonotonicznie rośnie. Stąd, gdy wartość ta przekracza liczbę poszukiwane, może powrócić Nothing:

findIndexInAscendingList :: (Ord a) => a -> [a] -> Maybe Integer 
findIndexInAscendingList a xs = find 0 xs 
    where 
    find i [] = Nothing -- won't get used for fibs 
    find i (x:xs) | a == x = Just i 
        | a < x  = Nothing 
        | otherwise = find (i + 1) xs 

invFib :: Integer -> Maybe Integer 
invFib n = findIndexInAscendingList n fibs 

i tak:

$ ghci 
GHCi, version 7.4.2: http://www.haskell.org/ghc/ :? for help 
λ: :load Fib.hs 
[1 of 1] Compiling Main    (Fib.hs, interpreted) 
Ok, modules loaded: Main. 
λ: map invFib [54,55,56] 
[Nothing,Just 10,Nothing] 

Istnieje kilka innych sposobów na to zbyt. Pomyśl o zip fibs [0..], a następnie możesz użyć dropWhile, aby usunąć część mniejszą niż n i sprawdzić, co zostało.

+0

dziękuję bardzo, działa idealnie! – lopezrican304

+0

FYI - ': set + s; niech a = 10^25000; invFibMVMark a => "Nic (0,38 s, 13927928 bajtów)"; invFibGroovy a => "Nic (0,18 s, 3633660 bajtów)" ' –

+0

@groovy czy przetestowałeś oba z nich na świeżo (tj. włączając czas na wygenerowanie sekwencji 'fibs')? Czy plik został skompilowany przed załadowaniem do GHCi? W moich testach widziałem, że wersja MVMark działa szybciej niż twoja, o 10%. Być może możemy przyjąć, że obie wersje są * porównywalne * w ich wydajności. :) –

1

Jeśli” ve już wyliczył fibs, wtedy odpowiedź jest prosta:

import Data.List 

invFib :: Integer -> Maybe Integer 
invFib n = fmap fromIntegral (elemIndex n fibs) 

fibs :: [Integer] 
fibs = 0:1:(zipWith (+) fibs (tail fibs)) 
+0

, która zwraca typ Int i potrzebuję typu Może Integer, jak mogę go przekonwertować? Wiem, że wartość 1 byłaby jedyną wartością, która ma dwie odpowiedzi: – lopezrican304

+0

Naprawiono to, aby zwracać wartość "Integer". –

+1

Ponieważ lista jest nieskończona, 'elemIndex' nie zadziała, jeśli chcesz, aby rzecz kończyła się na numery nie w kolejności. Musisz skorzystać z tego, że lista jest posortowana. – hammar

7

Dlaczego nie użyć funkcji takiej jak "takeWhile", aby zwrócić sekcję nieskończonej listy 'fibs', którą chcesz zbadać? Z listą skończoną można zastosować funkcję taką jak "elemIndex", która przy niewielkiej korekcie typu może zwrócić to, czego szukasz.

elemIndex myInteger (takeWhile (<= myInteger) fibs) 
+0

To źle się wydaje, ponieważ w istocie praca jest wykonywana dwa razy: raz przez "takeWhile" i raz przez "findIndex". – MtnViewMark

+1

Tylko na pierwszy rzut oka. Każdy element jest najpierw '<=' 'ed, a następnie '==' ed. W twoim kodzie, każdy element jest najpierw '==' 'ed i wszyscy, ale ostatni jest następnie "<" "ed. Tak więc praca nie jest wykonywana dwa razy i pokazuje ładnie jak może być modułowy Haskell. –

+0

True - w obu wersjach, gdy są one ustawione, dwie operacje porównania są stosowane do każdego elementu. W moim przykładzie kodu istnieje tylko jedno jawne przemieszczenie listy, podczas gdy w tym kodzie są dwa. Powiedział, że jest możliwe, że kompilator będzie fuse 'findIndex' i' takeWhile' prowadzące do jednego przejścia listy. W moim kodzie, można zastąpić strażników "przypadkiem porównać x of" prowadząc do jednego porównania na element. - * Wszystko, co zostało powiedziane, * moja uwaga nie dotyczyła efektywności, ale prezentacji algorytmu. Czułem się niesłuszny, ponieważ określa on więcej pracy niż trzeba. – MtnViewMark