2013-04-03 12 views
5

quindi ho bisogno di fare una funzione descritta comeHaskell- Trova elemento in una lista e restituisce la sua posizione di

invFib :: Integer -> Maybe Integer 

che prende un intero e lo cerca nella sequenza di Fibonacci (come descritto dalla funzione di seguito)

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

e restituisce l'indice del numero di esempio:

invFib 0 ~>Just 0

invFib 1 ~>Just 1 o Just 2

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

invFib (fibs !! 99) ~>Just 99

Ho provato a fare una funzione che prende una lista di interi e sputa fuori l'indice, ma mantiene in mancanza . qualche idea?

questo è funzione i tried-

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

Edit: la funzione si blocca su numeri non nella sequenza di Fibonacci, anche mostra solo 1 valore quando si immette 1

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

Dovresti pubblicare il codice che hai provato se vuoi una spiegazione del problema. – Pubby

+1

'findNum' sembra un buon inizio. Devi pormi questa domanda: dato che 'fibs' è una lista infinita, come stabiliresti che, per esempio,' 54' non è in quella lista? – MtnViewMark

risposta

8

Così la chiave qui è che fibs è infinito, ma anche monotona crescente. Quindi, una volta che si supera il numero di essere cercato, si può tornare 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 

E così:

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

Ci sono alcuni altri modi per farlo troppo. Pensa a zip fibs [0..] e poi puoi utilizzare dropWhile per rimuovere la porzione inferiore a n e testare ciò che è rimasto.

+0

grazie mille, funziona perfettamente! – lopezrican304

+0

FYI - ': set + s; lasciare a = 10^25000; invFibMVMark a => "Niente (0,38 secondi, 13927928 byte)"; invFibGroovy a => "Niente (0,18 secondi, 3633660 byte)" ' –

+0

@groovy hai provato entrambi i nuovi (ovvero il tempo per generare la sequenza' fibs')? Il file è stato compilato prima di essere caricato in GHCi? Nei miei test ho visto la versione di MVMark correre più veloce della tua, del 10%. Forse possiamo dire che entrambe le versioni sono * comparabili * nelle loro prestazioni. :) –

1

Se si' Abbiamo già calcolato fibs, quindi la risposta è semplice:

import Data.List 

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

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

che restituisce il tipo Int e ho bisogno del tipo Forse Integer, come posso convertirlo? So per il valore 1 sarebbe l'unico valore che ha due risposte – lopezrican304

+0

Risolto il problema di restituire un 'Integer'. –

+1

Poiché la lista è infinita, 'elemIndex' non funzionerà se si desidera che la cosa termini per i numeri che non si trovano nella sequenza. È necessario approfittare del fatto che l'elenco è ordinato. – hammar

7

Perché non utilizzare una funzione come 'takeWhile' per restituire una sezione dell'elenco infinito 'fibs' che si desidera esaminare? Con la lista finita, è possibile applicare una funzione come "elemIndex" che, con una piccola modifica del tipo, potrebbe restituire ciò che si sta cercando.

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

Questo sembra sbagliato perché in sostanza il lavoro viene eseguito due volte: una volta con 'takeWhile' e una volta con' findIndex'. – MtnViewMark

+1

Solo a prima vista. Ogni elemento è il primo '<=' 'ed e poi '==' ed. Nel tuo codice, ogni elemento è il primo '==' 'ed e tutti tranne l'ultimo è quindi '<'' ed. Quindi il lavoro non viene eseguito due volte e mostra chiaramente come Haskell può essere modulare. –

+0

Vero - in entrambe le versioni, mentre si siedono, due operazioni di confronto vengono applicate a ogni elemento. Nel mio esempio di codice c'è solo un attraversamento esplicito dell'elenco, mentre in questo codice ce ne sono due. Detto questo, è possibile che il compilatore fonderà 'findIndex' e' takeWhile' portando ad un attraversamento di lista. Nel mio codice, si potrebbero sostituire le guardie con 'case compare a x of' che porta a un confronto per elemento. - * Tutto ciò che è stato detto, * il mio commento non riguardava l'efficienza, ma la presentazione dell'algoritmo. Mi sembrava sbagliato perché specifica più lavoro del necessario. – MtnViewMark

Problemi correlati