23

One thing I find myself missing in emacs lisp is, surprisingly, a particular bit of list manipulation. I miss Python's concise list slicing.

>>> mylist = ["foo", "bar", "baz", "qux", "frobnitz"]
>>> mylist[1:4]
['bar', 'baz', 'qux']

I see the functions butlast and nthcdr in the emacs documentation, which would give the same results from code like this:

(setq mylist '("foo" "bar" "baz" "qux" "frobnitz"))
(butlast (nthcdr 1 mylist) 1)
;; ("bar" "baz" "qux")

Is there a more concise way of getting a list slice than combining butlast and nthcdr?

Brighid McDonnell
  • 4,293
  • 4
  • 36
  • 61
  • 3
    related: http://stackoverflow.com/questions/108169/how-do-i-take-a-slice-of-a-list-a-sublist-in-scheme - the third answer recommends subseq which is a slice; no idea if it is available in emacs lisp though... – l4mpi Nov 01 '12 at 20:02
  • 1
    Ahah! That's exactly what I was looking for, thank you. `subseq` is, like many other Nice Things, available through emacs's `clmacs.el`. Also, calling it "subseq" is probably why I came up blank Googling for this - I've had terminology issues like that more than once with emacs. Want to make an answer so I can accept it? – Brighid McDonnell Nov 01 '12 at 20:14
  • 4
    Don't forget that Python `list`s are arrays, while Lisp's are linked lists, so the performance characteristics are very different. If you need to do lots of indexing and subsequencing, especially if the lists can be long, you should be using a different type in Lisp. (For example, a Python slice `mylist[x:y]` is `O(y-x)`, while a Lisp equivalent is `O(y)`: for `mylist[50000,50005]` this means List will be 10000x slower…) – abarnert Nov 01 '12 at 20:27
  • Thanks for that clarification, abarnert. Fortunately the problem at hand has lists of manageable size. I'd probably try changing them to vectors if they got larger. – Brighid McDonnell Nov 01 '12 at 20:55
  • @SeanM `subseq` is not bad Emacs terminology, it's how Common Lisp calls the function. Common Lisp sequences are ordered collections of elements, which can be implemented as either lists of vectors, analogous to the abstraction that Python also calls sequence. – user4815162342 Nov 01 '12 at 21:49
  • @user4815162342: I didn't mean that it was bad. By "terminology issues" I meant that I've had several incidents where I was looking for a concept under one name and emacs/lisp knows that concept by another name. – Brighid McDonnell Nov 01 '12 at 22:25

2 Answers2

23

Sure there is:

(require 'cl-lib)
(setq mylist '("foo" "bar" "baz" "qux" "frobnitz"))
(cl-subseq mylist 1 4)
;; ("bar" "baz" "qux")

In modern Emacs, please note cl is deprecated see In Emacs, what does this error mean? "Warning: cl package required at runtime"

CT Zhu
  • 52,648
  • 17
  • 120
  • 133
Bozhidar Batsov
  • 55,802
  • 13
  • 100
  • 117
5

Common Lisp library is great, but if your codebase becomes large and you want to write concise code in functional style, I endorse dash.el library, which provides enormous amount of functions for list and tree manipulations. There is a function -slice that behaves just like Python's slicing:

(-slice (number-sequence 1 10) 1 7 2) ; (2 4 6)

Arguments are in order: list, start, (optional) stop, (optional) step.

Mirzhan Irkegulov
  • 17,660
  • 12
  • 105
  • 166