Seite 1 von 1
Merkwürdiges lambda...
Verfasst: Montag 2. Juni 2014, 08:48
von Hyperion
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.
Re: Merkwürdiges lambda...
Verfasst: Montag 2. Juni 2014, 08:55
von Boa
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.
Re: Merkwürdiges lambda...
Verfasst: Montag 2. Juni 2014, 09:00
von Hyperion
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?
Re: Merkwürdiges lambda...
Verfasst: Montag 2. Juni 2014, 09:02
von 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)]
Re: Merkwürdiges lambda...
Verfasst: Montag 2. Juni 2014, 09:11
von Hyperion
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!

Re: Merkwürdiges lambda...
Verfasst: Montag 2. Juni 2014, 20:53
von Hyperion
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))
Re: Merkwürdiges lambda...
Verfasst: Montag 2. Juni 2014, 22:34
von 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

Re: Merkwürdiges lambda...
Verfasst: Montag 2. Juni 2014, 22:41
von Hyperion
Du meinst natürlich mit
DEM Rechner schlechthin

Re: Merkwürdiges lambda...
Verfasst: Dienstag 3. Juni 2014, 01:52
von snafu
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);
}
}
Re: Merkwürdiges lambda...
Verfasst: Dienstag 3. Juni 2014, 12:24
von EyDu
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.
Re: Merkwürdiges lambda...
Verfasst: Dienstag 3. Juni 2014, 14:44
von Boa
@EyDu: Ist das Prolog? Sieht zumindest deklarativ aus.
Re: Merkwürdiges lambda...
Verfasst: Dienstag 3. Juni 2014, 15:09
von Hyperion
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

)
Re: Merkwürdiges lambda...
Verfasst: Dienstag 3. Juni 2014, 21:25
von jerch
Die Aufgabe lässt sich auch schön übers kgV vereinfachen zu: