Say I have a set like this:
#{"word1" "word2" "word3"}
How could I list all ways that these words might be ordered, i.e.
word1 word2 word3
word2 word3 word1
word3 word2 word1
etc.
The easiest way is using math.combinatorics:
user> (require '[clojure.math.combinatorics :as combo])
nil
user> (combo/permutations #{"word1" "word2" "word3"})
(("word1" "word2" "word3") ("word1" "word3" "word2") ("word2" "word1" "word3") ("word2" "word3" "word1") ("word3" "word1" "word2") ("word3" "word2" "word1"))
Edit: I haven't looked at the math.combinatorics implementation, but here's a lazy version because OP asked for some code to follow.
(defn permutations [s]
(lazy-seq
(if (seq (rest s))
(apply concat (for [x s]
(map #(cons x %) (permutations (remove #{x} s)))))
[s])))
Although math.combinatorics is probably the right answer, I was looking for something simpler to follow. Below is a non-lazy implementation that I can follow:
(defn permutations [colls]
(if (= 1 (count colls))
(list colls)
(for [head colls
tail (permutations (disj (set colls) head))]
(cons head tail))))
Related
Hi am learning clojure and trying to find the index of the vowels in a string here is what I tried
(def vowels [\a \e \i \o \u \y])
(let [word-index (interleave "aaded" (range))
indexs (for [ [x i] (vector word-index)
:when (some #{x} vowels)]
[i] )]
(seq indexs))
But this is giving me index "0" or nill what am doing wrong.
> (def vowels #{\a \e \i \o \u})
> (filter some? (map #(when (vowels %1) %2) "aaded" (range)))
(0 1 3)
You need to form the input correctly for the for comprehension:
(let [word-index (interleave "aaded" (range))
indexs (for [[x i] (partition 2 word-index)
:when (some #{x} vowels)]
i)]
(prn (seq indexs)))
;; => (0 1 3)
interleave will give a lazy sequence when we mapped that sequence to the vector of for loop, I think I missed the indexes. So changed the implementation as below.
(let [word-index (zipmap (range) "aaded")
indexs (for [ [i x] word-index
:when (some #{x} vowels)]
[i] )
]
(flatten indexs)
)
Which is working fine, if anyone has better implementation please share. It will be helpful for me thanks.
With every iteration of the for function, the same hash-set is formed repeatedly. So it's better to define it in the let block. Also, we can use the hash-set directly as a function and we don't need the some function for the same.
(let [word-index (zipmap (range) "aaded")
vowels-hash (into #{} [\a \e \i \o \u \y])
indexs (for [[i x] word-index
:when (vowels-hash x)]
[i])]
(flatten indexs))
a bit different approach with regex:
for all indices:
user> (let [m (re-matcher #"[aeiou]" "banedif")]
(take-while identity (repeatedly #(when (re-find m) (.start m)))))
;;=> (1 3 5)
for single index:
user> (let [m (re-matcher #"[aeiou]" "bfsendf")]
(when (re-find m) (.start m)))
;;=> 3
user> (let [m (re-matcher #"[aeiou]" "bndf")]
(when (re-find m) (.start m)))
;;=> nil
#jas has got this nailed down already. Adding my own to provide some comments on what happens in intermediary steps.
Use sets to check for membership. Then the question "is this a vowel?" will be fast.
(def vowels (set "aeiouy"))
vowels
;; => #{\a \e \i \o \u \y}
We can filter out the vowels, then get just the indexes
(defn vowel-indices-1 [word]
(->> (map vector (range) word) ; ([0 \h] [1 \e] [2 \l] ...)
(filter (fn [[_ character]] ; ([1 \e] [4 \o])
(contains? vowels character)))
(map first))) ; (1 4)
(vowel-indices-1 "hello!")
;; => (1 4)
... or we can go for a slightly more fancy with the :when keyword (didn't know about that, thanks!), in the style that you started!
(defn vowel-indices-2 [word]
(for [[i ch] (map vector (range) word)
:when (contains? vowels ch)]
i))
(vowel-indices-2 "hello!")
;; => (1 4)
I'm working on a project to learn Clojure in practice. I'm doing well, but sometimes I get stuck. This time I need to transform sequence of the form:
[":keyword0" "word0" "word1" ":keyword1" "word2" "word3"]
into:
[[:keyword0 "word0" "word1"] [:keyword1 "word2" "word3"]]
I'm trying for at least two hours, but I know not so many Clojure functions to compose something useful to solve the problem in functional manner.
I think that this transformation should include some partition, here is my attempt:
(partition-by (fn [x] (.startsWith x ":")) *1)
But the result looks like this:
((":keyword0") ("word1" "word2") (":keyword1") ("word3" "word4"))
Now I should group it again... I doubt that I'm doing right things here... Also, I need to convert strings (only those that begin with :) into keywords. I think this combination should work:
(keyword (subs ":keyword0" 1))
How to write a function which performs the transformation in most idiomatic way?
Here is a high performance version, using reduce
(reduce (fn [acc next]
(if (.startsWith next ":")
(conj acc [(-> next (subs 1) keyword)])
(conj (pop acc) (conj (peek acc)
next))))
[] data)
Alternatively, you could extend your code like this
(->> data
(partition-by #(.startsWith % ":"))
(partition 2)
(map (fn [[[kw-str] strs]]
(cons (-> kw-str
(subs 1)
keyword)
strs))))
what about that:
(defn group-that [ arg ]
(if (not-empty arg)
(loop [list arg, acc [], result []]
(if (not-empty list)
(if (.startsWith (first list) ":")
(if (not-empty acc)
(recur (rest list) (vector (first list)) (conj result acc))
(recur (rest list) (vector (first list)) result))
(recur (rest list) (conj acc (first list)) result))
(conj result acc)
))))
Just 1x iteration over the Seq and without any need of macros.
Since the question is already here... This is my best effort:
(def data [":keyword0" "word0" "word1" ":keyword1" "word2" "word3"])
(->> data
(partition-by (fn [x] (.startsWith x ":")))
(partition 2)
(map (fn [[[k] w]] (apply conj [(keyword (subs k 1))] w))))
I'm still looking for a better solution or criticism of this one.
First, let's construct a function that breaks vector v into sub-vectors, the breaks occurring everywhere property pred holds.
(defn breakv-by [pred v]
(let [break-points (filter identity (map-indexed (fn [n x] (when (pred x) n)) v))
starts (cons 0 break-points)
finishes (concat break-points [(count v)])]
(mapv (partial subvec v) starts finishes)))
For our case, given
(def data [":keyword0" "word0" "word1" ":keyword1" "word2" "word3"])
then
(breakv-by #(= (first %) \:) data)
produces
[[] [":keyword0" "word0" "word1"] [":keyword1" "word2" "word3"]]
Notice that the initial sub-vector is different:
It has no element for which the predicate holds.
It can be of length zero.
All the others
start with their only element for which the predicate holds and
are at least of length 1.
So breakv-by behaves properly with data that
doesn't start with a breaking element or
has a succession of breaking elements.
For the purposes of the question, we need to muck about with what breakv-by produces somewhat:
(let [pieces (breakv-by #(= (first %) \:) data)]
(mapv
#(update-in % [0] (fn [s] (keyword (subs s 1))))
(rest pieces)))
;[[:keyword0 "word0" "word1"] [:keyword1 "word2" "word3"]]
I have a list of strings, fx '("abc" "def" "gih") and i would like to be able to search the list for any items containing fx "ef" and get the item or index returned.
How is this done?
Combining filter and re-find can do this nicely.
user> (def fx '("abc" "def" "gih"))
#'user/fx
user> (filter (partial re-find #"ef") fx)
("def")
user> (filter (partial re-find #"a") fx)
("abc")
In this case I like to combine them with partial though defining an anonymous function works fine in that case as well. It is also useful to use re-pattern if you don't know the search string in advance:
user> (filter (partial re-find (re-pattern "a")) fx)
("abc")
If you want to retrieve all the indexes of the matching positions along with the element you can try this:
(filter #(re-find #"ef" (second %)) (map-indexed vector '("abc" "def" "gih")))
=>([1 "def"])
map-indexed vector generates an index/value lazy sequence
user> (map-indexed vector '("abc" "def" "gih"))
([0 "abc"] [1 "def"] [2 "gih"])
Which you can then filter using a regular expression against the second element of each list member.
#(re-find #"ef" (second %))
Just indices:
Lazily:
(keep-indexed #(if (re-find #"ef" %2)
%1) '("abc" "def" "gih"))
=> (1)
Using loop/recur
(loop [[str & strs] '("abc" "def" "gih")
idx 0
acc []]
(if str
(recur strs
(inc idx)
(cond-> acc
(re-find #"ef" str) (conj idx)))
acc))
For just the element, refer to Arthur Ulfeldts answer.
Here is a traditional recursive definition that returns the index. It's easy to modify to return the corresponding string as well.
(defn strs-index [re lis]
(let [f (fn [ls n]
(cond
(empty? ls) nil
(re-find re (first ls)) n
:else (recur (rest ls) (inc n))))]
(f lis 0)))
user=> (strs-index #"de" ["abc" "def" "gih"])
1
user=> (strs-index #"ih" ["abc" "def" "gih"])
2
user=> (strs-index #"xy" ["abc" "def" "gih"])
nil
(Explanation: The helper function f is defined as a binding in let, and then is called at the end. If the sequence of strings passed to it is not empty, it searches for the regular expression in the first element of the sequence and returns the index if it finds the string. This uses the fact that re-find's result counts as true unless it fails, in which case it returns nil. If the previous steps don't succeed, the function starts over with the rest of the sequence and an incremented index. If it gets to the end of the sequence, it returns nil.)
Being quite new to clojure I am still struggling with its functions. If I have 2 lists, say "1234" and "abcd" I need to make all possible ordered lists of length 4. Output I want to have is for length 4 is:
("1234" "123d" "12c4" "12cd" "1b34" "1b3d" "1bc4" "1bcd"
"a234" "a23d" "a2c4" "a2cd" "ab34" "ab3d" "abc4" "abcd")
which 2^n in number depending on the inputs.
I have written a the following function to generate by random walk a single string/list.
The argument [par] would be something like ["1234" "abcd"]
(defn make-string [par] (let [c1 (first par) c2 (second par)] ;version 3 0.63 msec
(apply str (for [loc (partition 2 (interleave c1 c2))
:let [ch (if (< (rand) 0.5) (first loc) (second loc))]]
ch))))
The output will be 1 of the 16 ordered lists above. Each of the two input lists will always have equal length, say 2,3,4,5, up to say 2^38 or within available ram. In the above function I have tried to modify it to generate all ordered lists but failed. Hopefully someone can help me. Thanks.
Mikera is right that you need to use recursion, but you can do this while being both more concise and more general - why work with two strings, when you can work with N sequences?
(defn choices [colls]
(if (every? seq colls)
(for [item (map first colls)
sub-choice (choices (map rest colls))]
(cons item sub-choice))
'(())))
(defn choose-strings [& strings]
(for [chars (choices strings)]
(apply str chars)))
user> (choose-strings "123" "abc")
("123" "12c" "1b3" "1bc" "a23" "a2c" "ab3" "abc")
This recursive nested-for is a very useful pattern for creating a sequence of paths through a "tree" of choices. Whether there's an actual tree, or the same choice repeated over and over, or (as here) a set of N choices that don't depend on the previous choices, this is a handy tool to have available.
You can also take advantage of the cartesian-product from the clojure.math.combinatorics package, although this requires some pre- and post-transformation of your data:
(ns your-namespace (:require clojure.math.combinatorics))
(defn str-combinations [s1 s2]
(->>
(map vector s1 s2) ; regroup into pairs of characters, indexwise
(apply clojure.math.combinatorics/cartesian-product) ; generate combinations
(map (partial apply str)))) ; glue seqs-of-chars back into strings
> (str-combinations "abc" "123")
("abc" "ab3" "a2c" "a23" "1bc" "1b3" "12c" "123")
>
The trick is to make the function recursive, calling itself on the remainder of the list at each step.
You can do something like:
(defn make-all-strings [string1 string2]
(if (empty? string1)
[""]
(let [char1 (first string1)
char2 (first string2)
following-strings (make-all-strings (next string1) (next string2))]
(concat
(map #(str char1 %) following-strings)
(map #(str char2 %) following-strings)))))
(make-all-strings "abc" "123")
=> ("abc" "ab3" "a2c" "a23" "1bc" "1b3" "12c" "123")
(defn combine-strings [a b]
(if (seq a)
(for [xs (combine-strings (rest a) (rest b))
x [(first a) (first b)]]
(str x xs))
[""]))
Now that I wrote it I realize it's a less generic version of amalloiy's one.
You could also use the binary digits of numbers between 0 and 16 to form your combinations:
if a bit is zero select from the first string otherwise the second.
E.g. 6 = 2r0110 => "1bc4", 13 = 2r1101 => "ab3d", etc.
(map (fn [n] (apply str (map #(%1 %2)
(map vector "1234" "abcd")
(map #(if (bit-test n %) 1 0) [3 2 1 0])))); binary digits
(range 0 16))
=> ("1234" "123d" "12c4" "12cd" "1b34" "1b3d" "1bc4" "1bcd" "a234" "a23d" "a2c4" "a2cd" "ab34" "ab3d" "abc4" "abcd")
The same approach can apply to generating combinations from more than 2 strings.
Say you have 3 strings ("1234" "abcd" "ABCD"), there will be 81 combinations (3^4). Using base-3 ternary digits:
(defn ternary-digits [n] (reverse (map #(mod % 3) (take 4 (iterate #(quot % 3) n))))
(map (fn [n] (apply str (map #(%1 %2)
(map vector "1234" "abcd" "ABCD")
(ternary-digits n)
(range 0 81))
(def c1 "1234")
(def c2 "abcd")
(defn make-string [c1 c2]
(map #(apply str %)
(apply map vector
(map (fn [col rep]
(take (math/expt 2 (count c1))
(cycle (apply concat
(map #(repeat rep %) col)))))
(map vector c1 c2)
(iterate #(* 2 %) 1)))))
(make-string c1 c2)
=> ("1234" "a234" "1b34" "ab34" "12c4" "a2c4" "1bc4" "abc4" "123d" "a23d" "1b3d" "ab3d" "12cd" "a2cd" "1bcd" "abcd")
In Python I can do this:
animals = ['dog', 'cat', 'bird']
for i, animal in enumerate(animals):
print i, animal
Which outputs:
0 dog
1 cat
2 bird
How would I accomplish the same thing in Clojure? I considered using a list comprehension like this:
(println
(let [animals ["dog" "cat" "bird"]]
(for [i (range (count animals))
animal animals]
(format "%d %d\n" i animal))))
But this prints out every combination of number and animal. I'm guessing there is a simple and elegant way to do this but I'm not seeing it.
There is map-indexed in core as of 1.2.
Your example would be:
(doseq [[i animal] (map-indexed vector ["dog" "cat" "bird"])]
(println i animal))
Quick solution:
(let [animals ["dog", "cat", "bird"]]
(map vector (range) animals))
Or, if you want to wrap it in a function:
(defn enum [s]
(map vector (range) s))
(doseq [[i animal] (enum ["dog", "cat", "bird"])]
(println i animal))
What happens here is the function vector is applied to each element in both sequences, and the result is collected in a lazy collection.
Go ahead, try it in your repl.
Use indexed from clojure.contrib.seq:
Usage: (indexed s)
Returns a lazy sequence of [index, item] pairs, where items come
from 's' and indexes count up from zero.
(indexed '(a b c d)) => ([0 a] [1 b] [2 c] [3 d]
For your example this is
(require 'clojure.contrib.seq)
(doseq [[i animal] (clojure.contrib.seq/indexed ["dog", "cat", "bird"])]
(println i animal))
map-indexed looks right but: Do we really need all of the doseq and deconstructing args stuff in the other answers?
(map-indexed println ["dog", "cat", "bird"])
EDIT:
as noted by #gits this works in the REPL but doesn't respect that clojure is lazy by default. dorun seems to be the closest among doseq, doall and doseq for this. doseq, howver, seems to be the idiomatic favorite here.
(dorun (map-indexed println ["dog", "cat", "bird"]))
Yet another option is to use reduce-kv, which pairs the elements of a vector with their indexes.
Thus,
(reduce-kv #(println %2 %3) nil ["dog" "cat" "bird"])
or perhaps the slightly more explicit
(reduce-kv (fn [_ i animal] (println i animal)) nil ["dog" "cat" "bird"])
I wouldn’t pick this solution over the one with doseq here, but it is good to be aware of this specialisation for vectors in reduce-kv.