Strona główna - poczytaj o JavaScript, jQuery, CSS i HTML5

Front-Trends 2010

Wydajna podmiana liczb w jednej linijce

JavaScript jest, jaki jest – kolejne jego wersje dodają bardzo przydatne funkcje, aczkolwiek przeglądarki implementują je dość opieszale. Absolutną podstawą, obecną we wszystkich nowoczesnych browserach, jest JS 1.5. Niestety smaczki, jakie oferuje nam JavaScript 1.7 są nieobecnie, na przykład, w Internet Explorerze, stąd też w, zdawałoby się, oczywistych sytuacjach, musimy sobie radzić róznymi workaroundami. Co na przykład, jeśli chcemy zrobić szybką podmianę wartości zmiennych, nie korzystając z trzeciej, pomocniczej?

W JavaScript 1.7 to bułka z masłem:

var x = 2000;
var y = 1000;

[x, y] = [y, x];

Działa w nowych Firefoxie i Operze.

Jako że z dostępnością takiej konstrukcji dość krucho – trzeba sobie radzić w inny sposób, wykorzystując pewien tok myślowy.

var x = 2000;
var y = 1000;

x += y;
y = x-y;
x -= y;

Do zmiennej x dodajemy zmienną y i robi sie 3000. Żeby wyłuskać starą wartość zmiennej x, tym samym dokonując pierwszej zamiany, trzeba odjąć od powstałej sumy zmienną y. Matematyka…

Ostatnim krokiem jest odjęcie od zmiennej x nowej wartości zmiennej y. Wszystko gra, a można to lepiej zrozumieć poprzez spokojną analizę powyższych trzech kroków. Można ewentualnie sobie to rozpisać:

var x = 2000;
var y = 1000;

x = x+y;
y = x-y;
x = x-y;

Wszystko fajnie, ale nie jesteśmy zwykłymi leszczami i chcielibyśmy pochwalić się kolegom (lub koleżankom, choć te rzadko programują ;-)), że potrafimy zrobić coś takiego w jednej linijce. Jako że JavaScript umożliwia wielokrotne przypisanie typu:

x = y = z = a;

zróbmy małą reorganizację kodu, przepisując to, co mamy

var x = 2000;
var y = 1000;

x -= y = (x+=y) - y;

Podmienia się tylko zmienna y, co dzieje się dość prosto, jeśli przeczytamy kod od prawej do lewej, aż do pierwszego przypisania (=):

y = (x+=y) - y;

W ten sposób zmienna y dostaje wartość 2000. Następnie JS wykonuje:

x -= y

co jest niczym innym, jak:

x = 2000 - 2000

Stało się tak dlatego, że JS w przypisaniu od lewej pobiera domyślnie wartość x z globalnego Scope’u, ignorując tym samym x+=y.

Jako że arytmetyka wygląda tak, jak wygląda – zawsze możemy pokombinować. Do dzieła!

Zróbmy małą reorganizację kodu:

var x = 2000;
var y = 1000;

x = x - y = (x = x + y) - y;

Jest już prościej (opuściliśmy wszelkie +=)! Trzeba by jednak przenieść x na koniec, by JavaScript nie ogłupiał nas z domyślną jego wartością.

Trochę zabawy z kolejnością:

var x = 2000;
var y = 1000;

x = -(y = (x = x + y) - y) + x;

i jest! Szczegółowa analiza tego, co się dzieje, wskazuje, że to nic innego, jak uproszczony zapis procesu, który przedstawiłem na początku w trzech krokach. Voila!

Powyższą konstrukcję można jeszcze bardziej uprościć, ale zadanie to zostawiam dla śmiałków.

Komentarze

1

Niektórzy się jeszcze martwią, że przy przypisaniu x = x + y można wyjść za zakres zmiennej (przynajmniej w c++, nie wiem jak ma się sprawa w JS).

Ciekawy artykuł :-)

2

Może to i wygląda “szpanersko” ale czy ma sens?
Minie kilka miesiący i zagladając w kod bedziesz zadowal sobie pytanie: “Co autor mial na mysli?” Nie wspominajac juz o osobach nowych.
Poza tym, fajna “sztuczka”.
Pozdr. :-)

Greg
3

Sztuczki ciekawe, ale jakoś nie widzę tego w praktycznym zastosowaniu. Dostajesz taki kod do poprawienia od kogoś i siedzisz przez godzinę, aby załapać co się dzieje w ciągu 10 linii kodu. Oszczędność łącza w przypadku takiego JS to oczywiście plus, ale rozwijanie aplikacji to koszmar…

4

Witam

Ten sam trick można powtórzyć korzystając z mnożenia oraz dzielenia, a także- co zdecydowanie bardziej zasługuje na miano “wydajnej podmiany”- z operatorów bitowych ;-)

Zgadzam się jednak z przedmówcami- rozwiązanie może i jest “dżezi”, ale łamie zasadę KISS. Dodatkowo- JS nie jest wykorzystywany w systemach wbudowanych, więc nie widzę problemu w stworzeniu dodatkowej zmiennej- pamięci nam raczej nie braknie ;-)

Pozdrawiam

5

Coś takiego ma sens, kiedy pamięć jest ograniczona i nie możemy sobie pozwolić na dodatkową zmienną – np. na sofcie w telefonach komórkowych ;-)

Co do operatorów bitowych, mnożenia, dzielenia – jasne, dlatego też napisałem ostatnie zdanie. Może w przyszłości przedstawie inne metody ;-) W kazdym razie chodziło mi tutaj o przemycenie idei jednolinijkowych przypisań.

Pozdrawiam

6

Wszystko ok, ale… co, jeśli zechcę podmienić zmienne typu string? ;)

7

Moze klepne dzisiaj notke na ten temat ;-)

8

spoko, pisząc soft na Samsungi, może się przydać ;)))

9

Swap rzeczywiście w jednej linijce, ale ile osób szybko to zrozumie równie szybko, jeśli obok nie będzie komentarza na ten temat. Osobiście wolę kiedy kod ma więcej linijek, a łatwiej się go czyta.

Z czasem zapomina się co kierowało programistą podczas tworzenia takiego kodu, a długa analiza to ciężka sprawa. Wniosek na podstawie własnych doświadczeń. Mimo, tego gratuluję pomysłu.

10

Zrobienie tego w jednej linijce jest też możliwe z pomocą średnika. Skoro jednak autor nie wspomniał o tym sposobie, to zgaduję, że średnika pewnie nie obsługują telefony komórkowe, z myślą o których opracował tę wyrafinowaną metodę.

;)

11

tak btw, bez kombinowania to możnaby i tak:
x=y+!(y=x)

Tomasz B.
12

Niezle! Aczkolwiek sypie sie z zerem z wiadomych powodow :-)

13

Mozna jeszcze tak:

x=y+( (y=x) & 0);

;-)

14

Brawo!
moje niedopatrzenie :-)

Tomasz B.
15

Najkrocej:

x=y+(y=x)*0;

Dodaj komentarz

Dozwolone tagi: <blockquote>, <code>, <strong>