Получить последнее значение, вставленное в набор

Документация MDN для Set говорит о том, что JavaScript Set объекты сохраняют порядок вставки элементов:

Заданные объекты являются коллекциями значений, вы можете перебирать их элементы в порядке вставки.

Есть ли способ вставить последний элемент в Set объект?

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

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

редактировать

Возможно реализовать класс контейнера структуры данных Linked Set, который имеет тот же интерфейс, что и Set и имеет желаемую возможность. Смотрите мой ответ ниже.

9 ответов

Решение

Мне не удалось найти какой-либо метод для получения последнего значения, вставленного в набор из спецификации ECMA 2015, возможно, они никогда не предполагали такой метод, но вы можете сделать что-то вроде:

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

Редактировать:

Вторая мысль: эффективное решение может быть:

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));

Некоторые идеи:

  • Рассмотрите возможность использования массива вместо набора. Извлечь последний элемент массива легко, например

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

    Если вам действительно нужен набор, вы можете преобразовать его в массив, когда вы хотите извлечь последний элемент, но это будет стоить времени и пространства.

  • Повторите набор вручную. Это будет стоить времени, но не так много места, как копирование в массив. Например (есть, вероятно, более элегантные способы сделать это)

    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
    
  • Попробуйте вставить элементы в обратном порядке. Тогда вам нужно только получить первый предмет в наборе, и это проще:

    set.values().next().value;
    
  • Подкласс Set чтобы добавить эту новую функциональность:

    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
    

    Обратите внимание, что это будет обнаруживать только значения, добавленные с add, Чтобы быть более полным, он также должен определять последнее значение при создании набора и обновлять значение при удалении последнего элемента.

Да, есть способ сделать это, вы можете просто преобразовать набор в массив и всплеск последнего элемента

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

чтобы получить ключи / значения и т.д., вы можете сделать

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

Если вы не хотите создавать массив, вам, вероятно, придется выполнить итерацию и получить последнее значение, например

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

FIDDLE

Просто другой подход.

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"

Я создал замену для Set, который повторно реализует связанную функциональность набора, используя базовый 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>

indexOfLastItem=s.length-1;

return(s[indexOfLastItem]);

Простое решение, ноO(N):

      const getLastValueFromSet = (set) => {
    for (var value of set);
    return value;
}

Метода доступа к последнему элементу нет, но вы можете сделать это следующим образом.

      let setOfNumbers = new Set([10]);
setOfNumbers.add(20).add(2);
let lastValue = [...setOfNumbers].pop()

Как упоминалось ранее, для этого есть много способов.

Если вы хотите изменить основное значение переменной в памяти:

s = new Set()
s.add('banana')
s.add('apple')

//acts like array.pop()
// removes the first item in the set
s.delete(s.values().next().value)
Другие вопросы по тегам