Schleifen gegeneinander ersetzbar?
jens87
- programmiertechnik
Hallo liebe Forianer,
es ist zwar nicht unbedingt eine direkte Frage zur Webentwicklung, aber da sich hier auch die einen oder anderen Programmierer tummeln, möchte ich es mal kurz versuchen:
In einem VisualBasic-Code habe steht folgendes Schleifenkonstrukt:
Do While var_1 > 2
%% ... %%
Do
%% ... %%
Loop Until var_3 + var_4 < 12
Loop
Dieses muss ich nun in eine sehr rudimentäre Umgebung "portieren", in der mir [neben den "klassischen" if-else-Bedingungen] nur For- bzw. While-Schleifen zur Verfügung stehen.
Die "Do-While"-Schleife aus VB entspricht dabei ja der While-Schleife aus der Umgebung; anders aber kann ich mir gerade keinen Reim darauf machen, wie ich denn dieses "Loop Until" "transformieren" kann.
Hat hier jemand einen Tipp für mich Übrig? Ich wäre darüber sehr dankbar!
LG
jens87
Hallo,
Dieses muss ich nun in eine sehr rudimentäre Umgebung "portieren", in der mir [neben den "klassischen" if-else-Bedingungen] nur For- bzw. While-Schleifen zur Verfügung stehen.
mehr braucht man auch nicht. ;-)
Und selbst diese beiden kann man gegeneinander austauschen, wenn auch nicht immer elegant.
Die "Do-While"-Schleife aus VB entspricht dabei ja der While-Schleife aus der Umgebung; anders aber kann ich mir gerade keinen Reim darauf machen, wie ich denn dieses "Loop Until" "transformieren" kann.
Hat hier jemand einen Tipp für mich Übrig? Ich wäre darüber sehr dankbar!
Es gibt zwei relevante Punkte:
a) Wann/wo wird die Schleifenbedingung überprüft?
Am Anfang oder am Ende des Schleifenrumpfes?
Am Ende hat's die Nebenwirkung, dass der Schleifenrumpf immer mindestens einmal ausgeführt
wird, selbst wenn die Bedingung von Anfang an nicht erfüllt ist.
b) Ist die Bedingung positiv oder negativ formuliert?
Positiv: Die Schleife läuft, solange die Bedingung erfüllt ist (while)
Negativ: Die Schleife läuft, solange die Bedingung nicht erfüllt ist (until)
Mit diesen beiden Überlegungen kannst du leicht Schleifenkonstruktionen ineinander überführen.
Übrigens kennt auch C die Varianten while() { ... } und do { ... } while(), wobei letztere eher selten verwendet wird.
Ciao,
Martin
@@Der Martin:
nuqneH
Übrigens kennt auch C die Varianten while() { ... } und do { ... } while()
JavaScript und PHP übrigens auch.
Qapla'
Hakuna matata!
Übrigens kennt auch C die Varianten while() { ... } und do { ... } while()
JavaScript und PHP übrigens auch.
JavaScript und PHP haben auch native Map/Reduce-Funktionen, das macht hoffentlich jeden Einsatz von Schleifen überflüssig.
Tach!
JavaScript und PHP haben auch native Map/Reduce-Funktionen, das macht hoffentlich jeden Einsatz von Schleifen überflüssig.
Nein, denn diese Funktionen können nur über vorgegebene Arrays iterieren. Schleifen, deren Endebedingung erst in einem der Durchläufe ermittelt werden kann, sind nicht durch map/reduce ersetzbar.
dedlfix.
Hakuna matata!
JavaScript und PHP haben auch native Map/Reduce-Funktionen, das macht hoffentlich jeden Einsatz von Schleifen überflüssig.
Nein, denn diese Funktionen können nur über vorgegebene Arrays iterieren. Schleifen, deren Endebedingung erst in einem der Durchläufe ermittelt werden kann, sind nicht durch map/reduce ersetzbar.
Ich hab mich bewusst provokant ausgedrückt, natürlich ist Map/Reduce alleine nicht funktional vollständig und man kann damit nicht jeden Algorithmus lösen. In der Praxis lassen sich aber gefühlte 99% aller Iterations-Probleme mit Map/Reduce (Filter und .co zähle ich auch dazu) sehr viel eleganter modellieren als mit Schleifen. Für das restliche 1% und die von dir angesprochene Problemgruppe bräuchte man unendlichle Datenstrukturen, ein ReduceRight und Lazy-Evaluation aka. call-by-need. Zumindest in JavaScript kann man sich das auch nachrüsten, siehe: Lazy.js
Tach!
Ich hab mich bewusst provokant ausgedrückt, natürlich ist Map/Reduce alleine nicht funktional vollständig und man kann damit nicht jeden Algorithmus lösen. In der Praxis lassen sich aber gefühlte 99% aller Iterations-Probleme mit Map/Reduce (Filter und .co zähle ich auch dazu) sehr viel eleganter modellieren als mit Schleifen.
Wenn das Resultat wieder ein Array oder ein einzelner Wert sein soll, dann ist map oder reduce in der Tat ein Schleifenablöser. Das sind aber garantiert nicht 99% aller Fälle. Es gibt noch genügend Fälle, für die man ein foreach braucht, das einfach nur etwas mit den Elementen macht (zum Beispiel ausgeben), ohne dass man als Resultat ein weiteres Array erzeugt. Dafür map() einzusetzen wäre eine nicht intentionsgemäße Verwendung.
dedlfix.
Hakuna matata!
Es gibt noch genügend Fälle, für die man ein foreach braucht, das einfach nur etwas mit den Elementen macht (zum Beispiel ausgeben), ohne dass man als Resultat ein weiteres Array erzeugt. Dafür map() einzusetzen wäre eine nicht intentionsgemäße Verwendung.
Auch wenn man nur Seiteneffekte auslösen möchte, würde ich nicht zur foreach
-Schleife (PHP) oder zur for-of-Schleife (ES6) greifen:
foreach ( $array as $value ) {
var_dump( $value );
}
for ( value of array ) {
console.log( value );
}
Sondern zum kopflosen Bruder array_walk()
(PHP) bzw. [].forEach()
(JavaScript):
array_walk( $array, 'var_dump');
array.forEach( console.log );
Tach!
Auch wenn man nur Seiteneffekte auslösen möchte, würde ich nicht zur
foreach
-Schleife (PHP) oder zur for-of-Schleife (ES6) greifen:
(Die Dinger heißen auf deutsch Nebenwirkungen oder Nebeneffekte. Seiteneffekte sind eine falsche 1:1-Übertragung des englischen side effects.)
Das Javascript-forEach() hatte ich im Sinn. Du meintest vermutlich nicht 99% map/reduce sondern 99% funktionale Herangehenswiese, egal welche Funktionen dabei konkret zum Einsatz kommen. Da bin ich dann auch einigermaßen bei dir.
Sondern zum kopflosen Bruder
array_walk()
(PHP) bzw.[].forEach()
(JavaScript):
array_walk( $array, 'var_dump');
var_dump($array);
Mach es nicht umständlicher als es notwendig ist, auch wenn es nur ein schnell ausgedachtes Beispiel ist. Zudem ist 'var_dump' stringly-typed (kein Tippfehler). Du wolltest doch ordentliches Programmieren propagieren. Um beim Beispiel zu bleiben:
array_walk($array, function ($element) {
var_dump($element);
});
Syntax gehört ausgeschrieben und nicht in Strings versteckt.
Wo ist nun aber bei PHP der Vorteil von array_walk() gegenüber foreach? - Außer dass man zur Laufzeit entscheiden kann, was man als auszuführende Funktion übergeben möchte, was ein wohl eher seltener Anwendungsfall sein dürfte, sehe ich ihn noch nicht wirklich. Es ist erstmal nur anders. (Benchmark-Vergleiche interessieren mich auch nicht, die Unterschiede gehen bei den üblichen Datenmengen im Grundrauschen auf.)
dedlfix.
Hakuna matata!
(Die Dinger heißen auf deutsch Nebenwirkungen oder Nebeneffekte. Seiteneffekte sind eine falsche 1:1-Übertragung des englischen side effects.)
Ah, das klingt in meinen Ohren auch gleich viel besser.
Das Javascript-forEach() hatte ich im Sinn. Du meintest vermutlich nicht 99% map/reduce sondern 99% funktionale Herangehenswiese, egal welche Funktionen dabei konkret zum Einsatz kommen. Da bin ich dann auch einigermaßen bei dir.
Ja, das meine ich. Es fällt mir einigermaßen schwer .forEach() als funktional zu bezeichnen, es ist immerhin eine Prozedur. Aber zu Map/Reduce gehört sie auch nicht wirklich. Zumindest ist jetzt geklärt, worauf ich hinaus möchte.
Zudem ist 'var_dump' stringly-typed (kein Tippfehler). Du wolltest doch ordentliches Programmieren propagieren. Um beim Beispiel zu bleiben:
array_walk($array, function ($element) {
var_dump($element);
});
>
> Syntax gehört ausgeschrieben und nicht in Strings versteckt.
Das ist eine Sünde von PHP. In besseren Programmiersprachen sind Funktionen über ihre Bezeichner referenzierbar. Dann muss man nicht auf Strings ausweichen und muss auch keinen Closure drumherum stricken.
> Wo ist nun aber bei PHP der Vorteil von array\_walk() gegenüber foreach?
Bei array\_walk() weiß ich sofort, dass das Array iteriert wird, um die Nebenwirkungen der Callback-Funktion auszulösen. Das kann ich festellen selbst ohne einen Blick in die Callback-Funktion zu werfen. Wenn ich mir dagegen nur den Schleifenkopf einer foreach-Schleife anschaue, dann kann ich nicht sagen, ob die Schleife für Nebenwirkungen, Zuordnungen oder zum Aggregrieren gebraucht wird. Um das sagen zu können, muss ich erst einen Blick auf den Körper der Schleife werfen. Deshalb finde array\_walk() expressiver als die foreach-Schleife.
Zum anderen passt array\_walk() besser zu meinem Programmierstil und hilft mir dabei konsistenteren Code zu schreiben, das ist eher ein persönliches Argument, aber jeder Programmierer sollte darum bemüht sein konsistenten Code zu schreiben.
> (Benchmark-Vergleiche interessieren mich auch nicht, die Unterschiede gehen bei den üblichen Datenmengen im Grundrauschen auf.)
Benchmarks interessieren mich auch nicht, im Übrigen glaube ich, dass array\_walk() schlechter abschneiden dürfte als die for-Schleife.
--
“All right, then, I'll go to hell.” – Huck Finn
Hallo!
Es gibt zwei relevante Punkte:
a) Wann/wo wird die Schleifenbedingung überprüft?
Am Anfang oder am Ende des Schleifenrumpfes?
Am Ende hat's die Nebenwirkung, dass der Schleifenrumpf immer mindestens einmal ausgeführt
wird, selbst wenn die Bedingung von Anfang an nicht erfüllt ist.
b) Ist die Bedingung positiv oder negativ formuliert?
Positiv: Die Schleife läuft, solange die Bedingung erfüllt ist (while)
Negativ: Die Schleife läuft, solange die Bedingung nicht erfüllt ist (until)Mit diesen beiden Überlegungen kannst du leicht Schleifenkonstruktionen ineinander überführen.
Mh, je länger ich darüber nachdenke, um so schwieriger gestaltet es sich. - Wenn ich bei mir diese until-Schleife habe, dann heißt die doch übersetzt: "Führe den Code darinnen solange aus, solange das Kriterium kleiner Als 1e-12 bleibt, also NICHT größer als 1e-12 ist"
Aber irgendwie habe ich hier ein Brett vor dem Kopf, um das auf die [kopfgesteuerte] Syntax der While-Schleife umzumünzen ...
Liebe Grüße,
jens87
hi,
Mh, je länger ich darüber nachdenke, um so schwieriger gestaltet es sich. - Wenn ich bei mir diese until-Schleife habe, dann heißt die doch übersetzt: "Führe den Code darinnen solange aus, solange das Kriterium kleiner Als 1e-12 bleibt, also NICHT größer als 1e-12 ist"
Bis das Kriterium..., until heißt bis...
;)
my $i = 0;
say ++$i while($i < 10);
# solange $i kleiner 10
$i = 0;
say ++$i until($i == 10);
# bis $i gleich 10
my $i = 0;
say ++$i while($i < 10);
# solange $i kleiner 10$i = 0;
say ++$i until($i == 10);
# bis $i gleich 10
naja ... so wär's ja einfach.
Das Problem ist, dass ich nur das Konstrukt einer Kopfgesteuerten while-Schleife zur Verfügung habe und nicht weiß, wie ich damit ein "do ... until( x < 1e-12 )" ersetzen kann. - da liegt der Hase im Pfeffer.
jens87
Hallo,
Das Problem ist, dass ich nur das Konstrukt einer Kopfgesteuerten while-Schleife zur Verfügung habe und nicht weiß, wie ich damit ein "do ... until( x < 1e-12 )" ersetzen kann. - da liegt der Hase im Pfeffer.
was hast du gegen ein "while (x > 1e-12)"?
Gruß
Kalk
Hallo,
Das Problem ist, dass ich nur das Konstrukt einer Kopfgesteuerten while-Schleife zur Verfügung habe und nicht weiß, wie ich damit ein "do ... until( x < 1e-12 )" ersetzen kann. - da liegt der Hase im Pfeffer.
was hast du gegen ein "while (x > 1e-12)"?
Gruß
Kalk
Das Problem ist, dass x zunächst "0" ist. Bei einem while(x > 1e-12) würde die Schleife nie gestartet werden, da das Kriterium nicht erfüllt wird.
Bei einem do ... until( x < 1e-12) hingegen zumindest 1x ... - und auf dieses eine Mal kommts hier an.
Lg
jens
Hallo,
Das Problem ist, dass x zunächst "0" ist.
Und? Daran kannst du nix ändern?
Gruß
Kalk
@@jens87:
nuqneH
Das Problem ist, dass ich nur das Konstrukt einer Kopfgesteuerten while-Schleife zur Verfügung habe und nicht weiß, wie ich damit ein "do ... until( x < 1e-12 )" ersetzen kann. - da liegt der Hase im Pfeffer.
Den Unterschied zwischen until und while hat Der Martin doch schon hinreichend erläutert, oder?
Dass DO-WHILE-Schleifen im Gegensatz zu WHILE-Schleifen mindestens einmal durchlaufen werden, wurde in diesem Thread auch schon mindestens einmal gesagt.
DO
{
action;
}
WHILE condition
wäre dasselbe wie
action;
WHILE condition
{
action;
}
Qapla'
hi Jens,
Das Problem ist, dass ich nur das Konstrukt einer Kopfgesteuerten while-Schleife zur Verfügung habe und nicht weiß, wie ich damit ein "do ... until( x < 1e-12 )" ersetzen kann. - da liegt der Hase im Pfeffer.
Erinnern wir uns mal an das, was wir mal gelernt haben:
Eine kopfgesteuerte Schleife nehmen wir immer dann, wenn die Anzahl der Schleifendurchläufe von vornherein feststeht (einschließlich der Abbruchbedingung).
Eine kopfgesteuerte Schleife nehmen wir nicht, wenn wir von vornherein wissen, dass wir mindestens einen Schleifendurchlauf brauchen.
Krasses Beispiel: DB-Verbindung ist weg, wir brauchen mindestens einen Schleifendurchlauf wo im Schleifenkörper versucht wird, die Verbindung wieder herzustellen.
do { ACTION } until (CONNECTION = TRUE);
Ergo: Wir können hier gar keine kofgesteuerte Schleife nehmen, weil ACTION nie ausgeführt wird. Von daher werden kopfgesteuerte Schleifen auch als abweisend bezeichnet.
Schöne Grüße.
hi,
Mh, je länger ich darüber nachdenke, um so schwieriger gestaltet es sich. - Wenn ich bei mir diese until-Schleife habe, dann heißt die doch übersetzt: "Führe den Code darinnen solange aus, solange das Kriterium kleiner Als 1e-12 bleibt, also NICHT größer als 1e-12 ist"
Bis das Kriterium..., until heißt bis...
;)
Ah. ... Hmm. ... Ich komm trotzdem nicht dahinter; ich kann mir kein Äquivalent für "mach das BIS etwas kleiner als etwas ist", denn "solange es nicht größer ist" ist es nicht wirklich und die Schleife zumindest 1x durchlaufen werden muss. Abgesehen davon gibt es ja keine Negationen von "größer als" oder "kleiner als" ...
jens87