2015-06-24 14 views
6

Chciałbym buforować niektóre dane w javascript, ale pamięć podręczna powinna być ograniczona do 10 elementów na przykład.Upuść ostatni element tablicy javascript, gdy tablica osiąga określoną długość.

Mogę umieścić obiekty w tablicy javascript, ale jaki jest najlepszy sposób, aby ograniczyć tablicę do 10 elementów?

Przykład:

function getData(dataId) { return new NextDataObject(dataId); } 

var array = new Array(); 

array.push(getData(0)); 
array.push(getData(1)); 
(...) 
array.push(getData(10)); // this should result in dropping "oldest" data, so getData(0) should be removed from the array, so that in array there are only 10 objects at maximum 

Jeżeli taki mechanizm być napisane ręcznie (za pomocą spawów() na przykład?) Czy istnieją lepsze sposoby, aby osiągnąć taką strukturę „cache” w javascript?

BTW: w tej szczególnej sytuacji używam kątowej.

+0

Musi to być tablicą lub może to być obiekt? – cosbor11

Odpowiedz

5

przesłonić funkcję push swojej tablicy buforowania.

var array = new Array() 
array.push = function(){ 
    if (this.length >= 10) { 
     this.shift(); 
    } 
    return Array.prototype.push.apply(this,arguments); 
} 

Plunker


Aby to bardziej wielokrotnego utworzonego sposobu, który zwraca nową instancję takiej macierzy (w oparciu o powyższy kod).

function getArrayWithLimitedLength(length) { 
    var array = new Array(); 

    array.push = function() { 
     if (this.length >= length) { 
      this.shift(); 
     } 
     return Array.prototype.push.apply(this,arguments); 
    } 

    return array; 

} 

var array = getArrayWithLimitedLength(10); 
+2

Nie sądzę, że jest to najlepszy sposób, ponieważ jeśli ma inną sytuację, w której tablica CAN może przekroczyć 10, push() będzie nadal ograniczać do 10 .. – Guinn

+0

@Guinn Pretty przyzwoite rozwiązanie. W "innej sytuacji, w której tablica CAN przekracza", wystarczy użyć czystej instancji tablicy z oryginalnym wypychaniem z prototypu. – dfsq

+2

@Michael Chcesz użyć 'shift', a nie' unshift'. – dfsq

4

Aby usunąć pierwszy element z zastosowania tablicy shift:

if (arr.length > 10) { 
    arr.shift(); // removes the first element from an array 
} 
+0

ta sama druga odpowiedź xD –

+2

@Tushar, myślę, że twoja druga odpowiedź jest niepoprawna, to tak naprawdę "przesunięcie", które pomaga nam usunąć pierwszy element. –

0

po prostu sprawdzić, czy została osiągnięta długość następnie pop to

if(arr.length > someNumber){ 
arr.pop(); // pop() will remove the last element 
} 
1
if(array.length == 10) { 

    array.splice(0, 1); 
    // this will delete first element in array 
} 
1

Jeśli do sprawdzenia, czy w tablicy osiągnął 10 pozycji za pomocą array.length, wystarczy usunąć pierwszy element przed naciśnięciem nowego elementu. Można to zrobić na wiele sposobów, jak twierdzi Tushar, array.shift() byłaby najszybsza, ale naprawdę można również użyć array.splice().

To będzie wyglądać następująco:

if(array.length > 10) { 
    array.shift(); 
    array.push(getData(10)); 
} 

Na marginesie, zamiast korzystania var array = new Array() Proponuję po prostu użyć var array = [];. Dzieje się tak dlatego, że nowe słowo kluczowe w JavaScript czasami ma złe efekty uboczne. Jeśli na przykład chcesz utworzyć tablicę z 1 elementem będącym cyfrą i użyjesz var arr = new Array(12);, zostanie utworzona tablica z 12 niezdefiniowanymi elementami. Natomiast var arr = [12]; utworzy tablicę z 1 elementu cyfra 12.

Ale myślę, że to drobne rzeczy do rozważenia ..

+0

To powinno być opublikowane jako Komentarz do pytania, a nie odpowiedzi. – walkeros

+0

Uh, dlaczego? Odpowiedziałem na twoje pytanie, prawda? Jeśli rozważasz odpowiedź tekstową zamiast kodu, możesz skopiować wklejkę niewłaściwą, zaktualizowałem ją kodem, który możesz skopiować, wklejałem ~ _ ~ – Guinn

+0

Podałem "plus jeden", ale proszę zauważyć, że nie zapytałem, jak powinienem zainicjować Array. Zapytałem, w jaki sposób powinienem ograniczyć i zacząłem swoją odpowiedź od "lekcji", jak ograniczyć tablicę ... możesz umieścić ją na końcu odpowiedzi lub jako BTW, ale nie powinieneś zaczynać swojej odpowiedzi od tego. BTW: fragment kodu nie ma znaczenia. Możesz edytować swoją odpowiedź zgodnie z tym i będzie dobrze. – walkeros

2

Można by stworzyć nową metodę w Array.prototype naśladować swoich potrzeb.

Array.prototype.push_with_limit = function(element, limit){ 
    var limit = limit || 10; 
    var length = this.length; 
    if(length == limit){ 
    this.shift(); 
    } 
    this.push(element); 
} 

var arr = [] 
arr.push_with_limit(4); // [4] 
arr.push_with_limit(9); // [4, 9] 
.... 
// 11th element 
arr.push_with_limit(3); // [9, ..., 3] 10 elements 
+1

Wykonuje to zadanie bez większego kodu. Zazwyczaj unikałem zmiany prototypu podstawowych obiektów JS chociaż ... Takie zmiany mogłyby wchodzić w interakcje z innym kodem, który robi te same lub podobne rzeczy. Ponadto, gdybym chciał dodać więcej komplikacji później, musiałbym albo jeszcze bardziej zanieczyszczać prototyp Array, albo zmienić sposób, w jaki ta funkcja jest używana w całym kodzie źródłowym. To i jestem totalnym kurczakiem. Bk-arrrrk. –

+0

OK, ale nie podoba mi się to, ponieważ zmienia prototyp obiektu Array – walkeros

2

Co powiesz na ten obiekt?

function Cache(maxLength) { 
    this.values = []; 

    this.store = function(data) { 
    if(this.values.length >= maxLength) { 
     this.getLast(); 
    } 
    return this.values.push(data); 
    } 

    this.getLast = function() { 
    return this.values.splice(0,1)[0]; 
    } 
} 

cache = new Cache(3); 
// => Cache {values: Array[0]} 
cache.store(1) 
// => 1 
cache.store(2) 
// =>2 
cache.store(3) 
// => 3 
cache.store(4) 
// =>3 
cache.values 
// => [2, 3, 4] 
cache.getLast() 
// => 2 
cache.values 
[3, 4] 
+0

Niestandardowa struktura danych może być najlepszym rozwiązaniem w tym przypadku. Łatwo testowalny i bardzo elastyczny. – dfsq

+0

Dziękuję. Nie uważam, że dobrą praktyką jest zmiana prototypu Array dla tego rodzaju funkcjonalności. (A co, jeśli zrobi to inna biblioteka?). Wierzę również, że dobrą praktyką jest tworzenie ładnych, zamkniętych jednostek OO kodu. Są one następnie adaptowalne, wielokrotnego użytku, a jeśli trzeba zmienić funkcjonalność mają interfejs, który można dostosować. –

+0

Przyjemne rozwiązanie (o którym też myślałem), ale nadpisanie metody dla pojedynczego wystąpienia macierzy, zgodnie z propozycją @Michael, jest znacznie lepsze, ponieważ jest proste. – walkeros

1

Zamiast tego można użyć obiektu ...

var obj = {}; //your cache object 
obj[window.performance.now()] = getData(val); //add value, index by microsecond timestamp 
if(Object.keys(obj).length > 10){ // then if the length ever gets bigger than 10.. 
var array = Object.keys(obj).sort(); //sort the properties by microsecond asc 
delete obj[array[0]]; //delete the oldest one 
} 

Tutaj jest przykład jsFiddle pokazujący jak to działa: https://jsfiddle.net/uhkvk4mw/

+0

Dzięki za kod, ale to jest droga do skomplikowanego na tak proste zadanie IMHO. – walkeros

2

Proste stałą długość kolejki:

Array.prototype.qpush = function(vals, fixed) { 
    if (arguments.length) { 
     if (Array.isArray(vals)) { 
      for (var v of vals) { 
       this.push(v); 
      } 
     } else { 
      this.push(vals); 
     } 
     var _f = (typeof this.fixed != undefined) ? this.fixed : 0; 
     if (typeof fixed != undefined) { 
      _f = (Number(fixed)===fixed && fixed%1===0) ? fixed : _f; 
     } 
     this.fixed = _f; 
     if (this.fixed>0) this.splice(0, this.length - _f);   
    } 
} 

var q = new Array(); 
q.push(0); 
q.qpush([1, 2, 3], 10); 
q.qpush([4]); 
q.qpush(5); 
q.qpush([6, 7, 8, 9, 10, {k:"object"} ]); 
console.log(q); 
+0

OK, ale nie podoba mi się to, ponieważ zmienia prototyp obiektu Array – walkeros

Powiązane problemy