2009-08-13 11 views
0

Ich mache ein anderes Project Euler Problem, und ich muss herausfinden, wenn das Ergebnis dieser 3 Listen gleich ist (wir sind 40755 als das erste Mal sie gleich sind, muss ich die nächste finden:Vergleichen von 3 Ausgabelisten in Haskell

hexag n = [ n*(2*n-1) | n <- [40755..]] 
penta n = [ n*(3*n-1)/2 | n <- [40755..]] 
trian n = [ n*(n+1)/2 | n <- [40755..]] 

ich habe versucht, in den anderen Listen als Prädikate der ersten Liste hinzufügen, aber das hat nicht funktioniert.

hexag n = [ n*(2*n-1) | n <- [40755..], penta n == n, trian n == n] 

ich stecken bin, wo von hier zu gehen

ich Ich habe versucht, die Funktion und sogar den Kalkül grafisch darzustellen, aber ohne Erfolg, also muss ich auf eine Haskell-Lösung zurückgreifen.

+1

Nicht sicher, wofür das führende n (arg) ist; es wird ignoriert. – jrockway

+0

Doppelte Frage: http://projecteuler.net/index.php?section=problems&id=45 :) – yairchu

Antwort

2
  • Ihre Funktionen sind seltsam. Sie bekommen n und ignorieren es dann?
  • Sie haben auch eine Verwechslung zwischen den Ein- und Ausgängen der Funktion. Die 40755. Sechseckszahl ist 3321899295, nicht 40755.

Wenn Sie wirklich einen Spoiler für das Problem wollen (aber nicht, dass der Punkt verpassen?):

binarySearch :: Integral a => (a -> Bool) -> a -> a -> a 
binarySearch func low high 
    | low == high = low 
    | func mid = search low mid 
    | otherwise = search (mid + 1) high 
    where 
    search = binarySearch func 
    mid = (low+high) `div` 2 

infiniteBinarySearch :: Integral a => (a -> Bool) -> a 
infiniteBinarySearch func = 
    binarySearch func ((lim+1) `div` 2) lim 
    where 
    lim = head . filter func . lims $ 0 
    lims x = x:lims (2*x+1) 

inIncreasingSerie :: (Ord a, Integral i) => (i -> a) -> a -> Bool 
inIncreasingSerie func val = 
    val == func (infiniteBinarySearch ((>= val) . func)) 

figureNum :: Integer -> Integer -> Integer 
figureNum shape index = (index*((shape-2)*index+4-shape)) `div` 2 

main :: IO() 
main = 
    print . head . filter r $ map (figureNum 6) [144..] 
    where 
    r x = inIncreasingSerie (figureNum 5) x && inIncreasingSerie (figureNum 3) x 
+0

Denken Sie daran, ich lerne immer noch Haskell .... Die Art, wie ich dachte, um dieses Problem zu lösen, ist nur zu berechnen die Zahlen und zeigen dann nur die Ergebnisse an, wenn die resultierenden Zahlen alle gleich sind. Ich habe noch nichts über Monaden oder das gelernt. –

+0

@Jonno_FTW: cool. Beachten Sie, dass hier keine Monaden verwendet werden, außer in "main". – yairchu

0

Es gibt mindestens ein paar Möglichkeiten, wie Sie das tun können.

Sie auf das erste Element aussehen könnte, und vergleichen Sie den Rest der Elemente, um es:

Prelude> (\x -> all (== (head x)) $ tail x) [ [1,2,3], [1,2,3], [4,5,6] ] 
False 
Prelude> (\x -> all (== (head x)) $ tail x) [ [1,2,3], [1,2,3], [1,2,3] ] 
True 

Oder Sie könnten eine explizit rekursive Funktion ähnlich der vorherigen machen:

-- test.hs 
f [] = True 
f (x:xs) = f' x xs where 
    f' orig (y:ys) = if orig == y then f' orig ys else False 
    f' _ [] = True 


Prelude> :l test.hs 
[1 of 1] Compiling Main    (test.hs, interpreted) 
Ok, modules loaded: Main. 
*Main> f [ [1,2,3], [1,2,3], [1,2,3] ] 
True 
*Main> f [ [1,2,3], [1,2,3], [4,5,6] ] 
False 

Sie könnte auch einen TakeWhile machen und die Länge der zurückgegebenen Liste vergleichen, aber das wäre weder effizient noch typisch Haskell.


Hoppla, gerade gesehen, dass Ihre Frage überhaupt nicht beantwortet hat. Markieren Sie dies als CW für den Fall, dass jemand auf Ihre Frage über Google stolpert.

1

Hier ist eine einfache, direkte Antwort genau die Frage, die Sie haben:

*Main> take 1 $ filter (\(x,y,z) -> (x == y) && (y == z)) $ zip3 [1,2,3] [4,2,6] [8,2,9] 
[(2,2,2)] 

natürlich Antwort des yairchu könnte sinnvoller sein, in tatsächlich die Euler Frage zu lösen :)

0

Der einfachste Weg ist Ihr Problem leicht mit drei Listen (man beachte die Entfernung des überflüssigen n Argument)

Anstatt sich zu neu angeben:

hexag = [ n*(2*n-1) | n <- [40755..]] 
penta = [ n*(3*n-1)/2 | n <- [40755..]] 
trian = [ n*(n+1)/2 | n <- [40755..]] 

könnte Sie zum Beispiel eine Liste erzeugen:

matches :: [Int] 
matches = matches' 40755 


matches' :: Int -> [Int] 
matches' n 
    | hex == pen && pen == tri = n : matches (n + 1) 
    | otherwise    =  matches (n + 1) where 
    hex = n*(2*n-1) 
    pen = n*(3*n-1)/2 
    tri = n*(n+1)/2 

Jetzt könnten Sie versuchen, dies für die Leistung zu optimieren, indem Sie Wiederholungen bemerken. Zum Beispiel bei der Berechnung im nächsten Spiel bei (n + 1):

(n+1)*(n+2)/2 - n*(n+1)/2 = n + 1 

so konnte man nur hinzufügen (n + 1) zum vorherigen tri den neuen Tri-Wert zu erhalten.

Ähnliche algebraische Vereinfachungen können auf die anderen beiden Funktionen angewendet werden, und Sie können alle von ihnen in akkumulierenden Parameter auf die Funktion passen '.

Das gesagt, gibt es effizientere Möglichkeiten, dieses Problem anzugehen.