2009-06-24 3 views
6

Ich lese durch Learn You a Haskell und erreichte eine Stelle, wo ich versuche, ein Element in einer Liste an den Kopf zu bewegen. Ich bin gekommen, mit dem, was ich denke, die naive Art und Weise ist, und ich bin gespannt, ob mir jemand zeigen kann, was die erfahrenen Haskell Programmierer stattdessen tun würden.Wie verschiebt man ein Element in einer Liste in Haskell?

In diesem Beispiel habe ich eine Liste von ganzen Zahlen, und ich möchte das Element bewegen, ‚4‘, der Index ‚3‘, an der Spitze der Liste sein würde.

let nums = [1, 2, 3, 4, 5] 
(nums !! 3) : delete (nums !! 3) nums 

gibt [4, 1, 2, 3, 5] zurück.

Was denkst du?

+3

„Löschen“ löscht das erste Auftreten der gegebenen Elementanpassung verwendet wird, so dass es möglicherweise das falsche Element entfernen, wenn es Duplikate ... – sth

Antwort

15

Ich würde es auf diese Weise tun:

move n as = head ts : (hs ++ tail ts) 
    where (hs, ts) = splitAt n as 

splitAt teilt eine Liste an der Position gegeben, es gibt die beiden Teile, die durch die Spaltung erzeugt werden (hier hs und ts). Das Element, das nach vorne verschoben werden soll, steht nun am Anfang von ts. head ts kehrt nur das erste Element ts, tail ts gibt alles aber, dass das erste Element. Das Ergebnis der Funktion sind nur diese Teile in der richtigen Reihenfolge kombiniert: hs verkettet mit tail ts und vorangestellt von dem Element head ts.

+3

toHead n l = lassen (xs, y: ys) = splitAt n l in y: xs ++ ys – Stephan202

+0

etw: Kannst du es bitte beschreiben, um den Code zu verstehen? – shahkalpesh

0

Was für eine Koinzidenz?
ich die gleiche Sache wieder ein paar Tage zu lesen. Sah es wieder nach oben & schrieb es wie folgt.

nums !! 3 : [x | x <- nums, (x == (num !! 3)) == False] 
+0

Zwei Probleme: Zuerst werden doppelte Elemente entfernt. Zweitens (weniger ein Problem) ist der ungleiche Operator (/ =) im Gegensatz zu ((a == b) == Falsch). –

+0

Guter Fang. Wie Sie sehen können, bin ich ein Anfänger.Danke für die Korrektur :) – shahkalpesh

11

Erfahrene Haskellers so gut wie nie mit Liste Indizierung. Ich würde Pause nutzen, um wiederholte Querungen zu vermeiden (vorausgesetzt, Sie auf Element übereinstimmen soll '4', nicht Index '3'):

case break (== 4) [1, 2, 3, 4, 5] of 
    (a,x:xs) -> x:a ++ xs 
    (a,xs) -> a ++ xs 

Wie in:

Prelude Data.List> case break (== 4) [1, 2, 3, 4, 5] of (a,x:xs) -> x:a ++ xs; (a,xs) -> a ++ xs 
[4,1,2,3,5] 

Wir können das Gleiche tun mit Indizierung über 'splitAt':

Prelude Data.List> case splitAt 3 [1, 2, 3, 4, 5] of (a,x:xs) -> x:a ++ xs; (a,xs) -> a ++ xs 
[4,1,2,3,5] 
+0

Ja, es passt auf Element 4 nicht auf Index '3'. Sorry für die Verwirrung – afrosteve

3

Es gibt auch

toHead n l = l !! n : take n l ++ drop (n+1) l 

, die ein wenig leichter zu folgen als mit splitAt sein kann.

+0

ist das nicht langsamer als die SplitAt-Version? – yairchu

+0

Nicht klar, nachdem der Optimierer damit fertig ist. Lauf mit ghc -O und finde es heraus! –

+0

Würde dies 2 über die Liste gehen? – Daniel

8

kleine Änderung auf Lösung von etw:

toHead n xs = x : pre ++ post 
    where (pre, x:post) = splitAt n xs 

Mustern anstelle von head n tail

+1

Ich denke, das ist die am einfachsten zu verstehende Lösung. Schöne Berührung mit dem Musterabgleich! – Michael