2016-05-10 6 views
1

Ich möchte eine Liste überlisten, aber den Elementindex in der Liste verfolgen.Python enumerate() analog in Common Lisp

In Python ich etwas entlang der Linien von tun können:

(mapcar-something (lambda (elt idx) (format nil "Elt ~D: ~S" idx elt)) 
        '(a b c d)) 

Erwartetes Ergebnis:

("Elt 0: A" "Elt 1: B" "Elt 2: C" "Elt 3: D") 

map(lambda (idx, elt): "Elt {0}: {1}".format(idx, elt), enumerate(mylist)) 

ich es etwas entlang der Linien von zu übersetzen versuchte,

Aber ich kann die mapcar-something Funktion nicht finden, die ich verwenden sollte. Muss ich das selbst implementieren (via Schleife, vielleicht)?

+0

Sie können wickeln Sie es in einem 'let' Block und erfassen ein n Index-Variable aus dem Lambda, dann inkrementieren, dass jedes Mal das Lambda aufgerufen wird. Ich glaube nicht, dass da ein eingebauter ist. – MicroVirus

Antwort

0

Common Lisp LOOP Makro automatisch halten können Spur des Indexes.

(loop for elt in '(a b c d) and idx from 0 
     collect (operation-on idx elt)) 

LOOP automatisch erhöht um 1 eine Variable mit from initialisiert; und wenn sie von and eingeführt werden, dann passieren beide Zuordnungen (das Element des Arrays und des Index) auf einmal, nicht verschachtelt.

So eine enumerate Funktion entlang der Linien würde:

(defun enumerate (list &optional (first-index 0)) 
    (loop for elt in list and idx from first-index 
    collect (cons idx elt))) 

In der Ausdruckskraft von Common Lisp, wäre es vielleicht sinnvoll sein, einen Makro entlang der Linien zu definieren:

(defmacro with-enumerated-list ((list elt idx &key (first-index 0)) &body body) 
    `(loop for ,elt in ,list and ,idx from ,first-index 
    collect (progn ,@body))) 

in diesem Fall könnte die enumerate-Funktion reduziert werden:

(defun enumerate (list &optional (first-index 0)) 
    (with-enumerated-list (list elt idx :first-index first-index) 
    (cons idx elt))) 
+0

Typisches Problem: Sie haben Ihren eigenen Code nicht ausprobiert. ** Die zweite ENUMERATE-Funktion funktioniert nicht. ** Es ist kein Makro erforderlich, die Oberfläche Ihres Makros ist hässlich, es wird keine Fehlerprüfung durchgeführt und es bietet keinen zusätzlichen Wert gegenüber dem einfachen LOOP. Schlimmer noch: Die Art, wie Sie den Körper definieren, eröffnet viele Probleme (können Sie sehen, warum)? Durch die Einführung des Makros haben Sie einen Bug und eine weitere Quelle für zufällige Fehler eingeführt ... –

+0

@RainerJoswig ist es eine so schlechte Antwort, dass es mehr wert ist, zu downvoten als zu versuchen, es zu verbessern? Ich habe meinen eigenen Code versucht, aber es scheint, ich habe eine schlechte Iteration davon kopiert. Der Wert, den es bietet, ist das sprachspezifische Idiom, was wohl nicht viel bedeuten mag. Wenn Sie darüber nachdenken, warum das Makro hässlich ist, hängt es von der mangelnden Hygiene ab, das kann sowohl gut als auch schlecht sein.Warum ist deine Meinung so stark negativ? – ssice

+0

Die LOOP-Syntax leckt in die WITH-ENUMERATED-LIST. Siehst du das? Wenn nicht, werde ich Ihnen in meinem nächsten Kommentar zeigen, wie das geht. –

6
CL-USER 25 > (defun iota (n) 
       (loop for i below n collect i)) 
IOTA 

CL-USER 26 > (iota 4) 
(0 1 2 3) 

CL-USER 27 > (mapcar (lambda (elt idx) 
         (format nil "Elt ~D: ~S" idx elt)) 
        '(a b c d) 
        (iota 4)) 
("Elt 0: A" "Elt 1: B" "Elt 2: C" "Elt 3: D") 

oder

CL-USER 28 > (loop for elt in '(a b c d) and idx from 0 
        collect (format nil "Elt ~D: ~S" idx elt)) 
("Elt 0: A" "Elt 1: B" "Elt 2: C" "Elt 3: D") 
+0

Ich hatte keine Ahnung, dass 'und idx von 0 'automatisch idx jedes Mal um eins erhöht. – ssice

0

Wenn Sie wollen etwas, das wie Ihr ursprüngliches Beispiel aussieht:

(defun enumerate (function list) 
    (let ((idx 0)) 
    (loop for elt in list 
     collect (funcall function elt idx) 
     do (incf idx)))) 

Ihr Beispiel:

(enumerate (lambda (elt idx) (format nil "Elt ~D: ~S" idx elt)) 
      '(a b c d)) 
=> ("Elt 0: A" "Elt 1: B" "Elt 2: C" "Elt 3: D") 
+0

Es ist in Ordnung, aber das zweite Codebeispiel von Rainer verbessert Ihr, indem es das inkf zur Schleifenimplementierung behandelt und es so vor dem Programmierer versteckt, der näher an der Verwendung in Python ist. – ssice