Add character to string to get another string? - string

I want to add a character to a string, and get another string with the character added as a result.
This doesn't work:
(cons \a "abc")
Possible solutions, in order of preference:
Clojure core function
Clojure library function
Clojure user-defined (me!) function (such as (apply str (cons \a "abc")))
java.lang.String methods
Is there any category 1 solution before I roll-my-own?
Edit: this was a pretty dumb question. :(

How about:
(str "abc" \a)
This returns "abca" on my machine.
You can also use it for any number of strings/chars: (str "kl" \m "abc" \a \b).

You could use join from clojure.string:
(clojure.string/join [\a "abc"])
But for the simple use case you should really just use str, as #Dan Filimon suggests. join has the added benefit that you could put a separator between the joined strings, but without a separator it actually just applies str:
(defn ^String join
"Returns a string of all elements in coll, separated by
an optional separator. Like Perl's join."
{:added "1.2"}
([coll]
(apply str coll))
([separator [x & more]]
(loop [sb (StringBuilder. (str x))
more more
sep (str separator)]
(if more
(recur (-> sb (.append sep) (.append (str (first more))))
(next more)
sep)
(str sb)))))

Related

Flexible replace substring - Scheme

Is there, in Scheme, a good way to replace a substring of a string with another string, the length of which could vary? I am looking for something similar to this:
(replace-all string pattern replacement)
(replace-all "slig slog slag" "g" "ggish")
=> "sliggish sloggish slaggish"
You can roll your own. It's not very efficient but it will do the work on small strings. (I wouldn't use it on string lengths above a million chars)
Make (prefix? src prefix) such that i evaluates to #t if the beginning of the list src is the same as prefix.
Make (append-reverse rev-head tail) such that (append-reverse '(1 2 3) '(4 5 6)) ; ==> (3 2 1 4 5 6). This could easily be done with foldl or it's a standard procedure in SRFI-1
Then (replace-all haystack needle replacement) is quite simple:
(define (replace-all haystack needle replacement)
;; most of the processing works on lists
;; of char, not strings.
(let ((haystack (string->list haystack))
(needle (string->list needle))
(replacement (string->list replacement))
(needle-len (string-length needle)))
(let loop ((haystack haystack) (acc '()))
(cond ((null? haystack)
(list->string (reverse acc)))
((prefix? haystack needle)
(loop (list-tail haystack needle-len)
(reverse-append replacement acc)))
(else
(loop (cdr haystack) (cons (car haystack) acc)))))))
(replace-all "The cat looks like a cat." "cat" "dog")
; ==> "The dog looks like a dog."
Sure, take a look at the documentation of your Scheme interpreter to find a suitable procedure. For instance, in Racket we have string-replace which works like this:
(string-replace "slig slog slag" "g" "ggish")
=> "sliggish sloggish slaggish"

What would be a good or efficient way to get the list of alphabet used in a string

Put it simply, how to get a list non-repeated letters from a string in Common Lisp?
e.g:
"common"
-> ("c" "o" "m" "n") or in characters, (#\c #\o #\m #\n)
I'd care less about the order and type, if it is in string or character.
"overflow" -> (o v e r f l w)
"tomtomtom" -> (t o m)
etc...
What I was thinking is to collect the first letter of the original string,
Then use the function;
(remove letter string)
collect the first letter of now, removed letter string and append it to the already collected letters from before.
It sounds like recursion but if recursively calling would loose the previously collected *letter*s list, right? I also doubt if there is any built-in functions for this.
Furthermore, I don't want to use set or any of them since I want
to do this completely in functional style.
Thanks for your time.
CL-USER> (remove-duplicates (coerce "common" 'list))
(#\c #\m #\o #\n)
Or you can even do it simply as:
CL-USER> (remove-duplicates "common")
"comn"
There may be certain better possibilities to do that, if you can make some assumptions about the text you are dealing with. For instance, if you are dealing with English text only, then you could implement a very simple hash function (basically, use a bit vector 128 elements long), so that you wouldn't need to even use a hash-table (which is a more complex structure). The code below illustrates the idea.
(defun string-alphabet (input)
(loop with cache =
(coerce (make-array 128
:element-type 'bit
:initial-element 0) 'bit-vector)
with result = (list input)
with head = result
for char across input
for code = (char-code char) do
(when (= (aref cache code) 0)
(setf (aref cache code) 1
(cdr head) (list char)
head (cdr head)))
finally (return (cdr result))))
(string-alphabet "overflow")
;; (#\o #\v #\e #\r #\f #\l #\w)
Coercing to bit-vector isn't really important, but it is easier for debugging (the printed form is more compact) and some implementation may actually optimize it to contain only so many integers that the platform needs to represent so many bits, i.e. in the case of 128 bits length, on a 64 bit platform, it could be as short as 2 or 3 integers long.
Or, you could've also done it like this, using integers:
(defun string-alphabet (input)
(loop with cache = (ash 1 128)
with result = (list input)
with head = result
for char across input
for code = (char-code char) do
(unless (logbitp code cache)
(setf cache (logior cache (ash 1 code))
(cdr head) (list char)
head (cdr head)))
finally (return (cdr result))))
but in this case you would be, in your worst case, create 128 big integers, which is not so expensive after all, but the bit-vector might do better. However, this might give you a hint, for the situation, when you can assume that, for example, only letters of English alphabet are used (in which case it would be possible to use an integer shorter then machine memory word).
Here some code in Haskell, because I am not so familiar with Lisp, but as they're both functional, I don't think, it will be a problem for translating it:
doit :: String -> String
doit [] = []
doit (x:xs) = [x] ++ doit (filter (\y -> x /= y) xs)
So what does it? You've got a String, if it's an empty String (in Haskell [] == ""), you return an empty String.
Otherwise, take the first element and concatenate it to the recursion over the tail of the String, but filter out those elements, which are == first element.
This Function filter is only syntactic sugar for a specific map-function, in Lisp called remove-if as you can reread here: lisp filter out results from list not matching predicate

List of chars to string in Emacs Lisp

I have a list of characters (?h ?e ?l ?l ?o) and i want to convert it to string "hello". Currently i use this structure:
(concat (mapcar (lambda (ch) (char-to-string ch)) s))
Is there a more elegant and idiomatic way to convert list of chars to a string in Elisp?
Elisp's concat returns a string:
(concat '(?h ?e ?l ?l ?o))
(Found it out from coerce implementation in cl)
There's also (apply #'string LIST-OF-CHARS).

Join multiple lazy sequences of strings in Clojure

I have several strings:
(def a "some random string")
(def b "this is a text")
Now i want to concatenate parts of them to create a string "some text". Unfortunately both of the strings below didn't work.
(clojure.string/join " " [(take 4 a) (take-last 4 b)])
(str (take 4 a) " " (take-last 4 b))
It's because functions take and take-last return lazy sequences. The question is: what is the proper way to concatenate multiple lazy sequences of strings and return one string?
Edit: I found one solution - (apply str (concat (take 4 a) " " (take-last 4 a))) - but is it the most correct way?
Rather than using sequence functions to slice the input strings, you might want to use the much more efficient subs (for substring; note there's a GC-related caveat about it, see below):
(subs "asdf" 1 2)
; => "s"
;; a and b as in the question text
(clojure.string/join " " [(subs a 0 4) (subs b (- (count b) 4))])
; => "some text"
The aforementioned caveat is that as long as the "s" returned in the first example here remains ineligible for garbage collection, so does the original "asdf" (since subs returns a "view" onto the input String without allocating fresh storage -- this is the behaviour of Java's substring method which subs wraps). This is not a problem if you immediately hand the "s" off to subs and retain no other reference to it, since join will discard it after pulling the characters.
If you do end up working with lazy sequences of characters after all, there's nothing to be done but to use something like (map (partial apply str) [...your vector here...]) to turn the inputs to clojure.string/join into strings.
Try this, and yes becoz of the laziness the result of your code is not proper.
(str (apply str (take 4 a)) " " (apply str (take-last 4 b)))
(str/join " " (map (fn [f col] (f col))
[first last]
(map #(str/split % #" ") [a b])))

Why does the following Clojure not detect a palindrome?

I'm just trying to convert to a string and compare to the reverse
(defn is-palindrome? [num]
(= (str num) (reverse (str num))))
Something like
(is-palindrome 1221)
Is returning false
Try this instead:
(defn is-palindrome? [num]
(= (str num) (apply str (reverse (str num)))))
In your code, the expression (reverse (str 1221)) returns the list of characters (\1 \2 \2 \1), which needs to be turned back into a string for the comparison to work. Alternatively, you could convert both numbers to character lists and perform a list comparison instead:
(defn is-palindrome? [num]
(= (seq (str num)) (reverse (str num))))
(defn palindrome? [num]
(= (seq (str num)) (clojure.string/reverse (str num))))
Your code returns false because it is comparing a string with a sequence, which can never be equal.
You can make it work by explicitly converting the string into a seq as follows:
(defn is-palindrome? [num]
(let [digit-sequence (seq (str num))]
(= digit-sequence (reverse digit-sequence))))
It turns out the the overhead of manipulating collections of characters dominates, so it's actually faster to compare the original string to a reversed version even though it seems like you're comparing twice as many characters as necessary. Make sure you use clojure.string/reverse, not clojure.core/reverse. The usual Clojure convention is to end a predicate with a question mark, but not to use the "is" prefix.
(require 'clojure.string)
(defn palindrome? [s] (= s (clojure.string/reverse s)))
(defn palindrome-num? [n] (palindrome? (str n)))
(reverse (str 1221))
returns a List of characters
(\1 \2 \2 \1)
but (str 1221) is a java String

Resources