извлекать / вырезать / переупорядочивать списки в (emacs) lisp? - PullRequest
6 голосов
/ 25 мая 2010

В 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 ]

4 голосов
/ 25 мая 2010

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

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

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

2 голосов
/ 25 мая 2010

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

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

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

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

С Мой опыт работы с Lisp и разработка GNU Emacs :

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

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

Очевидно, что машины теперь больше, и мы так больше не делаем. Мы вставляем 'caar' и 'cadr' и так далее, и мы можем вставить другую циклическую конструкцию на днях.

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

...