Is their a way in Clojure to go from an int to that int as a character, e.g. 1 to \1 ?
I have a string s and I want to parse out the digits that match a number n (n will always be 0 to 9)
e.g.
(let [n 1]
(filter #(= ??? %) "123123123"))
Where ??? would n as \n, e.g. would return "111"
Or maybe there is a better way to filter a string to only instance of a single digit?
The "java" way:
user=> (Character/forDigit 1 10) ; number and radix
\1
The "calculaty" way (add the int of \0 to it and then back to char):
user=> (char (+ 1 (int \0)))
\1
And as usual in Clojure, there's always a reduce one-line to solve the original problem: "I just want the count of how many times that digit appears."
(reduce (fn [m ch] (update m ch (fnil inc 0))) {} "123123123")
==> {\1 3, \2 3, \3 3}
A lot to unpack here, if you are new to Clojure.
Reduce is used to iterate over the String, counting occurrences of each character and storing it in a map.
From inner to outer:
(fnil inc 0) returns a function that runs inc with any argument provided. However, if the argument is nil, it will replace it with 0 instead. This is perfect for adding a new entry to the map.
update is used to look up an existing key ch in m and calculate a new value (by calling the function returned by (fnil inc 0)), i.e. if the ch is not in m this will run (inc 0) => 1, if ch is in m it will return the incremented counter.
(fn [m ch] ...) is the reducing function.
This is the most difficult part to understand. It takes two parameters.
The first is the last return value of this function (generated by an earlier iteration) or if it is the first time this function runs, the initial value provided: {} (there's also a third way to call reduce, see (doc reduce))
The second argument ch is the current character in the String provided (since String is a CharSequence and counts as a collection).
So the reducing function is called for each character and we just return the current map with an updated count for each character, starting with {}.
Related
I want a function written in Clojure that checks if my given String is bigger than my given number and if so, my function says true otherwise it says false.
Now i've come up with the following code, but it gives the following error:
ClassCastException java.lang.Long cannot be cast to clojure.lang.IFn user/checker (form-init1692807253513002836.clj:1)
The code i've come up with is:
(defn checker [str, num]
(cond
(> (count str) num) "True"
:else "False"
)
)
(checker "test" 6)
Can someone explain why count str is considered as a Long and/or how this function can be fixed?
You might want to “fix” your function by considering some Clojure
idioms that apply to your snippet:
booleans are built in; no need to use "True"/"False" strings
(unless you’re just using these as a placeholder example for
something else)
don’t need to be explicit about the return booleans since >
already returns a boolean
you’re measuring “length” rather than “bigness”, so use a
descriptive function name; strlen is probably common
since boolean return value you can end with ?
probably avoid str as var name
switch the comparison order to use < instead of >, based on Elements of Clojure recommendation
With those in mind, your function simplifies down to:
(defn strlen-exceeds? [s n]
(< n (count s)))
(And now it’s short enough that you might not even need it to be an
explicit function.)
I think your code should work, but for this case, don't use cond use if.
(defn checker [str, num]
(if (> (count str) num)
"True"
"False"))
> (checker "a" 1)
"False"
> (checker "a" 2)
"False"
> (checker "ab" 2)
"False"
> (checker "ab" 2)
I want to define the Thue-Morse Sequence (or the fair-sharing sequence) in terms of an initial element, 0, and the rule defining the next section of the list in terms of the entire list up until this point. i.e.
fair 0 = [0]
--fair 1 = [0,1]
--fair 2 = [0,1,1,0]
--fair 3 = [0,1,1,0,1,0,0,1]
fair n = fair (n - 1) ++ map (1-) (fair (n - 1))
This works fine to generate the list up to any predefined length, but it seems ineffective to not just define the entire list at once, and use take if I need a predefined amount.
My first attempt at defining the entire list was fair = 0 : map (1-) fair but of course, this populates the list as it goes, so it doesn't ever (need to) reenter the list (and returns [0,1,0,1,0,1...]). What I want is some way to define the list so that when it reaches a not-yet-defined element in the list, it defines the next 'chunk' by reentering the list only until that point, (rather than the computation 'chasing' the new values as they're produced), so the steps in computing the list would be akin to this procedure:
begin with initial list, [0]
map (1-) over the existing list, producing [1]
append this to the existing list, producing [0,1]
map (1-) over the existing list, producing [1,0]
append this to the existing list, producing [0,1,1,0]
map (1-) over the existing list, producing [1,0,0,1]
append this to the existing list, producing [0,1,1,0,1,0,0,1]
The Wikipedia article I linked above has a helpful gif to illustrate this process.
As I presume you can see, this would continue indefinitely as new elements are needed. However, I can't for the life of me find a way to successfully encode this in a recursive function.
I have tried
reenter f xs = reenter f (xs ++ map f xs)
fair = reenter (1-) [0]
But while the logic seems correct, it hangs without producing anything, probably due to the immediate recursive call (though I thought haskell's lazy evaluation might take care of that, despite it being a rather complex case).
As you noted, you can't do the recursive call immediately - you first need to return the next result, and then recursively call, as in your last try:
Prelude> reenter prev_list = inverted_prev_list ++ reenter (prev_list ++ inverted_prev_list) where inverted_prev_list = map (1-) prev_list
Prelude> f = [0] ++ reenter [0]
Prelude> take 20 f
[0,1,1,0,1,0,0,1,1,0,0,1,0,1,1,0,1,0,0,1]
Following is code in Racket, another functional programming language, using the steps listed in the question.
(define (f n)
(define (invert s) ; sub-function to invert the numbers
(list->string
(for/list ((i (string->list s)))
(if (equal? i #\0) #\1 #\0))))
(let loop ((c 1)
(s "0")) ; starting string is "0"
(if (> c n)
s
(loop (add1 c)
(string-append s (invert s))))))
Testing:
(f 1)
(f 2)
(f 3)
(f 4)
(f 5)
Output:
"01"
"0110"
"01101001"
"0110100110010110"
"01101001100101101001011001101001"
For infinite series:
(define (f)
(define (invert s)
(list->string
(for/list ((i (string->list s)))
(if (equal? i #\0) #\1 #\0))))
(let loop ((s "0"))
(define ss (string-append s (invert s)))
(println ss)
(loop ss)))
To run:
(f)
This may give some ideas regarding a Haskell solution to this problem.
I am new to lisp. I am trying to read numbers from user and want to store it as a list. For example: if the user enters 1 2 3 4 5, then the list would contain 5 elements (1 2 3 4 5). I tried (parse-integer(read-line) :junk-allowed t) but it returns only the first element. How should I do this? Thanks.
Use read
The simplest option is to ask the user to enter the list (with the parens) and just call (read).
The second option is to put the parens yourself:
(read-from-string (concatenate 'string "(" (read-line) ")"))
safety and security
Note that the power of the Lisp reader can put you in trouble. E.g., if the user types #.(start-ww3) instead of (1 2 3) at your prompt, you might not reach your bomb shelter in time.
This means that you must bind *read-eval* to nil when calling read on text you do not control.
Call parse-integer repeatedly
Finally, you can call parse-integer in a loop
(defun parse-integers (s &optional (start 0))
(loop with num do
(setf (values num start) (parse-integer s :start start :junk-allowed t))
while num collect num))
or recursively:
(defun parse-integers (s &optional (start 0))
(multiple-value-bind (num end)
(parse-integer s :start start :junk-allowed t)
(and num (cons num (parse-integers s end)))))
I'm looking for an equivalent of replace-regexp-in-string that just uses literal strings, no regular expressions.
(replace-regexp-in-string "." "bar" "foo.buzz") => "barbarbarbarbarbarbarbar"
But I want
(replace-in-string "." "bar" "foo.buzz") => "foobarbuzz"
I tried various replace-* functions but can't figure it out.
Edit
In return for the elaborate answers I decided to benchmark them (yea, I know all benchmarks are wrong, but it's still interesting).
The output of benchmark-run is (time, # garbage collections, GC time):
(benchmark-run 10000
(replace-regexp-in-string "." "bar" "foo.buzz"))
=> (0.5530160000000001 7 0.4121459999999999)
(benchmark-run 10000
(haxe-replace-string "." "bar" "foo.buzz"))
=> (5.301392 68 3.851943000000009)
(benchmark-run 10000
(replace-string-in-string "." "bar" "foo.buzz"))
=> (1.429293 5 0.29774799999999857)
replace-regexp-in-string with a quoted regexp wins. Temporary buffers do remarkably well.
Edit 2
Now with compilation! Had to do 10x more iteration:
(benchmark-run 100000
(haxe-replace-string "." "bar" "foo.buzz"))
=> (0.8736970000000001 14 0.47306700000000035)
(benchmark-run 100000
(replace-in-string "." "bar" "foo.buzz"))
=> (1.25983 29 0.9721819999999983)
(benchmark-run 100000
(replace-string-in-string "." "bar" "foo.buzz"))
=> (11.877136 86 3.1208540000000013)
haxe-replace-string is looking good
Try this:
(defun replace-in-string (what with in)
(replace-regexp-in-string (regexp-quote what) with in nil 'literal))
s.el string manipulation library has s-replace function:
(s-replace "." "bar" "foo.buzz") ;; => "foobarbuzz"
I recommend installing s.el from Emacs package manager, if you work with strings in your Elisp.
Emacs 28.1 (still in development at time of writing) provides this as standard:
** New function 'string-replace'.
This function works along the line of 'replace-regexp-in-string', but
matching on strings instead of regexps, and does not change the global
match state.
(string-replace FROMSTRING TOSTRING INSTRING)
Replace FROMSTRING with TOSTRING in INSTRING each time it occurs.
(string-replace ".*" "BAR" "foo.*bar.*baz")
⇒ "fooBARbarBARbaz"
I'd not hope for this to be faster:
(defun haxe-replace-string (string string-a string-b)
"Because there's no function in eLisp to do this."
(loop for i from 0 upto
(- (length string) (length string-a))
for c = (aref string i)
with alen = (length string-a)
with result = nil
with last = 0
do (loop for j from i below (+ i alen)
do (unless
(char-equal
(aref string-a (- j i))
(aref string j))
(return))
finally
(setq result
(cons (substring string last (- j alen)) result)
i (1- j) last j))
finally
(return
(if result
(mapconcat
#'identity
(reverse (cons (substring string last) result)) string-b)
string))))
Becasue replace-regexp-in-string is a native function, but you never know... Anyways, I wrote this some time ago for some reason, so, if you fill like comparing the performance - you are welcome to try :)
Another idea, using temporary buffer:
(defun replace-string-in-string (what with in)
(with-temp-buffer
(insert in)
(beginning-of-buffer)
(while (search-forward what nil t)
(replace-match with nil t))
(buffer-string)))
s-replace is fine if you are ready to require it, but say you want to use a replace in string feature early in the load process and don't yet have s.el loaded or don't need all of it. Well, here is the definition of s-replace from s.el. As you can see, it has no dependencies so you can use it without requiring the rest of s.el:
(defun s-replace (old new s)
"Replaces OLD with NEW in S."
(declare (pure t) (side-effect-free t))
(replace-regexp-in-string (regexp-quote old) new s t t))
I'd like a hint on how to apply this function:
dti xs = (map intToDigit (take 6 (map digitToInt xs))++['/']++map intToDigit(drop 6 (map digitToInt xs)))
on a list of Integers, e.g.; [1234567822,3245336792,...], so I'd get an output like ["123456/7822","324533/6792",...].
The point is to add a "/" after the 6th digit in each number of a list of integers, e.g.; [1234567822,3245336792,...]. Maybe there's a better way to do it than mine.
intToDigit expects a single digit, so it will raise an error on input like 1234567822.
To convert an Int (or Integer) into a list of characters, you can use show, and then split the resulting string after six digits
format n = first ++ '/':second
where
s = show n
(first,second) = splitAt 6 s
dti = map format