Как я могу получить элемент по индексу из упорядоченной таблицы в Nim?

#nim-lang

#nim-lang

Вопрос:

В Nim есть OrderedTable как я могу получить элемент по его индексу, а не по его ключу?

Если это возможно — это эффективная операция, как O(log n) или лучше?

 import tables
let map = {"a": 1, "b": 2, "c": 3}.toOrderedTable
  

Что-то вроде

 map.getByIndex(1) # No such method
  

Постскриптум

В настоящее время я использую оба seq и Table для предоставления доступа как по ключу, так и по индексу и задаюсь вопросом, можно ли заменить его на OrderedTable

 type IndexedMap = ref object
  list*: seq[float]
  map*:  Table[string, float]
  

Ответ №1:

Прямой доступ по индексу к упорядоченным таблицам отсутствует из-за их внутренней структуры. Типичный способ доступа к элементам по порядку -:

 import tables

let map = {"a": 1, "b": 2, "c": 3}.toOrderedTable

for f in map.keys:
  echo $f
  

В основном, доступ к итератору ключей. Если вы перейдете по ссылке на исходный код в документации, вы получите фактический код итератора:

   let L = len(t)
  forAllOrderedPairs:
    yield t.data[h].key
  

И если вы будете следовать реализации шаблона forAllOrderedPairs (рекомендуется использовать редактор с возможностями перехода к реализации, чтобы упростить проверку такого кода):

   if t.counter > 0:
    var h = t.first
    while h >= 0:
      var nxt = t.data[h].next
      if isFilled(t.data[h].hcode):
        yieldStmt
      h = nxt
  

Понятия не имею о производительности там, но это будет не так быстро, как доступ к простому списку / массиву, потому что внутренняя структура OrderedTable содержит скрытое data поле с фактическими ключами и значениями, и требуется дополнительная условная проверка, чтобы убедиться, что запись действительно используется. Эта деталь реализации, вероятно, является компромиссом, позволяющим избежать перетасовки всего списка после удаления одного элемента.

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

Или вернитесь к своей первоначальной идее ведения отдельного списка.