2016-01-04 13 views
24

MDN documentation for Set mówi, że JavaScript Set obiekty zachować kolejność wstawiania elementów:Pobierz ostatnią wartość wstawiony do zestawu

Set obiekty są zbiorami wartości, można iteracyjne jego elementy w kolejności wprowadzania.

Czy istnieje sposób na umieszczenie ostatniego przedmiotu w obiekcie Set?

var s = new Set(); 
s.add("Alpha"); 
s.add("Zeta"); 
s.add("Beta"); 

console.log(getLastItem(s)); // prints "Beta" 
+0

W celu wstawienia? Czy javascript ma ustawione operacje O (n)? –

+0

@FilipHaglund Wstawianie, wyszukiwanie i usuwanie to O (1). Standard wymaga jeszcze jednej rzeczy: powtarzania elementów w zamówieniu reklamowym. Ale nie trzeba powtarzać, aby wykonać wyszukiwanie. –

+0

Jestem pewien, że to nie jest O (1). Czy zachowuje oddzielną listę kluczy do iteracji i drzewo do wyszukiwania, czyniąc iterację O (n log n)? –

Odpowiedz

18

nie udało mi się znaleźć żadnego sposobu, aby uzyskać ostatnią wartość włożonej w komplecie z ECMA 2015 Specification, mogą być one nigdy przeznaczone taka metoda, ale można zrobić coś takiego:

var a = new Set([1, 2, 3]); 
a.add(10); 
var lastValue = Array.from(a).pop(); 

Edit:

na drugim myśli, przestrzeń skutecznym rozwiązaniem może być:

function getLastValue(set){ 
    var value; 
    for(value of set); 
    return value; 
} 

var a = new Set([1, 2, 3]); 
a.add(10); 
console.log('last value: ', getLastValue(a)); 
+0

Czy nie ma wbudowanego rozwiązania stałego czasu? –

+0

@hege_hegedus niestety nie, przynajmniej nie mogę znaleźć żadnego w specyfikacjach :( – mido

+1

Zaczynam podejrzewać, że narzut na konwersję 'set' z powrotem na' tablicę' W przypadku dużego zbioru może on, ale nie musi, wykazywać pewne koszty Jednak ma to sens, że '.last' nie jest zawarty w specyfikacji, ponieważ teoretycznie zestaw nie potrzebuje kolejności –

2
indexOfLastItem=s.length-1; 

return(s[indexOfLastItem]); 
+5

Obawiam się, że to nie jest kod JavaScript. Ale teraz jestem ciekawy: w jakim języku jest "długość" zestawu (lub tablicy) funkcji gettera? –

+0

http://www.w3schools.com/jsref/tryit.asp?filename=tryjsref_length_string – Themer

+2

@Themer, którego kod używa '.length', bez'() '. To własność, a nie funkcja. –

10

Tak, istnieje sposób, aby to zrobić, można po prostu przekonwertować zestaw do tablicy i pop ostatniego elementu

function getLastItem(_set) { 
    return [..._set].pop(); 
} 

dostać klucze/wartości etc, można zrobić

return [..._set.entries()].pop(); // the entire entry 
return [..._set.keys()].pop(); // the key only 
return [..._set.values()].pop(); // the value only 

Jeśli nie chcesz, aby utworzyć tablicę, to prawdopodobnie masz do iteracji i dostać ostatnią wartość, tak

var last; s.forEach(k => { last = k }); // last === "Beta" 

FIDDLE

+0

Bardzo podoba mi się użycie rozpowszechnianej składni tutaj –

+0

@hege_hegedus - Nie zauważyłem mido najpierw odpowiedziałem i wysłałem to samo, więc pomyślałem, że będę musiał wymyślić coś co najmniej trochę innego, operator rozprzestrzeniania się i jak uzyskać wszystkie wpisy, klucze itp., wydaje się wystarczający, aby nie opublikować dokładnie – adeneo

+0

Jestem po prostu ciekawy: czy istnieje krótka składnia do wyczerpania iteratora i uzyskania ostatniego elementu bez budowania listy? (mam na myśli krótsze niż pisanie oddzielnej funkcji dla tego zadania) –

12

Kilka pomysłów:

  • rozważyć użycie tablicę zamiast zestawu. Wyodrębnianie ostatniego elementu tablicy jest łatwe, np.

    array[array.length-1]; 
    array.slice(-1)[0]; 
    array.pop(); // <-- This alters the array 
    

    Jeśli naprawdę potrzebujesz zestawu, można przekonwertować je do tablicy, gdy chcemy wyodrębnić ostatni element, ale to kosztuje czas i przestrzeń.

  • Powtórzyć zestaw ręcznie. Będzie to kosztować czas, ale nie tyle miejsca, ile kopiowanie do tablicy. Na przykład (prawdopodobnie istnieją bardziej elegancki sposób to zrobić)

    var set = new Set([1, 2, 3]); 
    var iter = set.values(), prev, curr; 
    do { 
        prev = curr; 
        curr = iter.next(); 
    } while(!curr.done) 
    var last = prev.value; // 3 
    
  • rozważyć wstawienie elementów w odwrotnej kolejności. Potem trzeba tylko uzyskać pierwszą pozycję w zestawie, a to ułatwi:

    set.values().next().value; 
    
  • Podklasa Set aby dodać nową funkcjonalność:

    class MySet extends Set { 
        add(value) { 
        super.add(value); 
        this.last = value; 
        } 
    } 
    var set = new MySet(); 
    set.add(1); set.add(2); set.add(3); 
    set.last; // 3 
    

    Uwaga ta wykryje tylko wartości dodanej z add.Aby być bardziej kompletnym, powinien także wykryć ostatnią wartość, gdy zestaw jest zbudowany, i zaktualizować wartość, gdy ostatni element zostanie usunięty.

3

To kolejne podejście.

Set.prototype.last = function(){ 
    return new Set().add([...this].pop()); 
} 

Set.prototype.lastKey = function(){ 
    return [...this.keys()].pop(); 
} 

Set.prototype.lastValue = function(){ 
    return [...this.values()].pop(); 
} 

var lastSet = s.last(); // "Beta" 
var lastKey = s.lastKey(); // "Beta" 
var lastValue = s.lastValue(); // "Beta" 
+0

Zauważ, że 's.last()', zdefiniowane jako 'nowy zestaw(). Add ([. ..this] .pop()); 'w tej odpowiedzi zwraca' Set {"Beta"} ', a nie' "Beta" ' – runsun

1

Stworzyłem zastępstwo dla Set, która ponownie implementuje funkcjonalność związaną z zestawu, przy użyciu stanowiącego podstawę Map.

class LinkedSetLink { 
 
    constructor(value) { 
 
    this.value = value; 
 
    this.prev = this; 
 
    this.next = this; 
 
    } 
 
    
 
    insertBefore(item) { 
 
    const prev = item.prev = this.prev; 
 
    const next = item.next = this; 
 
    next.prev = item; 
 
    prev.next = item; 
 
    } 
 
    
 
    remove() { 
 
    const prev = this.prev; 
 
    const next = this.next; 
 
    next.prev = prev; 
 
    prev.next = next; 
 
    } 
 
} 
 

 

 
class LinkedSet { 
 
    constructor(iterable) { 
 
    this._map = new Map(); 
 
    this._pivot = new LinkedSetLink(/* undefined */); 
 
    if (iterable) { 
 
     this._addAll(iterable); 
 
    } 
 
    } 
 

 
    _addAll(iterable) { 
 
    for (const item of iterable) { 
 
     this.add(item); 
 
    } 
 
    } 
 

 
    has(item) { 
 
    return this._map.has(item); 
 
    } 
 

 
    add(item) { 
 
    if (!this._map.has(item)) { 
 
     const link = new LinkedSetLink(item); 
 
     this._pivot.insertBefore(link); 
 
     this._map.set(item, link); 
 
    } 
 
    } 
 

 
    delete(item) { 
 
    const link = this._map.get(item); 
 
    if (link) { 
 
     this._map.delete(item); 
 
     link.remove(); 
 
    } 
 
    } 
 

 
    clear() { 
 
    this._map.clear(); 
 
    this._pivot.next = this._pivot.prev = this._pivot; 
 
    } 
 

 
    get size() { 
 
    return this._map.size; 
 
    } 
 

 
    values() { 
 
    return this._map.keys(); 
 
    } 
 

 
    keys() { 
 
    return this.values(); 
 
    } 
 

 
    [Symbol.iterator]() { 
 
    return this.values(); 
 
    } 
 

 
    *entries() { 
 
    for (const key of this.values()) { 
 
     yield [key, key]; 
 
    } 
 
    } 
 

 
    first() { 
 
    return this._pivot.next.value; 
 
    } 
 

 
    last() { 
 
    return this._pivot.prev.value; 
 
    } 
 
} 
 

 
function test1() { 
 
    console.log(Array.from(new LinkedSet(["a", "b", "c"]).entries())); 
 
} 
 
function test2() { 
 
    console.log(new LinkedSet(["a", "b", "c"]).last()); 
 
}
<button onclick="test1()">test entries</button> 
 
<button onclick="test2()">test last</button>

Powiązane problemy