Wissel inhoud van variabelen zonder temp

Door Johan Dam, 10 jaar geleden, 7.811x bekeken

Goed, dit is simpel trucje,

Eerst een stukje waarom ik dit uberhaubt ben gaan opzoeken,

In een artikel dat ik niet zo lang zag, stond er dat veel mensen die soliciteren als programmeur vaak niet konden programmeren, om het kaf van het koren te scheiden werden er vragen gesteld. 1 van die vragen was als volgt;

Hoe zou je de inhoud van 2 variabele verwisselen zonder het gebruik van een 3e variabele?

Op zich nog geen makkelijke vraag in PHP
Met getallen is dit nogal makkelijk;

Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
6
$a = 2;
$b = 5;

$a = $a + $b;
$b = $a - $b;
$a = $a - $b;


Maar met strings?
Hoe verwissel je die?
Wil je moeilijk gaan doen met strlen ofzo?
Dat moet toch veel makkelijker kunnen?

En ja, dit kan veel makkelijker: de XOR operator

Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
6
7
8
9
10
$foo = 'foo';
$bar = 'bar';

echo '$foo = ', $foo, ' && $bar = ', $bar, ';<br />';

$foo ^= $bar;
$bar ^= $foo;
$foo ^= $bar;

echo '$foo = ', $foo, ' && $bar = ', $bar, ';<br />';


Wat de ^ nu eigenlijk doet is, het zet de bits die in $foo aan staan maar niet in $bar, na de eerste keer bevat $foo dus de bit gegevens van beide variabele, daarna worden ze weer terug gezet, eigenlijk netzoals de + en - met getallen, maar dan op het niveau van de eentjes en nulletjes.

Waarom zou je dit in vredesnaam willen?
Elke variabele kost geheugen, als het geen nut heeft om een variabele aan te maken moet je dat niet doen.

Gesponsorde koppelingen

Inhoudsopgave

  1. Geen tutorials aanwezig.

 

Er zijn 26 reacties op 'Wissel inhoud van variabelen zonder temp'

PHP hulp
PHP hulp
0 seconden vanaf nu
 

Gesponsorde koppelingen
Danny Roelofs
Danny Roelofs
10 jaar geleden
 
Ik zou me niet zo zeer zorgen maken om het geheugen, maar het is ja een programmeer technische uitdaging om zo vraag te beantwoorden, voor iedereen die ooit in ASM heeft geschreven komt dit bekend wel voor.

Maar nog een manier, zonder gebruik te maken van nog een variabele.

Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
6
<?php
$foo
=1;
$bar=2;
list($bar, $foo) = array($foo, $bar);
echo $foo,$bar;
?>
Niels K
Niels K
10 jaar geleden
 
Ja Danny, maar ik vind die oplossing van Johan toch wat efficiënter, en het kost nog minder tijd om hem te schrijven ook...
Pim -
Pim -
10 jaar geleden
 
Quote:
Waarom zou je dit in vredesnaam willen?
Elke variabele kost geheugen, als het geen nut heeft om een variabele aan te maken moet je dat niet doen.

Onzin. Zowel lees- als schrijfgemak zijn net zo belangrijk als prestatie.
Danny Roelofs
Danny Roelofs
10 jaar geleden
 
0 +1 -0 -1
@Niels Efficiënter wel, Maar beperkt zich alleen tot Integers, en 'kost nog minder tijd om hem te schrijven' is qua inkloppen van code verhoudingsgewijs te verwaarlozen.

Want uiteindelijk ging de vraagstelling over om twee variabelen te wisselen, en dan lijkt me een voorbeeld om het met getallen gemakkelijk gaat toch ook belangrijk om aan te geven dat dit ook met andere inhoud kan.
Niels K
Niels K
10 jaar geleden
 
Daar heb je dan weer helemaal gelijk in.
Wim Tibackx
Wim Tibackx
10 jaar geleden
 
Ik vraag me toch echt wel af wat er hier nuttig aan is. Als je nu gewoon je ongebruikte variables opkuist, bijvoorbeeld met unset, is er toch geen probleem? Dan kan je toch makkelijk een 3e var gebruiken?

Verder, zoals eerder vermeld in de commentaren, moet de code logisch en begrijpbaar zijn. Waarom je 6 (int) of 10 (string) lijnen code gebruiken voor zoiets?

En verder, wat voor nut heeft een vraag als deze op een solicitatiegesprek? Ik zou liever een programmeur hebben die z'n garbage collection deftig kan, dan een die zo'n belachelijke stukken code schrijft om maar geen extra variable te moeten gebruiken.

Ik heb vroeger ook al zaken gelezen waarbij men in solicitatiegesprekken vroeg hoe functie X werkte of welke parameters functie Y aannam. Da's ook weer zoiets belachelijks. Als een programmeur goeie code schrijft en in een deftige tijd, wat maakt het dan uit of hij/zij functieparameters of functienamen van buiten kent?

Code moet spontaan ontstaan, vanuit gevoel, niet door van buiten te leren. Je moet in code kunnen denken en er je plan mee kunnen trekken. Het is totaal belachelijk om code vanbuiten te leren, want dan kan men ze vaak maar op één wijze implementeren en vaak weet men op den duur ook niet meer wat de code precies doet.

Ik leer op dit moment op school C#. Zelf heb ik daar geen probleem mee, omdat ik gewoon ben in code te denken enz. doordat ik al jaren php programmeer. Ik merk echter dat veel van mijn klasgenoten grote stukken van hun code vanbuiten leren. En oa. ook welke parameters functie X aanneemt en welke functie men moet gebruiken om iets bepaalds te doen, met als gevolg dat, wanneer men een detail veranderd in de opgave, men niet meer weet hoe dit te maken, of wanneer men vraagt de code uit te leggen, zij dit niet kunnen.
Niels K
Niels K
10 jaar geleden
 
Richard van Velzen
Richard van Velzen
10 jaar geleden
 
0 +1 -0 -1
Schattig, heel schattig. Maar helaas ook compleet nutteloos, stel dat $bar 'barbar' bevat, dan verlies je als $foo 'foo' bevat de laatste drie tekens.

Probeer alsjeblieft nooit de 'kortste' manier voor iets te bedenken: het kost je ten eerste meer tijd en ten tweede moet je niet vergeten dat alle soorten compilers zijn geoptimaliseerd om dit soort zaken op te vangen.

Probeer nooit een compiler te slim af te zijn: dat kost je meer dan die extra variabele.
Wesley Overdijk
wesley Overdijk
10 jaar geleden
 
0 +1 -0 -1
Je was me net voor. naja, 18 uur, maar toch.
Karl Karl
Karl Karl
10 jaar geleden
 
Nicoow Unknown
Nicoow Unknown
10 jaar geleden
 
0 +1 -0 -1
@Niels,
De Wetten Van De Morgan heeft te maken met statistiek, kans bereken enzo (yeah,, heb een 5,5 =D).
Wat dat hier mee te maken heb, ik heb eerlijk waar geen idee, maar ik vond deze nog:
http://nl.wikipedia.org/wiki/Wet_van_Murphy
Martijn Wieringa
Martijn Wieringa
10 jaar geleden
 
0 +1 -0 -1
Zeker met PHP vind ik leesbaarheid belangrijker dan efficiency; maar dat komt ook omdat het aantal regels dat een PHP script doorloopt relatief laag is.

Bij extremere applicaties die miljoenen regels doorlopen; en van zichzelf niet zo'n effectieve 'garbage collection' hebben, kan elke bit geheugen die je onnodig claimt uiteindelijk leiden tot een vol geheugen. Al die bits bij elkaar kan zo oplopen tot vele MB's of zelfs GB's.
Richard van Velzen
Richard van Velzen
10 jaar geleden
 
0 +1 -0 -1
Dat wil niet zeggen dat je dit soort praktijken moet gaan toepassen.

Het enige waar je op moet letten is je geheugengebruik: resources vrijmaken zodra je ze niet gebruikt, en natuurlijk vanaf 5.3 de nieuwe GC-functies gebruiken.
Aad B
Aad B
10 jaar geleden
 
0 +1 -0 -1
Het is een leuk onderwerp en geinige geheugentraining maar in de praktijkk voegen we toch wat geheugenbankjes toe ? Onze blades zijn 64GB intern memory en 8 cores en we voegen een node toe wanneer nodig....
Niemand maakt zich meer druk om wat variabelen toch ??
Niek s
niek s
10 jaar geleden
 
0 +1 -0 -1
*Dubbelcheckt*
Ja dit is echt een artikel van 3 weken geleden =/

Ik denk dat tegenwoordig met de snelheden & geheugen dit geen probleem meer hoeft zijn, en is.
Denk dat tegenwoordig dat duidelijkheid van code toch wel veel belangrijker kan worden geacht, als dit soort prut..
Ivo K
Ivo K
10 jaar geleden
 
1 +1 -0 -1
Nou nou nou, iedereen is weer lekker bezig als ik het zo lees. Johan heeft hier gewoon een snippet geplaatst, om ons een extra truckje te leren, wat weliswaar tegenwoordig nauwelijks meer nodig is, hij zegt nergens dat het een must-do is. Ga dan toch niet allemaal zeggen dat het overbodig is, wat maakt dat uit? Kunnen mensen niet gewoon even zeggen: Leuk dat het ook op deze manier kan.
John Zondag
John Zondag
10 jaar geleden
 
0 +1 -0 -1
Ook ik vind het een leuke snippet van Johan.
@Danny: leuk geprobeerd, maar list creeert een array en dat is ook een (hele dure) variabele....
Pim -
Pim -
10 jaar geleden
 
0 +1 -0 -1
En wat is er mis met het maken van een array? Zeker als de refcount daarna 0 is en hij als het goed is weer wordt verwijderd bij de garbage collection.
Laurens Tummers
Laurens Tummers
10 jaar geleden
 
Ik programmeer zelf al 25 jaar en heb dus een redelijke kijk op deze materie. Deze flauwekul met het swappen van variabelen zonder het aanmaken van een 3e dummy variabel was 20 jaar geleden al not-done. Laat staan nu, in een computertijdperk waar we echt niet wakker liggen van 2 bytes meer of minder declareren. Ik heb het idee dat hier een paar mensen zich heel interessant willen voordoen en een cryptogram wedstrijd willen maken van het programmeren. Laten we liever elkaar helpen met echte vraagstukken die echt er toe doen....
Pieter Jansen
Pieter Jansen
10 jaar geleden
 
0 +1 -0 -1
@Laurens: Los van het feit dat JIJ het misschien compleet nutteloos vindt, zijn er wel degelijk belangen om te swappen. Mensen kunnen misschien wel interessant praten, maar soms moet het ook?

Als jij embedded hardware gaat programmeren, dan ga je echt wel letten op het geheugen gebruik. Als er maar 32 byte tot je beschikking zijn, en je gaat een simpele timer clock programmeren in bijv. assembly, dan wil je toch echt wel je bytes vrij houden. Elke byte gaat dan tellen. En als je een swap moet maken, of wat dan ook, wil je niet eerst een nieuwe byte gaan reserveren.
Laurens Tummers
Laurens Tummers
10 jaar geleden
 
0 +1 -0 -1
Beste Merijn,

In dergelijke gevallen als er slechts 32 bytes beschikbaar is, is het natuurlijk nuttig. Maar in het ontwikkelen van de doorsnee programmatuur is het totaal overbodig.
Bovendien komt het niet ten goede voor het lezen van de sourcecode.
Ik heb zelf ook jarenlang 68000 motorola assembler geprogrammeerd maar nooit heb ik zo'n trucendoos gebruikt. Liever 2 dummy bytes declareren die je in de gehele sourcecode kan gebruiken als tijdelijke opslag en voor iedereen begrijpelijk is. Maar ja, dat is mijn mening....
Richard van Velzen
Richard van Velzen
10 jaar geleden
 
0 +1 -0 -1
@Merijn: misschien dat je dan een betere compiler moet gebruiken, de meeste optimaliseren juist voor swap-variabelen en dit soort trucs maken de uiteindelijk machinecode juist minder efficiënt.
Pieter Jansen
Pieter Jansen
10 jaar geleden
 
0 +1 -0 -1
Klopt, heb je wel gelijk in. Maar los van dat feit blijft het argument staan dat het wel verdomd handig kan zijn, zeker als je niet een compiler hebt die dat onder water voor je regelt. Ik geef alleen aan dat het nodig kan zijn.

Voor de meeste programmeurs is het totaal overbodig, zeker door de enorme hoeveelheden geheugen die we tegenwoordig tot onze beschikking hebben. Daarom kan het wel handig zijn, want je zult maar 16bit tot je beschikking hebben.. Dan hang je als je niet je bits kunt reserveren..
Toby hinloopen
toby hinloopen
10 jaar geleden
 
Efficient?
Dit is ver weg van efficient. Dit is handig voor omgevingen waar een zwaar tekort aan geheugen is en geheugen allocatie te zwaar is, niet voor PHP :P

Bij deze techniek voor je 3 zware bitwise operaties uit over je data. In PHP is deze techniek volledig zinloos; een tijdelijke variable aanmaken in PHP is toch wel wat efficienter dan 3 zware bitwise operaties.

Verder maak je bij PHP geen kopie van de tekenreeks wanneer je 'm toewijst aan een andere variable. Je kopieert slechts de pointer naar de tekenreeks, zoals bij alle andere loose-typed talen. Pas als je de tekenreeks aanpast wordt er een nieuwe gemaakt.

Alleen in C/C++ zou deze techniek nog nut kunnen hebben.

Als je echt wilt wisselen zonder het maken van een nieuwe tekenreeks kan je ook teken voor teken verwisselen; je hoeft dan maar 1 teken op te slaan in de tijdelijke variable.

Je draait dan een loop door beide tekenreeksen en verwisselt de tekens 1-voor-1, maar in PHP is dit ook weer totaal zinloos omdat PHP de fisieke tekenreeks niet opslaat in variables, maar de pointer ernaar.
Richard van Velzen
Richard van Velzen
10 jaar geleden
 
0 +1 -0 -1
Toby: waar heb jij dat soort onzin precies geleerd?
PHP hulp
PHP hulp
0 seconden vanaf nu
 

Gesponsorde koppelingen
Toby hinloopen
toby hinloopen
10 jaar geleden
 
0 +1 -0 -1
Ik heb wel eens gespeeld met diversen interpreters en compilers, zoals die van PHP en Google's V8 Javascript engine.

Verder:
Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<?php

header('Content-Type: text/plain');

echo memory_get_usage() . '\n';

// Store 2 4MB strings in 2 variables
$a = str_repeat('1234',1024*1024);
$b = str_repeat('5678',1024*1024);

echo memory_get_usage() . '\n';

$c = $a;
$a = $b;
$b = $c;

echo memory_get_usage() . '\n';

// $c veranderen; nieuwe tekenreeks wordt aangemaakt.
$c[4] = '2';

echo memory_get_usage() . '\n';

?>


Output:
Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
325852
8714620
8714668
12909012


Als de fisieke tekenreeks naar $c gekopieerd zou worden zou het geheugen op ~12MB zitten, niet op ~8MB.

Pas wanneer ik 1 teken in $c aanpas moet er een nieuwe tekenreeks gemaakt worden. Dat is ook weer terug te zien, want na het aanpassen van 1 byte in de tekenreeks is er opeens 4MB geheugengebruik bijgekomen.

Daar heb ik deze 'onzin' dus geleerd.

Verder, om het nog eventjes leuker te maken:
Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
<?php

header('Content-Type: text/plain');

// Store 2 4MB strings in 2 variables
$a = str_repeat('1234',1024*1024);
$b = str_repeat('5678',1024*1024);

$s1 = microtime();

$a ^= $b;
$b ^= $a;
$a ^= $b;

$e1 = microtime();

$s2 = microtime();

$c = $a;
$a = $b;
$b = $c;

$e2 = microtime();

function
getMillisecondsPassed($start, $end){
    $start=explode(' ',$start,2);
    $end=explode(' ',$end,2);
    return ((int)$end[1] - (int)$start[1]) * 1000
         + ((float)$end[0] - (float)$start[0]) * 1000;
}


echo 'Tijd xor: '.getMillisecondsPassed($s1, $e1).' millisecs\n';
echo 'Tijd wissel: '.getMillisecondsPassed($s2, $e2).' millisecs\n';

?>


Resultaat:
Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
Tijd xor: 80.763 millisecs
Tijd wissel: 0.00299999999998 millisecs


Je bespaart dus 48 bytes voor de pointer (zie verschil in bovenstaande voorbeeld), maar het kost 1000en keren zoveel tijd.

Om te reageren heb je een account nodig en je moet ingelogd zijn.

 
 

Om de gebruiksvriendelijkheid van onze website en diensten te optimaliseren maken wij gebruik van cookies. Deze cookies gebruiken wij voor functionaliteiten, analytische gegevens en marketing doeleinden. U vindt meer informatie in onze privacy statement.