extracting a n element from a list with dolist on lisp - linux

I am trying to create a function where it takes a list of letters as parameter and a single letter as a parameter. I want to remove the single letter from the list.
(defun extract-all (lett li)
(let ((new-list nil))
(dolist (letter li new-list)
(if (eql lett letter)
(setf new-list (cons nil new-list))
(setf new-list (cons letter new-list))))))
so if I call the function with (extract-all 'n '(i n t e l l)), I want it to return i t e l l with the n removed.

First of all, you are not removing letters
(characters), but rather
symbols:
(type-of 'n)
==> SYMBOL
Second, there is a standard function remove to do just that:
(remove 'n '(i n t e l l))
==> (I T E L L)
Third, if you remove your "then" clause and reverse the result, you will get what you want:
(defun my-remove (object list)
(let ((new-list nil))
(dolist (element list (nreverse new-list))
(unless (eql object element)
(push element new-list)))))
(my-remove 'n '(i n t e l l))
==> (I T E L L)
Note that there are more ways to skin the cat, e.g.,
(defun my-remove (object list)
(loop for element in list
unless (eql object element)
collect element))
However, it is always best to use the library.
See also Where to learn how to practically use Common Lisp.

Related

Check are there lowercase characters in string

I need return True or False
True if at least one lowercase character
False no lowercase characters
I tried do it with loop and lambda function
Something like this
(defun check-lower-word (word)
(loop
for ch across word
((lambda (c) (if (lower-case-p c) return T) ch)
)
)
I need False if never worked "if"
With a predefined function, you could use some (manual):
CL-USER> (some #'lower-case-p "AbC")
T
CL-USER> (some #'lower-case-p "ABC")
NIL
There is a similar operation for the loop syntax (manual):
CL-USER> (loop for x across "AbC" thereis (lower-case-p x))
T
CL-USER> (loop for x across "ABC" thereis (lower-case-p x))
NIL
Finally, note that loop always returns nil when the iteration terminates without producing a result, so a less concise use of loop could be:
CL-USER> (loop for x across "AbC" if (lower-case-p x) do (return t))
T
CL-USER> (loop for x across "ABC" if (lower-case-p x) do (return t))
NIL
Code errors
You code is not balanced with respect to parentheses, there is a missing closing parenthesis at the end:
(defun check-lower-word (word)
(loop
for ch across word
((lambda (c) (if (lower-case-p c) return T) ch)
)
) ; <-- closes "(loop"
The syntax error in your loop should have raised an error, it does not make sense to write an expression EXPR directly in (loop for c across w EXPR), there should be a preceding do.
The literal ((lambda (c) E) ch) can be directly written as E where every occurence of the variable c is substituted by ch, namely:
(if (lower-case-p ch) return T)
The use of an intermediate literal lambda brings nothing here.
Also, the above reads as: if ch is lowercase, the value of the if is the value bound to the return variable, otherwise it is T. You are indeed missing parens around (return T). A "one-armed" (if T X) is best written as (when T X).
Another approach
You already have an example with some and loop, you can also use a short-circuiting map:
(defun check-lower-word (word)
(block nil
(map ()
(lambda (c)
(when (lower-case-p c)
(return t)))
word)))
A call to MAP with nil as a first argument means the sequence is iterated for effects and returns nil. For each character in the sequence (list or vector), when the character is lower-case, return T. The return exits the iteration early up to the NIL block.
I did it as
(defun check-lower-word (word)
(block outer
(loop
for ch across word do
(if (lower-case-p ch) (return-from outer T))
)
)
)

How to modify string by index in Clojure?

I want to modify a string by applying a function to some of its chars (by starting index and length).
For example, I want to increment the ascii representation of the string "aaaaa" from the 2nd index to the 4th.
[start=1 length=3]
"aaaaa" => "abbba"
The only way I could think of is applying map, but it goes over all the sequence.
You could use subs to get the portions you do and don't want to modify. After modification use str to concatenate the result together:
(defn replace-in-str [f in from len]
(let [before (subs in 0 from)
after (subs in (+ from len))
being-replaced (subs in from (+ from len))
replaced (f being-replaced)]
(str before replaced after)))
You can call it:
(replace-in-str
(fn [sub-str] (apply str (map #(char (+ 1 (int %))) sub-str)))
"aaaaa"
1
3)
Indeed map applies the function to every element in the sequence. One way to get around that is to start with map-indexed. Unlike map, map-indexed passes the element's index as the first argument to the mapping function. When we have element's index, we can use it to choose if we need to perform the operation or just return the element as is.
A solution might look like this:
(defn inc-char [c]
(char (inc (long c))))
(defn if-in-range [from to f]
(fn [i x & args]
(if (<= from i (dec to))
(apply f x args)
x)))
(defn map-subs [from to f s]
(apply str (map-indexed (if-in-range from to f) s)))
(map-subs 1 4 inc-char "aaaaa")
;; "abbba"
I thought of using map-index to execute the operation only on the specified index:
((fn [op start length] (map-indexed (fn [i m] (if (<= start i length)
(op m)
m)) "aaaaa"))
#(char (+ 1 (int %)))
1
3)
=> (\a \b \b \b \a)
Here you go:
(defn replace-str
[s start-i end-i]
(apply str (map-indexed (fn [index val]
(if (and (>= index start-i)
(<= index end-i))
(char (+ (int val) 1))
val))
s)))
(replace-str "aaaa" 1 2)
;=> "abba"

A Replace Function in Lisp That Duplicates Mathematica Functionality

What is the easiest way to accomplish the following in a Mathematica clone or in any version of Lisp(any language is probably okay actually even Haskell)? It doesn't appear any lisps have a similar replace function.
Replace[{
f[{x, "[", y, "]"}],
f#f[{x, "[", y, y2, "]"}]
}
, f[{x_, "[", y__, "]"}] :> x[y],
Infinity]
and a return value of {x[y], f[x[y, y2]]}
It replaces all instances of f[{x_, "[", y__, "]"}] in args where x_ represents a single variable and y__ represents one or more variables.
In lisp the function and replacement would probably be the equivalent(forgive me I am not the best with Lisp). I'm looking for a function of the form (replace list search replace).
(replace
'(
(f (x "[" y "]"))
(f (f '(x "[" y y2 "]")))
)
'(f (x_ "[" y__ "]"))
'(x y)
)
and get a return value of ((x y) (f (x y y2))).
Let's give it another try.
First, install quicklisp and use it to fetch, install and load optima and alexandria.
(ql:quickload :optima)
(ql:quickload :alexandria)
(use-package :alexandria)
The functions from alexandria referenced below are ensure-list and last-elt. If you don't have them installed, you can use the following definitions:
(defun ensure-list (list) (if (listp list) list (list list)))
(defun last-elt (list) (car (last list)))
We define rules as functions from one form to another.
Below, the function tries to destructure the input as (f (<X> "[" <ARGS> "]"), where <ARGS> is zero or more form. If destructuring fails, we return NIL (we expect non-matching filters to return NIL hereafter).
(defun match-ugly-funcall (form)
(optima:match form
((list 'f (cons x args))
(unless (and (string= "[" (first args))
(string= "]" (last-elt args)))
(optima:fail))
`(,x ,#(cdr (butlast args))))))
(match-ugly-funcall '(f (g "[" 1 3 5 4 8 "]")))
; => (G 1 3 5 4 8)
Then, we mimic Mathematica's Replace with this function, which takes a form and a list of rules to be tried. It is possible to pass a single rule (thanks to ensure-list). If a list of list of rules is given, a list of matches should be returned (to be done).
(defun match-replace (form rules &optional (levelspec '(0)))
(setf rules (ensure-list rules))
(multiple-value-bind (match-levelspec-p recurse-levelspec-p)
(optima:ematch levelspec
((list n1 n2) (if (some #'minusp (list n1 n2))
(optima:fail)
(values (lambda (d) (<= n1 d n2))
(lambda (d) (< d n2)))))
((list n) (if (minusp n)
(optima:fail)
(values (lambda (d) (= d n))
(lambda (d) (< d n)))))
(:infinity (values (constantly t) (constantly t))))
(labels
((do-replace (form depth)
(let ((result
(and (funcall match-levelspec-p depth)
(some (lambda (r) (funcall r form)) rules))))
(cond
(result (values result t))
((and (listp form)
(funcall recurse-levelspec-p depth))
(incf depth)
(do (newlist
(e (pop form) (pop form)))
((endp form) (values form nil))
(multiple-value-bind (result matchedp) (do-replace e depth)
(if matchedp
(return (values (nconc (nreverse newlist)
(list* result form)) t))
(push e newlist)))))
(t (values form nil))))))
(do-replace form 0))))
And a test:
(match-replace '(a b (f (x "[" 1 2 3 "]")) c d)
#'match-ugly-funcall
:infinity)
; => (A B (X 1 2 3) C D)
; T
In order to replace all expressions instead of the first matching one, use this instead:
(defun match-replace-all (form rules &optional (levelspec '(0)))
(setf rules (ensure-list rules))
(multiple-value-bind (match-levelspec-p recurse-levelspec-p)
(optima:ematch levelspec
((list n1 n2) (if (some #'minusp (list n1 n2))
(optima:fail)
(values (lambda (d) (<= n1 d n2))
(lambda (d) (< d n2)))))
((list n) (if (minusp n)
(optima:fail)
(values (lambda (d) (= d n))
(lambda (d) (< d n)))))
(:infinity (values (constantly t) (constantly t))))
(labels
((do-replace (form depth)
(let ((result
(and (funcall match-levelspec-p depth)
(some (lambda (r) (funcall r form)) rules))))
(cond
(result result)
((and (listp form)
(funcall recurse-levelspec-p depth))
(incf depth)
(mapcar (lambda (e) (do-replace e depth)) form))
(t form)))))
(do-replace form 0))))
Oh boy, how Mathematica manages to obfuscate everything by applying its renown NIH approach.
Basically, you're looking for a function to perform string replacement according to some pattern. In most languages, this is accomplished with regular expressions.
For instance, in Common Lisp using the cl-ppcre library it will look something like this:
(cl-ppcre:regex-replace-all
;; regular expression you match against with groups
"f\\[{(x[^ ]*), \"\\[\", ((y[^ ]* ?)+), \"\\]\"}\\]"
;; your string
"{f[{x, \"[\", y, \"]\"}], f#f[{x, \"[\", y, y2, \"]\"}]}"
;; substitution expression using groups 1 & 2
"\\1[\\2]")
Surely, you can write a specialized 20-line function for this problem of matching and substituting subtrees using subst and recursion, but if all that you want is cases similar to the presented one you can get away with a simple regex-based approach.

How to get the last element of a list and return nil if the element isn't in the list

I would like to get the position of any element in the list and get nil if the element isn't in the list. I did:
(defun myposition (letter list)
(cond
((atom list) nil)
((equal (car list) letter) 0)
((null (car list)) (myposition letter))
(t (1+ (myposition letter (cdr list)))) ) )
(myposition 'k '(g h i j k l)
4
(myposition 'p '(g h i j k l)
nil is not a number
When I replace ((atom list) nil) par ((atom list) 0), I get 6 instead nil
(myposition 'p '(g h i j k l)
6
In your first example, your function will recursively compute 1+1+1+1+0 = 4 to find the correct result.
In your second example, it will run through the whole list, add 1 per (non-matching) element, and finally add nil. So it actually computes 1+1+1+1+1+1+nil, which is incorrect since nil is not a number, hence the error message. If you replace nil by zero, it computes 1+1+1+1+1+1+0 which is wrong.
So your basic problem is that you recursively add 1 and, reaching the end of the list, you would like to throw away what you computed until then. But you have an addition pending which you cannot escape.
The easiest way is to change from a recursive to a tail-recursive solution, which is technically a plain goto. Here the addition is done by incrementing a variable, not by unwinding the call stack, which makes it easy to throw away the result from the previous additions and just return nil because there is no addition pending.
A (tail-)recursive solution could be:
(defun myposition (letter lst)
(labels ((sub (lst pos)
(cond
((null lst) nil)
((equal (car lst) letter) pos)
(t (sub (cdr lst) (1+ pos))))))
(if (atom lst) nil (sub lst 0))))
This will work in Common Lisp, but technically, if your implementation does no tail call optimisation, it might still blow the stack for large lists. That's why Common Lisp prefers iterative solutions, such as using the loop macro:
(defun myposition (letter lst)
(when (consp lst)
(loop for c in lst for i from 0
when (equal c letter) return i)))

LISP - Modify String

I have to write a program that changes a string's vowels, consonants and other symbols into C, V respectively 0. I've done this but I wonder if there is a more efficient and elegant way to do it. Would appreciate input.
(defun string-to-list (string)
(loop for char across string collect char))
(defun is-vowel (char) (find char "aeiou" :test #'char-equal))
(defun is-consonant (char) (find char "bcdfghjklmnpqrstvwxyz" :test #'char-equal))
(defun letter-type (char)
(if (is-vowel char) "V"
(if (is-consonant char) "C"
"0")))
(defun analyze-word (word-string)
(loop for char across word-string collect (letter-type char)))
Moreover, I would like to make it a string, how could I do that? Should I define a function that would iterate through the list and make it a string or is it an easier way to do it?
(defun letter-type (char)
(cond ((find char "aeiou" :test #'char-equal) #\V)
((alpha-char-p char) #\C)
(t #\0)))
CL-USER> (map 'string #'letter-type "analyze-word")
"VCVCCCV0CVCC"
Just for the sake of the idea:
(defun multi-replace-if (sequence function &rest more-functions)
(map (type-of sequence)
(lambda (x)
(loop for f in (cons function more-functions)
for result = (funcall f x)
while (eql x result)
finally (return result)))
sequence))
(multi-replace-if "bcdfghjklmnpqrstvwxyz"
(lambda (x) (if (find x "aeiouy") #\v x))
(lambda (y) (declare (ignore y)) #\c))
"cccccccccccccccccccvc"

Resources