извлечь/срез / изменить порядок списков в (emacs) lisp?

в python вы можете сделать что-то вроде

i = (0, 3, 2)
x = [x+1 for x in range(0,5)]
operator.itemgetter(*i)(x)

и (1, 4, 3). В (emacs) lisp я написал эту функцию под названием extract, которая делает что-то подобное,

(defun extract (elems seq)
  (mapcar (lambda (x) (nth x seq)) elems))

(extract '(0 3 2) (number-sequence 1 5))

но я чувствую, что должно быть что-то встроено? Все, что я знаю, это first, last, rest, nth, car, cdr... Какой путь выбрать? ~ Заранее спасибо ~

3 ответов


Если ваша проблема-скорость, то используйте (вектор 1 2 3 4 5) вместо списка и (индекс aref vec), чтобы получить элемент.

(defun extract (elems seq)
  (let ((av (vconcat seq)))
    (mapcar (lambda (x) (aref av x)) elems)))

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


я делал только простые скрипты в elisp, но это относительно небольшой язык. И extract - очень неэффективная функция в связанных списках, которая является структурой данных по умолчанию в Emacs lisp. Так что вряд ли он встроенный.

ваше решение является лучшим простым. Это n^2, но чтобы сделать его быстрее, требуется намного больше кода.

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

  1. вроде elems (n log n)
  2. создайте карту, которая отображает элементы в отсортированном elem к их индексам в оригинальной elem (возможно N log n, возможно n)
  3. перебираем seq и отсортированный elem. Храните только индексы в sorted elem (возможно, n, возможно, N log n, в зависимости от того, является ли это хэш-картой или картой дерева)
  4. сортировать результат по значениям elem отображение (N log n)

с мой опыт Lisp и развитие GNU Emacs:

в те дни, в 1985 году, были люди, у которых были одномегабайтные машины без виртуальной памяти. Они хотели иметь возможность использовать GNU Emacs. Это означало, что программа должна быть как можно меньше.

например, в то время единственной конструкцией цикла было "while", что было чрезвычайно просто. Не было никакого способа вырваться из заявления "while", вам просто нужно было сделать уловка и бросок или проверка переменной, которая запускает цикл. Это показывает, как далеко я продвинулся, чтобы держать вещи маленькими. У нас не было "каар", "кадр" и так далее; "выжать все возможное" было духом GNU Emacs, духом Emacs Lisp, с самого начала.

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

Так что мой думаю, если вы его не видите, его там нет.