2009-06-24 9 views
6

Je suis en train de lire Learn You a Haskell et j'ai atteint un point où j'essaie de déplacer un élément dans une liste vers la tête. Je suis venu avec ce que je pense est la manière naïve et je suis curieux de savoir si quelqu'un peut me montrer ce que le programmeur expérimenté Haskell ferait à la place.Comment déplacer un élément dans une liste dans Haskell?

Dans cet exemple, j'ai une liste d'entiers et je veux déplacer l'élément '4', qui serait l'index '3', en tête de la liste.

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

renvoie [4, 1, 2, 3, 5].

Qu'en pensez-vous?

+3

« supprimer » supprime la première occurrence de l'élément donné, il peut enlever le mauvais élément le cas duplicates ... – sth

Répondre

15

je le ferais de cette façon:

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

splitAt divise une liste à la position donnée, il renvoie les deux parties qui sont créées par la division (ici hs et ts). L'élément qui doit être déplacé vers l'avant est maintenant au début de ts. head ts retourne juste ce premier élément de ts, tail ts renvoie tout mais ce premier élément. Le résultat de la fonction sont juste ces parties combinées dans le bon ordre: hs concaténé avec tail ts et ajouté par l'élément head ts.

+3

toHead n l = let (xs, y: ys) = splitAt n l dans y: xs ++ ys – Stephan202

+0

sth: Pourriez-vous le décrire s'il vous plaît pour comprendre le code? – shahkalpesh

0

Quelle co-incidence?
Je lisais la même chose il y a quelques jours. A regardé à nouveau & l'a écrit comme suit.

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

Deux problèmes: Tout d'abord, les éléments en double sont supprimés. Deuxième (moins d'un problème), l'opérateur non égal est (/ =), par opposition à ((a == b) == Faux). –

+0

Bonne prise. Comme vous pouvez le voir, je suis un débutant.Merci de corriger :) – shahkalpesh

11

Les Haskellers expérimentés utilisent rarement l'indexation de liste. J'utilise pause pour éviter traversals répétées (en supposant que vous voulez faire correspondre à l'élément « 4 », et non l'indice « 3 »):

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

Comme dans:

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] 

Nous pouvons faire la même chose avec l'indexation via '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

Oui, cela correspond à l'élément 4 pas à l'index '3'. Désolé pour la confusion – afrosteve

3

Il y a aussi

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

qui peut être un peu plus facile à suivre que d'utiliser splitAt.

+0

n'est-ce pas plus lent que la version splitAt? – yairchu

+0

Pas clair après l'optimisation de l'optimiseur. Courir avec ghc -O et découvrir! –

+0

Est-ce que cela ferait 2 passages sur la liste? – Daniel

8

petite modification sur la solution de STH:

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

aide d'un patron au lieu de head n tail

+1

Je pense que c'est la solution la plus facile à comprendre. Bon contact avec le motif correspondant! – Michael

Questions connexes