Bubble sort for letters - clojure

I want to develop a bubble sort function that reorders letters into the correct order alphabetically.
So far this is my code
(defn bubble [ys x]
(if-let [y (peek ys)]
(if (> y x)
(conj (pop ys) x y)
(conj ys x))
[x]))
(defn bubble-sort [xs]
(let [ys (reduce bubble [] xs)]
(if (= xs ys)
xs
(recur ys))))
I believe the issue is the > on the line (if (> y x) and the = on the line (if (= xs ys). This makes it want a number and not a letter.
Is their anyway I can change this code to make it work for letters?

You can make the comparisons more generically applicable using the compare function:
(defn bubble [ys x]
(if-let [y (peek ys)]
(if (neg? (compare x y))
(conj (pop ys) x y)
(conj ys x))
[x]))
(defn bubble-sort [xs]
(let [ys (reduce bubble [] xs)]
(if (= xs ys)
xs
(recur ys))))
(bubble-sort [\b \a \c \z \h])
=> [\a \b \c \h \z]
You could also consider an optional argument allowing for custom comparators.

Related

Clojure: Implementing the some function

I'm new to clojure and tried to implement the some function (for some specific tests):
(my-some even? [1 2 3 4]) => true
(my-some #{3 4} [1 2 3 4]) => 3
(my-some zero? [1 2 3 4]) => nil
That's what I came up with so far:
(defn my-some [f x]
(loop [[y & t] x]
(if (empty? t) nil
(if (f y)
(f y)
(recur t)))))
I could imagine there are more idiomatic approaches.
Any suggestions?
Firstly, you have a bug: [[y & t] x] destructures x, but the following empty? check on t means you are ignoring the last element in the sequence. You can see this with
(my-some even? [2])
=> nil
You can replace (if (empty? x) nil (else-form)) with when and seq:
(when (seq x) ...)
you can then use first and next to deconstruct the sequence:
(defn my-some [f x]
(when (seq x)
(if (f (first x))
(f (first x))
(recur f (rest x)))))
the call to recur is then back into my-some so you need to pass the predicate f.
you can replace (if x x (else ....)) with (or x (else ...)):
(defn my-some [f x]
(when (seq x)
(or (f (first x)) (recur f (next x)))))
you can compare this with the implementation of some

What is wrong with my Clojure implementation of permutations

I know that there are multiple ways to solve permutations using Clojure.
I have tried creating a DCG (definite clause grammar) using Core.Logic but
the DCG part of the library is too experimental and didn't work.
In the code below I try two different approaches. One is a list comprehension (commented out), which is similar to the way I would solve this problem in Haskell.
The second approach uses MapCat to apply cons/first to each return value from the
recursive call to permutation. Remove item makes sure that I don't use the same letter more than once for each position.
Can someone please explain what is wrong with the list comprehension approach and what is wrong with the MapCat approach. It is much easier to reason about this kind of problem in Haskell - is there some perspective I am missing about Clojure?
(defn remove-item [xs]
(remove #{(first xs)} xs )
)
(defn permutation [xs]
(if (= (count xs) 1)
xs
;(for [x xs y (permutation (remove-item xs))
; :let [z (map concat y)]]
; z)
(mapcat #(map cons first (permutation (remove-item %)) ) xs)
)
)
Edit: #thumbnail solved the MapCat sub-problem in the comments already
We can simplify the permutation function to
(defn permutation [xs]
(if (= (count xs) 1)
xs
(for [x xs
y (permutation (remove-item xs))]
(map concat y))))
Attempting to use it on anything plural produces java.lang.IllegalArgumentException: Don't know how to create ISeq from: ... whatever you are trying to permute.
There are two errors:
permutation should return a sequence of sequences, even when there is
only one of them; so xs should be (list xs). This is what causes the exception.
The permutation for a given x from xs and, given that, a permutation y of xs without xis just (cons x y).
With these corrected, we have
(defn permutation [xs]
(if (= (count xs) 1)
(list xs)
(for [x xs
y (permutation (remove-item x xs))]
(cons x y))))
For example,
(permutation (range 3))
;((0 1 2) (0 2 1) (1 0 2) (1 2 0) (2 0 1) (2 1 0))
The above works only if all the permuted things are different. At the other extreme ...
(permutation [1 1 1])
;()
Also,
count scans the whole of a sequence. To find out if there is only
one element, (seq (rest xs)) is faster than (= (count xs) 1).
And the remove in remove-item scans the whole sequence. There is
little we can do to mend this.
If we know that we are dealing with distinct things, it is simpler and faster to deal with them as a set:
(defn perm-set [xs]
(case (count xs)
0 '()
1 (list (seq xs))
(for [x xs, y (perm-set (disj xs x))]
(cons x y)))
It works for empty sets too.
count is instant and disj is almost constant time, so this is
faster.
Thus:
(perm-set (set '()))
;()
(perm-set (set (range 3)))
;((0 1 2) (0 2 1) (1 0 2) (1 2 0) (2 0 1) (2 1 0))
We can add support for duplicates by working with the index of the items in the original sequence. The function append-index returns a new sequence where the index and value are now in a vector. For example '(\a \b \c) -> '([0 \a] [1 \b] [2 \c] [3 \a]).
You then work with this sequence within the for loop, taking the index of the item when we want to remove it from the original and taking the value when we cons it to the tail sequence.
(defn remove-nth [coll n]
(into (drop (inc n) coll) (reverse (take n coll))))
(defn append-index [coll]
(map-indexed #(conj [%1] %2) coll))
(defn permutation [xs]
(let [i-xs (append-index xs)]
(if (= (count xs) 1)
(list xs)
(for [x i-xs
y (permutation (remove-nth xs (first x)))]
(cons (last x) y)))))
Thanks to the previous post, I was struggling with the permutation problem myself and had not considered using a for comprehension.

How to delete an element from a nested list?

I have a deeply nested list and I want to delete a given element from all its occurrences in the list. I have this code:
(defn eliminate [value lst]
(defn sub-eliminate [lst]
(def currentItem (first lst))
(if-not (empty? lst)
(if (seq? currentItem)
(cons (sub-eliminate currentItem) (sub-eliminate (rest lst)))
(if (= value currentItem)
(sub-eliminate (rest lst))
(cons currentItem (sub-eliminate (rest lst)))
)
)
'()
)
)
(sub-eliminate lst)
)
But, it doesn't delete at inner levels. Why??
My guess is that you're using vectors as sequences.
(eliminate 3 [3 3])
;()
(eliminate 3 [3 [3]])
;([3])
This would have been trivial to find had you shown us an example: tut, tut!
What's going on?
Although vectors are seqable, they are not sequences:
(seq? [])
;false
At the outer level, you treat lst as a sequence, so first and rest work, since they wrap their argument in an implicit seq. But seq? will fail on any immediately enclosed vector, and those further in won't even be seen.
If you replace seq? with sequential?, lists and vectors will work.
(sequential? [])
;true
More serious, as #noisesmith noted, is your use of def and defn at inner scope. Replace them with let or letfn.
You could also improve your style:
Replace (if-not (empty? lst) ... ) with (if (seq lst) ...).
Use cond to flatten your nested ifs. This requires inverting
the test in (1), so removes the need for it.
Use recur for the tail-recursive case where you find value, as
#Mark does.
If you don't want to see the result, look away now:
(defn eliminate [value lst]
(letfn [(sub-eliminate [lst]
(let [current-item (first lst)]
(cond
(empty? lst) '()
(sequential? current-item) (cons (sub-eliminate current-item)
(sub-eliminate (rest lst)))
(= value current-item) (recur (rest lst))
:else (cons current-item (sub-eliminate (rest lst))))))]
(sub-eliminate lst)))
There is a remaining tender spot:
You invoke (first lst) before you know that lst is not empty. No
harm done: you'll just get nil, which you ignore.
An Alternative Apporach using Destructuring
You can often use destructuring to abbreviate recursive processing of sequences. I'd be inclined to express your function thus:
(defn eliminate [x xs]
((fn rem-x [xs]
(if-let [[y & ys] (seq xs)]
(if (= x y)
(recur ys)
(cons
(if (sequential? y) (rem-x y) y)
(rem-x ys)))
()))
xs))
For the sake of learning take a look at this function:
(define rember*
(lambda (x l)
(cond ((null? l) '())
((atom? (car l))
(if (eq? (car l) x)
(rember* x (cdr l))
(cons (car l)
(rember* x (cdr l)))))
(else (cons (rember* x (car l))
(rember* x (cdr l)))))))
This is a simple recursive function from book 'The Little Schemer', which is a good source to learn how to write such recursive functions.
Let's see if we can translate it into Clojure:
(defn rember* [x l]
(cond (empty? l) '()
(seq? (first l)) (cons (rember* x (first l))
(rember* x (rest l)))
:else (if (= (first l) x)
(recur x (rest l))
(cons (first l)
(rember* x (rest l))))))
user> (rember* 'x '((x y) x (z (((((x))))))))
;; => ((y) (z ((((()))))))
(defn expel [victim xs]
(mapcat (fn [x]
(cond
(sequential? x) [(expel victim x)]
(= x victim) []
:else [x]))
xs))

Clojure: How to count occurrences in a list?

I'm still pretty new to clojure, so I apologize if this a bit trivial. Basically, the issue is in the "then" part of the if statement: (if (symbol? (first slist)).
;counts the number of occurences of
(defn count-occurrences [s slist]
(if (empty? slist)
0
(if (symbol? (first slist))
(if (= (first slist) s)
(+ 1 (count-occurrences s (rest slist)))
(+ 0 (count-occurrences s (rest slist))))
(count-occurrences s (first slist))))) ;Problem on this line
(println (count-occurrences 'x '((f x) y (((x z) x)))))
To count elements in a nested list, you could try this function:
(defn count-occurrences [s slist]
(->> slist
flatten
(filter #{s})
count))
Test:
user> (count-occurrences 'x '((f x) y (((x z) x))))
;; => 3
user> (count-occurrences 'y '((f x) y (((x z) x))))
;; => 1
user> (count-occurrences 'z '((f x) y (((x z) x))))
;; => 1
As Diego Basch commented, the skeleton of your algorithm ought to be
(defn count-occurrences [s slist]
(+ (count-occurrencies s (first slist))
(count-occurrencies s (rest slist))))
... which has one or two little problems:
It never terminates.
It doesn't deal with a symbol.
It doesn't deal with an empty list.
slist might not be a list, and eventually, through first calls,
won't be.
How do we deal with these problems?
First, test whether were dealing with a symbol.
If we aren't, assume it's a list and test whether it's empty.
If not, apply the skeleton recursion.
... giving us something like this:
(defn count-occurrences [s x]
(if (symbol? x)
(if (= x s) 1 0)
(if (empty? x)
0
(+ (count-occurrences s (first x))
(count-occurrences s (rest x))))))
... which works:
(count-occurrences 'x '((f x) y (((x z) x))))
;3
This solution has several problems (which you'll come to appreciate) that make Mark's answer superior in practice. However, if you're trying to get to grips with recursion, this will do nicely.

Scheme: remove elements from nested list

Given a propositional formula, i. e. ((a and (b implies c) or (d and (e implies f)))),
I need to write a Scheme function to remove the connectives, and, implies, or.
The the return of the function contains all variables in the formula. For instance,
(a b c d e f).
I am not sure how to even get started on this, because I am unsure how to get inside the nested lists and remove and cons certain variables and connectives.
I would start up with something like the following:
(define somelist
(list 'a 'and (list 'b 'implies 'c)
'or (list 'd 'and (list 'e 'implies 'f))))
(define (remove-vars xs ys)
(let ((xs-f (flatten xs)))
(filter-two xs-f ys)))
(define (filter-two xs ys)
(foldr (lambda(y acc)
(filter (lambda(x) (not (eq? x y))) acc))
xs
ys))
Test:
> (remove-vars somelist (list 'and 'or 'implies))
(a b c d e f)
> (remove-vars somelist (list 'and 'or))
(a b implies c d e implies f)
UPDATE: OK, #karategeek6 reported, that he doesn't have flatten and filter in his Scheme interpreter, and I'm not sure you do, so let's implement them manually, because there are no filter and flatten in R^6RS either:
(define (my-flatten xs)
(foldr
(lambda(x acc)
(if (list? x)
(append (my-flatten x) acc)
(cons x acc)))
(list)
xs))
(define (my-filter pred xs)
(let recur ((xs xs)
(acc (list)))
(if (empty? xs)
(reverse acc)
(if (pred (car xs))
(recur (cdr xs) (cons (car xs) acc))
(recur (cdr xs) acc)))))
Modify remove-vars and filter-two appropriately:
(define (remove-vars xs ys)
(let ((xs-f (my-flatten xs)))
(filter-two xs-f ys)))
(define (filter-two xs ys)
(foldr (lambda(y acc)
(my-filter (lambda(x) (not (eq? x y))) acc))
xs
ys))
You should get the same output as with previous versions of the above procedures.