Zwei Variablenwerte tauschen
Gestern bin ich auf eine interessante Aufgabe gestossen. Eigentlich war es ein sehr einfacher Test bei einem Bewerbungsgespräch an einen Software-Entwickler-Kandidaten. Die Aufgabe lautete:
„Du hast 2 Variablen mit 2 Werten belegt. Tausche die beiden Werte schnell und effektiv aus.“
Die Erwartung war: Wenn der Kandidat nicht sofort anfängt, eine temporäre dritte Variable zu erstellen, hat er sehr wenig Programmiererfahrung.
$a = 5; $b = 13; $c = $a; $a = $b; $b = $c;
Doch wenn man genauer überlegt, gibt es viele weitere Lösungen, um die Aufgabe zu bewältigen, auch ohne eine dritte Variable. Hier ein paar schöne Lösungen:
$a = 5; $b = 13; $a += $b; $b = $a - $b; $a -= $b;
Bei dem obigen Beispiel gab es eine kleine Diskussion, ob ein Integer-Overflow Probleme machen könnte, dem ist aber nicht so.
$a = 5; $b = 13; $a ^= $b; $b ^= $a; $a ^= $b;
Tricky, aber funktioniert: mit der XOR Funktion klappt es wunderbar. Achtung: Hier wir das bitweise XOR verwendet, nicht das logische XOR.
Aber aufgepasst: Die obigen zwei Lösungen funktionieren nur mit ganzzahligen Werten! Stünden in den Variablen Strings, Objekte, Arrays oder sonstwas drin, würden die Lösungen scheitern. Und streng genommen ist in der Aufgabenstellung nirgends von Zahlen die Rede.
Hier noch ein Beispiel, das mit nur einer Zeile auskommt und jegliche Werte tauschen kann:
$a = 5; $b = 13; list($a, $b) = array($b, $a);
—————-
Edit:
Lösung von Tyco aus den Kommentaren:
$a = 5; $b = 13; $b = $b + $a – ($a = $b);
—————-
Es gibt also auch Lösungen, die ohne eine temporäre dritte Variable auskommen. Von der Lesbarkeit und Wartbarkeit sind die erste und die vierte Lösung wohl auch vorn.
Wer kann noch weitere schöne Lösungen beisteuern?
Ich finde die List-Lösung am Schönsten, auch wenn der Klassiker mit Temporärer Variable natürlich der in jedem Informatik-Grundkurs propagierte ist, da er Sprachunabhängig ist.
Eventuell noch folgende besser lesbare Variante deiner Nummer 4:
function tausche(&$a, &$b){
list($a, $b) = array($b, $a);
}
Bastian
14 Jan 10 at 09:15
$a = 7;
$b = 11;
$b = $b + $a – ($a = $b);
Tyco
14 Jan 10 at 09:27
@Bastian: Das gilt für alle Lösungen, dass man sie natürlich in eine Funktion packen kann bzw. sollte.
@Tyco: Schöne Lösung, noch ein Einzeiler!
Michael Kliewe
14 Jan 10 at 10:22
1 $a = 5;
2 $b = 13;
3 $c = array($b, $a);
4 $a = 6;
Bin grad zu faul zu testen: steht dann in $c[1] 5 oder 6 drin?
Worauf ich hinauswill: wird unnötiger Speicherplatz reserviert bei der array()-Variante. Wenn ja, ist der Umweg über $c vermutlich ressourcensparender.
Martin
14 Jan 10 at 11:19
Nagut, wenn so wenige Vorschläge kommen, muss noch einer von mir her… ^^
$a .= $b;
$b = substr($a, 0, strlen($a) – strlen($b));
$a = substr($a, strlen($b));
Ist halt eine reine Spielerrei und geht nur unter PHP. thx2typejuggling
Tyco
14 Jan 10 at 12:03
Die Lösung mit list() ist mal echt innovativ. Werde ich mir merken 🙂
Stephan Hochdoerfer
14 Jan 10 at 14:33
@Martin: Habe gerade ein einfaches Benchmarking gemacht.
Die list/array-Variante dauert etwa doppelt so lang wie die herkömmliche Variante mit temporärer Variable.
Sobald du für die herkömmliche Variante aber einen Funktionsaufruf (zB. function tausche() von oben) verwendest, dauert es ca. genauso lang.
Das Schöne, an der list/array-Variante ist, dass absolut klar ist, was da passiert. Es ist mE. eine leserliche und elegante Lösung.
Tyco
14 Jan 10 at 15:32
Ich glaube, die Frage war nicht, welche Lösung schneller ist, sondern ob bei der Lösung mit array() und list() Pointer oder Kopien genutzt werden und damit der Speicherverbrauch steigt und Daten hin-und-her kopiert werden.
Hier die Lösung: Beim Aufruf von array() werden Kopien angelegt. Siehe:
$a = 5;
$b = 13;
$c = array($b, $a);
$a = 6;
var_dump($c);
Ausgabe:
array(2) {
[0]=>
int(13)
[1]=>
int(5)
}
Michael Kliewe
14 Jan 10 at 15:43
Ich muss noch ergänzen: Wenn man mit Objekten arbeitet, werden keine Kopien erzeugt, sondern nur mit den Referenzen gearbeitet. So wie man es erwartet.
Michael Kliewe
14 Jan 10 at 15:50
Hübsch sieht ja das aus:
$a ^= $b ^= $a ^= $b;
Red
14 Jan 10 at 16:08
Wenn ich folgendes Standard-Konstrukt habe
$a = 3;
$b = $a;
wird $a eben nicht kopiert. PHP funktioniert mit dem Copy-On Wrtie Paradigma (http://schlueters.de/blog/archives/125-Do-not-use-PHP-references.html) so wird $b erst kopiert wenn $a bzw. $b geändert werden. Zuvor zeigen beide Variablen auf die gleiche interne Variable.
Die ganzen (anderen) Möglichkeiten, welche ich bisher gelesen habe überzeugen mich nicht. Die „Standard-Variante“ mit der temporären Variable ist sprachunabhängig und jeder kennt sie. Eure Möglichkeiten versuchen doch größtenteils die PHP-Engine auszutricksen aber das soll man gerade nicht un (Don’t try to outsmart the engine – http://php100.wordpress.com/2009/07/13/php-performance/).
Ulf
14 Jan 10 at 17:23
[…] Dieser Eintrag wurde auf Twitter von Nico Hofmann, Michael Kliewe erwähnt. Michael Kliewe sagte: Neuer Blogartikel: Zwei Variablenwerte tauschen ( https://www.phpgangsta.de/zwei-variablenwerte-tauschen ) […]
Tweets die Zwei Variablenwerte tauschen | PHP Gangsta - Der PHP Blog erwähnt -- Topsy.com
16 Jan 10 at 04:19
Die XOR variante geht übrigens auch bei Strings mit gleicher Länge.
Malte
6 Mrz 10 at 02:34