Zestaw Javascript a wydajność tablicy

To może dlatego, że zestawy są stosunkowo nowe w Javascript, ale nie byłem w stanie znaleźć artykułu, na StackO lub gdziekolwiek indziej, który mówi o różnicy wydajności między tymi dwoma w Javascript. Więc jaka jest różnica, jeśli chodzi o wydajność, między tymi dwoma? W szczególności, jeśli chodzi o usuwanie, dodawanie i iterację.

Author: neoflash, 2016-08-18

5 answers

OK, przetestowałem dodawanie, iterację i usuwanie elementów zarówno z tablicy, jak i zbioru. Przeprowadziłem test "mały", z użyciem 10 000 elementów i test" duży", z użyciem 100 000 elementów. Oto wyniki.

Dodawanie elementów do zbioru

Wydaje się, że metoda .push array jest około 4 razy szybsza niż metoda .add set, bez względu na liczbę dodanych elementów.

Iteracja i modyfikowanie elementów w zbiorze

Do tej części w teście użyłem pętli for do iteracji po tablicy i pętli for of do iteracji po zbiorze. Ponownie, iteracja na tablicy była szybsza. Tym razem wydawałoby się, że jest tak wykładniczo, że w "małych" testach trwało to dwa razy dłużej, a w "dużych" prawie cztery razy dłużej.

Usuwanie elementów ze zbioru

Teraz robi się ciekawie. Użyłem kombinacji pętli for i .splice do usunięcia niektórych elementów z tablicy i użyłem for of i .delete, aby usunąć niektóre elementy z zestawu. W przypadku" małych "testów usunięcie elementów z zestawu było około trzy razy szybsze (2.6 MS vs 7.1 ms), ale sytuacja zmieniła się drastycznie w przypadku" dużego " testu, gdzie usunięcie elementów z tablicy zajęło 1955.1 ms, podczas gdy usunięcie ich z zestawu zajęło tylko 83.6 ms, 23 razy szybciej.

Wnioski

Przy 10K elementach oba testy przebiegały porównywalnie (array: 16.6 ms, set: 20.7 ms) ale gdy mamy do czynienia z 100k elementami, zestaw był zdecydowanym zwycięzcą (array: 1974,8 ms, set: 83,6 ms), ale tylko ze względu na operację usunięcia. W przeciwnym razie tablica była szybsza. Nie wiem dlaczego.

Grałem w kilka hybrydowych scenariuszy, w których tablica została utworzona i wypełniona, a następnie przekształcona w zestaw, w którym niektóre elementy zostaną usunięte, zestaw zostanie ponownie przekształcony w tablicę. Chociaż to da znacznie lepszą wydajność niż usuwanie elementów w tablicy, dodatkowe przetwarzanie czas potrzebny na przeniesienie do i z zestawu przeważa nad zyskami wynikającymi z wypełnienia tablicy zamiast zestawu. W końcu szybciej jest poradzić sobie tylko z zestawem. Jednak interesującym pomysłem jest to, że jeśli ktoś zdecyduje się użyć tablicy jako zbioru danych dla niektórych dużych danych, które nie mają duplikatów, może to być korzystne pod względem wydajności, jeśli kiedykolwiek istnieje potrzeba usunięcia wielu elementów w jednej operacji, aby przekonwertować tablicę na zestaw, wykonać operację usuwania i przekonwertować zestaw z powrotem na zestaw. / align = "left" /

Kod tablicy:

var timer = function(name) {
  var start = new Date();
  return {
    stop: function() {
      var end = new Date();
      var time = end.getTime() - start.getTime();
      console.log('Timer:', name, 'finished in', time, 'ms');
    }
  }
};

var getRandom = function(min, max) {
  return Math.random() * (max - min) + min;
};

var lastNames = ['SMITH', 'JOHNSON', 'WILLIAMS', 'JONES', 'BROWN', 'DAVIS', 'MILLER', 'WILSON', 'MOORE', 'TAYLOR', 'ANDERSON', 'THOMAS'];

var genLastName = function() {
  var index = Math.round(getRandom(0, lastNames.length - 1));
  return lastNames[index];
};

var sex = ["Male", "Female"];

var genSex = function() {
  var index = Math.round(getRandom(0, sex.length - 1));
  return sex[index];
};

var Person = function() {
  this.name = genLastName();
  this.age = Math.round(getRandom(0, 100))
  this.sex = "Male"
};

var genPersons = function() {
  for (var i = 0; i < 100000; i++)
    personArray.push(new Person());
};

var changeSex = function() {
  for (var i = 0; i < personArray.length; i++) {
    personArray[i].sex = genSex();
  }
};

var deleteMale = function() {
  for (var i = 0; i < personArray.length; i++) {
    if (personArray[i].sex === "Male") {
      personArray.splice(i, 1)
      i--
    }
  }
};

var t = timer("Array");

var personArray = [];

genPersons();

changeSex();

deleteMale();

t.stop();

console.log("Done! There are " + personArray.length + " persons.")

Ustaw kod:

var timer = function(name) {
    var start = new Date();
    return {
        stop: function() {
            var end  = new Date();
            var time = end.getTime() - start.getTime();
            console.log('Timer:', name, 'finished in', time, 'ms');
        }
    }
};

var getRandom = function (min, max) {
  return Math.random() * (max - min) + min;
};

var lastNames = ['SMITH','JOHNSON','WILLIAMS','JONES','BROWN','DAVIS','MILLER','WILSON','MOORE','TAYLOR','ANDERSON','THOMAS'];

var genLastName = function() {
    var index = Math.round(getRandom(0, lastNames.length - 1));
    return lastNames[index];
};

var sex = ["Male", "Female"];

var genSex = function() {
    var index = Math.round(getRandom(0, sex.length - 1));
    return sex[index];
};

var Person = function() {
	this.name = genLastName();
	this.age = Math.round(getRandom(0,100))
	this.sex = "Male"
};

var genPersons = function() {
for (var i = 0; i < 100000; i++)
	personSet.add(new Person());
};

var changeSex = function() {
	for (var key of personSet) {
		key.sex = genSex();
	}
};

var deleteMale = function() {
	for (var key of personSet) {
		if (key.sex === "Male") {
			personSet.delete(key)
		}
	}
};

var t = timer("Set");

var personSet = new Set();

genPersons();

changeSex();

deleteMale();

t.stop();

console.log("Done! There are " + personSet.size + " persons.")
 51
Author: neoflash,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-08-18 05:18:57

Obserwacje :

  • operacje Set mogą być rozumiane jako migawki w strumieniu wykonania.
  • Nie jesteśmy przed ostatecznym substytutem.
  • elementy klasy Set nie mają dostępnych indeksów.
  • klasa Set jest dopełniaczem klasy Array, przydatnym w tych scenariuszach, w których musimy przechowywać kolekcję, na której można zastosować podstawowe dodawanie, Usuwanie, sprawdzanie i iteracja szef.
Dzielę się testem wydajności. Spróbuj otworzyć konsolę i skopiuj poniższy kod.

Tworzenie tablicy (125000)

var n = 125000;
var arr = Array.apply( null, Array( n ) ).map( ( x, i ) => i );
console.info( arr.length ); // 125000

1. Pozycjonowanie indeksu

Porównaliśmy metodę has zbioru z tablicą indexOf:

Array / indexOf (0.281 ms) | Set/ has (0.053 ms)

// Helpers
var checkArr = ( arr, item ) => arr.indexOf( item ) !== -1;
var checkSet = ( set, item ) => set.has( item );

// Vars
var set, result;

console.time( 'timeTest' );
result = checkArr( arr, 123123 );
console.timeEnd( 'timeTest' );

set = new Set( arr );

console.time( 'timeTest' );
checkSet( set, 123123 );
console.timeEnd( 'timeTest' );

2. Dodawanie nowego elementu

Porównujemy metody add I push zestawu i odpowiednio Obiekty tablicy:

Array / push (1.612 ms) | Set/ add (0.006 ms)

console.time( 'timeTest' );
arr.push( n + 1 );
console.timeEnd( 'timeTest' );

set = new Set( arr );

console.time( 'timeTest' );
set.add( n + 1 );
console.timeEnd( 'timeTest' );

console.info( arr.length ); // 125001
console.info( set.size ); // 125001

3. Usuwanie elementu

Usuwając elementy, musimy pamiętać, że tablica i Set nie uruchamiają się w równych warunkach. Tablica nie posiada natywnej metody, dlatego konieczna jest funkcja zewnętrzna.

Array / deleteFromArr (0.356 ms) | Set/ remove (0.019 ms)

var deleteFromArr = ( arr, item ) => {
    var i = arr.indexOf( item );
    i !== -1 && arr.splice( i, 1 );
};

console.time( 'timeTest' );
deleteFromArr( arr, 123123 );
console.timeEnd( 'timeTest' );

set = new Set( arr );

console.time( 'timeTest' );
set.delete( 123123 );
console.timeEnd( 'timeTest' );
[5] ... Czytaj całość artykuł tutaj
 26
Author: Daniel Eduardo Delgado Diaz,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-09-13 07:05:35

Moja obserwacja jest taka, że zestaw jest zawsze lepszy z dwoma pułapkami dla dużych tablic w umyśle :

A) tworzenie zestawów z tablic musi odbywać się w pętli for o wstępnie ustawionej długości.

powolne (np. 18ms) new Set(largeArray)

szybki (np. 6ms) const SET = new Set(); const L = largeArray.length; for(var i = 0; i<L; i++) { SET.add(largeArray[i]) }

B) iteracja może być wykonana w ten sam sposób, ponieważ jest również szybsza niż pętla for of...

Zobacz https://jsfiddle.net/0j2gkae7/5/

Dla prawdziwego porównania z difference(), intersection(), union() i uniq() (+ich towarzysze itp.) z 40.000 elementów

 2
Author: sebilasse,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-11-12 15:04:24

Ostatnio przeprowadziłem ten test i okazało się, że Set znacznie przewyższa tablicę 1000 elementów (około 10x operacje mogą się zdarzyć w tym samym czasie). I w zależności od przeglądarki albo beat lub utracone do obiektu.hasOwnProperty w teście like for like.

Zarówno Set, jak i Object mają swoją metodę" has " wykonującą to, co wydaje się być zamortyzowane do O(1), ale w zależności od implementacji przeglądarki pojedyncza operacja może trwać dłużej lub szybciej.

Https://jsperf.com/set-has-vs-object-hasownproperty-vs-array-includes/1 Jeśli chcesz uruchomić własne testy w różnych przeglądarkach/środowiskach.

 0
Author: Zargold,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-04-29 15:22:38
console.time("set")
var s = new Set()
for(var i = 0; i < 10000; i++)
  s.add(Math.random())
s.forEach(function(e){
  s.delete(e)
})
console.timeEnd("set")
console.time("array")
var s = new Array()
for(var i = 0; i < 10000; i++)
  s.push(Math.random())
s.forEach(function(e,i){
  s.splice(i)
})
console.timeEnd("array")

Te trzy operacje na 10K przedmiotów dał mi:

set: 7.787ms
array: 2.388ms
 -4
Author: jessh,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-08-17 23:24:39