2013-04-03 15 views
5

Also muss ich eine Funktion alsHaskell- Finden Element in einer Liste und das Rück seine Position

invFib :: Integer -> Maybe Integer 

beschrieben machen, die einen Integer und sucht es in der Fibonacci-Sequenz nimmt (wie durch die Funktion unten beschrieben)

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

und gibt den Index der Zahl Beispiel:

invFib 0 ~>Just 0

invFib 1 ~>Just 1 oder Just 2

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

invFib (fibs !! 99) ~>Just 99

Ich habe versucht, eine Funktion zu machen, die eine Liste von ganzen Zahlen nimmt und den Index spuckt, aber es hält versagt . Irgendwelche Gedanken?

diese Funktion i tried-

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

Edit: die Funktion auf Zahlen nicht in der Fibonacci-Sequenz friert, zeigt auch nur 1 Wert, wenn 1 eingegeben wird

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

Sie sollten den Code, den Sie ausprobiert haben, wenn Sie eine Erklärung des Problems damit möchten. – Pubby

+1

'findNum' sieht wie ein guter Anfang aus. Sie müssen sich die folgende Frage stellen: Angesichts der Tatsache, dass "fibs" eine unendliche Liste ist, wie würden Sie feststellen, dass "54" nicht in dieser Liste enthalten ist? – MtnViewMark

Antwort

8

Also hier der Schlüssel ist, dass fibs unendlich ist, aber auch monoton steigend. Daher, sobald sie die Zahl wird gesucht übersteigt, kann es Nothing zurück:

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 

Und so:

$ 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] 

Es gibt einige andere Möglichkeiten, es zu tun. Denken Sie an zip fibs [0..] und dann könnten Sie dropWhile verwenden, um den Teil weniger als n zu entfernen und zu testen, was übrig ist.

+0

vielen dank, es funktioniert perfekt! – lopezrican304

+0

FYI - ': set + s; lass a = 10^25000; invFibMVMark a => "Nichts (0,38 Sekunden, 13927928 Bytes)"; invFibGroovy a => "Nichts (0,18 Sekunden, 3633660 Bytes)" –

+0

@groovy haben Sie die beiden frisch getestet (d. h. einschließlich der Zeit für die Generierung der "fibs" Sequenz)? Wurde die Datei vor dem Laden in GHCi kompiliert? In meinen Tests lief die Version von MVMark um 10% schneller als deine. Vielleicht können wir sagen, dass beide Versionen in ihrer Leistung * vergleichbar * sind. :) –

1

Wenn Sie‘ ve bereits berechnet fibs, dann ist die Antwort einfach:

+0

, die den Typ Int zurückgibt und ich brauche den Typ Vielleicht Integer, wie kann ich es konvertieren? Ich weiß für den Wert 1 wäre der einzige Wert, der zwei Antworten hat – lopezrican304

+0

Es wurde behoben, um eine 'Integer' zurückzugeben. –

+1

Da die Liste unendlich ist, wird 'elemIndex' nicht funktionieren, wenn Sie wollen, dass die Sache für Zahlen endet, die nicht in der Sequenz sind. Sie müssen die Tatsache ausnutzen, dass die Liste sortiert ist. – hammar

7

Warum verwenden Sie nicht eine Funktion wie 'takeWhile', um einen Abschnitt der unendlichen 'fibs' Liste zurückzugeben, den Sie untersuchen möchten? Mit der endlichen Liste könnten Sie eine Funktion wie 'elemIndex' anwenden, die mit einer kleinen Typanpassung zurückgeben könnte, wonach Sie suchen.

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

Das fühlt sich falsch an, weil im Wesentlichen die Arbeit zweimal getan wird: einmal von 'takeWhile' und einmal von' findIndex'. – MtnViewMark

+1

Nur auf den ersten Blick. Jedes Element ist zuerst '<=' 'ed und dann '==' ed. In deinem Code ist jedes Element zuerst '==' 'ed und jeder außer dem letzten ist dann '<'' ed. Die Arbeit wird also nicht zweimal gemacht und zeigt, wie modular Haskell sein kann. –

+0

Wahr - in beiden Versionen werden zwei Vergleichsoperationen auf jedes Element angewendet. In meinem Codebeispiel gibt es nur eine explizite Liste Traversal, während in diesem Code zwei sind. Das heißt, es ist möglich, dass der Compiler "findIndex" und "takeWhile" fusioniert, was zu einer Listendurchquerung führt. In meinem Code könnte man die Wächter durch 'case compare a x of' ersetzen, was zu einem Vergleich pro Element führt. - * Alles, was gesagt wurde, * mein Kommentar war nicht über Effizienz, sondern über die Präsentation des Algorithmus. Es fühlte sich falsch an, weil es mehr Arbeit vorschreibt, als nötig ist. – MtnViewMark