Why does the following Clojure not detect a palindrome? - string

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

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"

detecting a palindrome without using reverse

I was thinking a way to create a function that detects a palindrome without using reverse...
I thought I would be clever and do a condition where substring 0 to middle equals substring end to middle. I;ve found out that it only works on words with 3 letters "wow" because "w" = "w". But if the letters are like "wooow", wo doesn't equal ow. What is a way to detect palindrome without using a reverse function?
Hint or solutions might be very helpful
(define (palindrome? str)
(cond
((equal? (substring str 0 (- (/ (string-length str) 2) 0.5))
(substring str (+ (/ (string-length str) 2) 0.5) (string-length str))) str)
(else false)))
Oh and I'm using beginner language so I can't use stuff like map or filter
yes I know this is a very useless function haha
It's possible to solve this problem by messing around with the string's characters in a given index. The trick is to use string-ref wisely. Here, let me give you some hints pointing to a solution that will work with the beginner's language :
; this is the main procedure
(define (palindrome? s)
; it uses `loop` as a helper
(loop <???> <???> <???>))
; loop receives as parameters:
; `s` : the string
; `i` : the current index, starting at 0
; `n` : the string's length
(define (loop s i n)
(cond (<???> ; if `i` equals `n`
<???>) ; then `s` is a palindrome
(<???> ; if the char at the current index != its opposite (*)
<???>) ; then `s` is NOT a palindrome
(else ; otherwise
(loop <???> <???> <???>)))) ; advance the recursion over `i`
Of course, the interesting part is the one marked with (*). Think of it, a string is a palindrome if the char at the 0 index equals the char at the n-1 index (n being the string's length) and the char at the 1 index equals the char at the n-2 index, and so on. In general, if it's true that the char at the i index equals the char at the n-i-1 index (its "opposite") for all i, then we can conclude that the string is a palindrome - but if a single pair of opposite chars is not equal to each other, then it's not a palindrome.
As a further optimization, notice that you don't need to traverse the whole string, it's enough to test the characters up to the half of the string's length (this is explained in Chris' answer) - intuitively, you can see that if the char at i equals the char at n-i-1, then it follows that the char at n-i-1 equals the char at i, so there's no need to perform the same test two times.
Try to write the procedures on your own, and don't forget to test them:
(palindrome? "")
=> #t
(palindrome? "x")
=> #t
(palindrome? "axa")
=> #t
(palindrome? "axxa")
=> #t
(palindrome? "axc")
=> #f
(palindrome? "axca")
=> #f
(palindrome? "acxa")
=> #f
(palindrome? "axcta")
=> #f
Here is a creative answer
(define (palindrome list)
(let halving ((last list) (fast list) (half '()))
(cond ((null? fast) (equal? half last))
((null? (cdr fast)) (equal? half (cdr last)))
(else (halving (cdr last) (cddr fast)
(cons (car last) half))))))
It travels halfway down the list (using fast to find the end), builds up a list of the first half and then simply uses equal? on half with the remainder of list.
Simple.
For each i, from 0 to floor(length / 2), compare the character at index i and at index length - i - 1.
If mismatch, return false.
Otherwise, if the loop runs out, return true.
Skeletal code:
(define (palindrome? str)
(define len (string-length str))
(define halfway <???>)
(let loop ((i 0))
(cond ((>= i halfway) #t)
((char=? <???> <???>)
(loop (+ i 1)))
(else #f))))

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).

Add character to string to get another 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)))))

Resources