4

I have this list:

(setq MYLIST '("J. Phys."
               "New. J. Phys." 
               "J. Phys. Soc. Jap."
               "Phys. Plasmas"))

How can I get a new list ordered by the decreasing length of the strings? :

("J. Phys. Soc. Jap."
 "New. J. Phys."
 "Phys. Plasmas"
 "J. Phys.")

ADDENDUM. It happens that when I try the DoMiNeLa10 answer on a 232 element list I get a 130 list. 102 of them goes lost (they are not duplicates). If you need my list as a file please tell me how can I share it.

You can find my list here: MYLIST.

Gabriele Nicolardi
  • 1,199
  • 8
  • 17
  • @DoMiNeLa10 's answer is correct, you need to use the result of the function: `(setq MYLIST (my-sort-decreasing-length MYLIST))` - without this a reference to the original list may loose elements. – ideasman42 Sep 20 '21 at 11:06

2 Answers2

5

You can write a function which uses sort and pass it a predicate that compares lengths:

(defun my-sort-decreasing-length (list)
  (sort list
        (lambda (a b)
          (> (length a) (length b)))))

Note that the result of this function must be used as the new list.

(setq some-list (my-sort-decreasing-length some-list))
ideasman42
  • 8,375
  • 1
  • 28
  • 105
  • 2
    Note that `sort` destructively modifies the `list`, so you should usually pass it through `copy-sequence` first. – Basil Feb 18 '18 at 15:04
  • 1
    What @Basil said. And if you are OK with the list-structure modification and you have a variable that points to the original list, and you want it to also point to the modified list, then you need to _assign it to the result_ of using `sort`: `(setq mylist (my-sort mylist))`. – Drew Feb 18 '18 at 16:13
  • I cannot accept your answer because of an issue with long lists. Please see my edit to the question. – Gabriele Nicolardi Feb 18 '18 at 20:29
  • Suggest to mark this as the correct answer. Updated it to avoid confusion. – ideasman42 Sep 20 '21 at 14:08
5

See DoMiNeLa10's answer for the canonical answer.

On Emacs 25 and later, however, and if you don't care about sheer performance, there is a way to save yourself some typing:

(require 'seq)
(seq-sort-by #'length #'> MYLIST)

or

(seq-sort-by #'string-width #'> MYLIST)

should you care about displaying the strings.

Basil
  • 12,019
  • 43
  • 69
  • Anyone care to explain the downvote? – Basil Feb 18 '18 at 16:15
  • (downvote not mine). Can you please take a look my edited part of the question? – Gabriele Nicolardi Feb 18 '18 at 20:32
  • @GabrieleNicolardi Have you tried using `copy-sequence` as I mention in [my comment](https://emacs.stackexchange.com/questions/38897/sort-list-by-decreasing-length-of-the-strings/38903?noredirect=1#comment61374_38902) to DoMiNeLa10's answer? I.e. like so: https://pastebin.com/raw/70G6CeRG – Basil Feb 18 '18 at 20:36
  • @GabrieleNicolardi Otherwise, try using my suggestion which automatically does this for you. – Basil Feb 18 '18 at 20:36
  • @GabrieleNicolardi If either of these suggestions fix the issue, then you should consider reaccepting DoMiNeLa10's answer with the `copy-sequence` caveat. – Basil Feb 18 '18 at 20:38
  • The `seq-sort-by` solution works fine. I tried with `copy-sequence` and the DoMiNeLA10's solution by I've not been able to make it work. – Gabriele Nicolardi Feb 18 '18 at 20:49
  • @GabrieleNicolardi Glad it works, but it's *very* strange that using `copy-sequence` doesn't make DoMiNeLa10's solution work. Are you sure you re-evaluated the function after adding `copy-sequence`? – Basil Feb 18 '18 at 20:59
  • Once again, you're right. I didn't understand the behaviour of (copy-sequence). Now it works. It think I should reaccept the DoMiNeLa10 answer... but it needs to be updated with you caveat, otherwise it doesn't work (at least in my case). – Gabriele Nicolardi Feb 18 '18 at 22:13