Merkwürdiges lambda...

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

Hallo,

ursprünglich ging es um eine Hausaufgabe der 5. Klasse, für die folgendes gilt:

Code: Alles auswählen

x % 2 = 1
x % 3 = 2
x % 4 = 3
x % 5 = 4
x % 6 = 6
x % 7 = 0

mit 1 <= x < 1000
Logisch, statt mit Denken löst man das schnell in Python per Brute-Force ;-)

Nun war mein Ansatz folgender:

Code: Alles auswählen

funcs = [lambda x: x % n == n-1 for n in range(2, 7)]

funcs.append(lambda x: x % 7 == 0)

for i in range(1, 1001):
    if all(f(i) for f in funcs):
        print(i)

> 35 77 119 161 203 245 287 329 371 413 455 497 539 581 623 665 707 749 791 833 875 917 959
Klappt leider nicht! :-( (die gesuchte Lösung ist [119, 539, 959])

Wenn ich die Lambdas "zu Fuß" generiere, funktioniert die Berechnung.

Offenbar ist das innere ``n`` bei den in der List-Comprehension generierten Lambda-Funktionen bei allen gleich der ``6``. Dies kann man mittels Ausgabe aller Lambda-Ergebnisse ohne das manuelle letzte leicht herausfinden.

Jetzt meine Frage: Wieso?

Ein kurzes googlen ergab, dass ich nicht der erste bin, der das sonderbar findet. Leider ist mir aktuell vollkommen unklar, wieso das nicht funktioniert!

Edit: Ich habe dafür ein Python 3.3.3 benutzt - falls das eine Rolle spiele sollte.
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
Boa
User
Beiträge: 190
Registriert: Sonntag 25. Januar 2009, 12:34

Eine Zeile scheint falsch zu sein:
x % 6 = 5
Und probiere es vielleicht Mal mit Klammern um die Modulo Ausdrücke; Es kann sein, dass die ziemlich spät kommen in der Operator rang liste.
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

Boa hat geschrieben:Eine Zeile scheint falsch zu sein:
x % 6 = 5
Ooops, stimmt :-)
Boa hat geschrieben: Und probiere es vielleicht Mal mit Klammern um die Modulo Ausdrücke; Es kann sein, dass die ziemlich spät kommen in der Operator rang liste.
Wo genau meinst Du denn, sollte man Klammern setzen?
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
BlackJack

@Hyperion: Ist doch ein Klassiker. Das `n` wird beim *Aufruf* der ``lambda``-Funktion aufgelöst, und nicht beim *Erstellen*. Und wenn die Funktion aufgerufen wird, hat `n` den Wert des letzten Schleifendurchlaufs. Die LC und das ``lambda`` sind ja letztendlich nur Kurzschreibweisen für das hier:

Code: Alles auswählen

def create_funcs():
    result = list()
    for n in range(2, 7):
        def f(x):
            return x % n == n - 1
        result.append(f)
    return result
Wäre Dir hier klar warum `n` bei Aufrufen von `f` immer zu 6 aufgelöst wird?

Lösungen: Default-Werte, weil die ausgewertet werden wenn die Funktion *erstellt* wird und nicht wenn sie *aufgerufen* wird, oder `functools.partial()`:

Code: Alles auswählen

funcs = [lambda x, n=n: x % n == n - 1 for n in range(2, 7)]
# oder
funcs = [partial((lambda n, x: x % n == n - 1), n) for n in range(2, 7)]
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

BlackJack hat geschrieben: Wäre Dir hier klar warum `n` bei Aufrufen von `f` immer zu 6 aufgelöst wird?
Ja, danke. Damit ist der Groschen gefallen! :-)
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

Hier mal eine Lösung in Clojure - sieht fast aus wie die Lösung in Python :-)

Code: Alles auswählen

(defn make-func [x] 
  (partial #(= (mod %2 %1) (- %1 1)) x))

(defn make-funcs []
  (cons 
    #(zero? (mod % 7)) 
    (map make-func (range 2 7))))

(filter (apply every-pred (make-funcs)) (range 1 1001))
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
BlackJack

Wenn ich so eine Hausaufgabe mit dem Rechner hätte lösen wollen, würde das wohl so aussehen:

Code: Alles auswählen

   10 DIM A(5),B(5):FOR I=2 TO 7:A(I-2)=I:B(I-2)=I-1:NEXT:B(5)=0
   20 FOR X=1 TO 999:FOR I=0 TO 5:C=X-INT(X/A(I))*A(I)=B(I):IF NOT C THEN I=5
   30 NEXT:IF C THEN PRINT X,
   40 NEXT
:-)
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

Du meinst natürlich mit DEM Rechner schlechthin 8)
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
Benutzeravatar
snafu
User
Beiträge: 6731
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Java 8 mit der Stream-API:

Code: Alles auswählen

import java.util.stream.IntStream;

public class FunctionalExperiments {
    public static void main(String[] args) {
        IntStream.rangeClosed(1, 1000).filter(x -> 
            IntStream.rangeClosed(2, 6).allMatch(n -> 
                x % n == n - 1
            )
            && x % 7 == 0
        ).forEach(System.out::println);
    }
}
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

Warum selber nachdenken:

Code: Alles auswählen

rule(X) :-
    between(1, 999, X),
    X mod 2 =:= 1,
    X mod 3 =:= 2,
    X mod 4 =:= 3,
    X mod 5 =:= 4,
    X mod 6 =:= 5,
    X mod 7 =:= 0.
Das Leben ist wie ein Tennisball.
Boa
User
Beiträge: 190
Registriert: Sonntag 25. Januar 2009, 12:34

@EyDu: Ist das Prolog? Sieht zumindest deklarativ aus.
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

Boa hat geschrieben:@EyDu: Ist das Prolog? Sieht zumindest deklarativ aus.
Japp, ist es. Hätte ich ja eigentlich von pillmuncher erwartet ;-)

(Wenn Du auf "Zitieren" eines Beitrags gehst, siehst Du übrigens auch die Angabe in der Syntax-Deklaration ;-) - ok, die könnte natürlich auch lügen :mrgreen: )
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
jerch
User
Beiträge: 1669
Registriert: Mittwoch 4. März 2009, 14:19

Die Aufgabe lässt sich auch schön übers kgV vereinfachen zu:

Code: Alles auswählen

f = lambda x: (60*x + 17) * 7
Antworten