0

Q:   I have a list of strings: '("apple" "pear" "peach" "nectarine" "watermelon"). How can I replace "peach" with "plum" and maintain the same order of fruits?  [CAVEAT: The list may be very long and the nth position of the element to be replaced will not be known at the outset.]

BACKBROUND:

I am working on implementing wdired compatibility with a dired-mode listing of files created by calling:

(dired (directory-files-recursively "/path/to/directory" "" 'include-directories))

This creates a listing of absolute paths to files and directories. After modifying the wdired buffer, and pressing the command to finalize/commit the edits, here is what happens:

  1.  The files get renamed correctly using a revised version of wdired-get-filename, thanks to the assistance of @Drew in a related thread: Dired / Wdired: How to test whether a filename is relative / absolute . [The renaming of directories (if applicable) will be dealt with by me on another day.]

  2.  dired-readin-insert does not work correctly to populate the buffer anew because the variable dired-directory was not updated with the new absolute path of the files that got renamed.

    /path/to/bin/gls: cannot access '/path/to/filename': No such file or directory

There will undoubtedly be additional hurdles to implement this new wdired feature, so I understand this will be one baby step at a time. To resolve this particular question, I am looking for something a little fancier than delete and push/add-to-list. Specifically, I would like to programmatically replace the old filename with the new filename and maintain the same list order.


EDIT:  Here is a link to the bug-report seeking an enhancement of wdired and dired: http://debbugs.gnu.org/cgi/bugreport.cgi?bug=31601

3
  • 1
    You might want to retitle or rephrase your question, based on your answer. The answer is purely about replacing an element of a list of strings. It doesn't refer to Dired or Wdired or default-directory at all.
    – Drew
    Commented May 25, 2018 at 15:08
  • @Drew -- thank you for taking a look at this thread. I was looking for a couple of things with this question: (1) a quick solution to get me over over the hurdle, which the answer by @Andreas Röhler does well; and, (2) verification that dired-mode does not presently have the ability to update the dired-directory variable when a user renames a file in a buffer containing a recursive list of files in various subdirectories. I tried to rename a file in a dired-mode buffer also in Emacs 26 using the recursive listing of files as indicated in the question, and the variable is not updated.
    – lawlist
    Commented May 25, 2018 at 21:49
  • @Drew -- just a follow-up to let you know that adding (when (and (listp dired-directory) (member file dired-directory)) (setq dired-directory (ar-replace--in-list file newname dired-directory))) to dired-rename-file fixes the issue desribed in #2 of the question above. I would imagine that this will need to be added to other aspects of dired such as deleting a file; and, there may be an issue with speed/performance. Perhaps a hash-table system would be better suited to this type of job. I'll submit an enhancement request to the Emacs team.
    – lawlist
    Commented May 26, 2018 at 4:17

1 Answer 1

1
(setq mylist '("apple" "pear" "peach" "nectarine" "watermelon"))

(defun ar-replace--in-list (elem replacement list)
  "Expects a LIST of strings.
ELEM: element to replace by arg REPLACEMENT"
  (let (newlist)
    (dolist (ele list)
      (push (if (string= ele elem) replacement ele) newlist))
    (nreverse newlist)))

So let's replace pear by cherry:

(ar-replace--in-list "pear" "cherry" mylist)

==>

("apple" "cherry" "peach" "nectarine" "watermelon")

Lists may contain other kind of elements than strings:

(defun ar-replace--in-list (pred elem replacement list)
  "Expects a LIST whose type must fit to arg PRED.
PRED: a function to select ELEM
ELEM: element to replace by arg REPLACEMENT"
  (let (newlist)
    (dolist (ele list)
      (push (if (funcall pred ele elem) replacement ele) newlist))
    (nreverse newlist)))

Call for this example:

(ar-replace--in-list 'string= "pear" "cherry" mylist)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.