Can anyone explain why sort-by is reacting like this with these keyfunctions?
user=> (sort-by number? [1 2 13 4 "s" 0 "a"])
("s" "a" 1 2 13 4 0)
user=> (sort-by str [1 2 3 4 "s" 0 "a"])
(0 1 2 3 4 "a" "s")
My idea is its dividing the args of the vector into strings and numbers? Is there anything more about what's happening here?
And my second question does sort-by travel through every item of the vector and then returning the result?
number? returns true or false depending on whether the input is a number. false is apparently less than true for comparisons.
str returns a string whose value depends on the input. e.g. (str 1) => "1". String comparison is somewhat complicated, but, in general, numerals are less than uppercase letters are less than lowercase letters and letters are sorted in alphabetical order.
I'm not sure exactly the behavior you're wanting, but it would seem that (sort-by number? ...) did indeed "divide the vector into strings and numbers" by giving you strings at the start of the list and numbers at the end.
If you're wanting to separate strings from numbers, use (group-by number? ...)
As for your second question, sort-by uses the keyfn for comparisons during a merge sort.
Related
I am a clojure newbie. I am trying to play around repl and i see the following as output. And I don't quite understand why each of them behave so differently
(def a (list 1 2 3)) =>#'test.core/a
(list* 4 5 a) =>(4 5 1 2 3)
(list* a 4 5) =>IllegalArgumentException Don't know how to create ISeq from: java.lang.Long clojure.lang.RT.seqFrom (RT.java:542)
why does the above 2 statements behave the same way in the above 2 statements?
(list* 4 5 [1 2 3]) =>(4 5 1 2 3)
(list* 4 5 [a]) =>(4 5 (1 2 3))
(list* 4 5 (1 2)) =>ClassCastException java.lang.Long cannot be cast to clojure.lang.IFn test.core/eval3837 (form-init633779145118520639.clj:1)
Could someone explain why each of the above statement has a different output?
If you look at the definition and docstring, it'll make sense.
The docs say:
"Creates a new seq containing the items prepended to the rest, the last of which will be treated as a sequence."
Emphasis mine.
In the first block, the last expression fails because 5 is the last argument, but isn't a sequence.
(list* 4 5 [1 2 3]) works for the same reason that (list* 4 5 a) works. The last argument is a sequence, as it's expecting. It just cons onto the last argument as you can see in the definition.
(list* 4 5 [a]) gives different results because you've wrapped the collection a in another collection. It just adds onto the outer collection, leaving the inner one untouched.
The failure of (list* 4 5 (1 2)) isn't really a related problem. Remember, any time you have (...) unquoted, it will attempt to evaluate it, and is expecting that the first element in the list is callable. 1 however isn't callable, thus the error. You need to quote it to treat it as a list literal and not code that you want evaluated.
See the doc string for list*:
Creates a new seq containing the items prepended to the rest, the last
of which will be treated as a sequence.
Note a seq is not a list but lists and vectors and other things can be treated as sequences. Also a seq when output at the repl looks like a list - it is printed within parens.
So in the first case your last argument is a literal vector and it is treated as a sequence and you get an unnested sequence.
In the second case you have the list 'a' as a single element within a literal vector so the vector is treated as a sequence but the inner list is not, your returned sequence is three elements long: 4, 5, and the list a.
In the last case you are tripping up on the function call syntax in lisps being very similar to the list syntax. (1 2) is trying to call the number 1 as if it in a function (with the argument 2). A literal number can not be interpreted as a function.
If you want a list literal not a function call you have to quote it:
(list* 4 5 '(1 2)) => (4 5 1 2)
I have the word describe, and I want to see how many times each letter appears in the word. Eg "e" appears twice, "d" appears once etc
I have tried
(for [letter (map str (seq describe))]
(count (re-seq letter describe)))
But I get the error
ClassCastException java.lang.String cannot be cast to java.util.regex.Pattern clojure.core/re-matcher (core.clj:4667)
Any help would be much appreciated
You can use frequencies to count the frequency at which each character appears in the string, returning a map like this:
(frequencies "ababacdefg")
=> {\a 3, \b 2, \c 1, \d 1, \e 1, \f 1, \g 1}
This works because the string is being treated as a sequence of characters. frequencies can be used on general collections:
(frequencies [1 1 2 3])
=> {1 2, 2 1, 3 1}
The key is the value being counted, and the value is the frequency.
This question already has an answer here:
Zip two lists in clojure into list of concatenated strings
(1 answer)
Closed 6 years ago.
If I have two sequences
(let [v1 '(1 2 3 4)
v2 '(2 4 6 8)]
...)
is there some way of combining them through a function to single vector, something like:
(combine #(* % %2) [1 2 3 4] [2 4 6 8]) => [2 8 18 32]
The "mapping" function would take one argument for each sequence "combined", so calling it with 3 sequences would require a 3-arity function.
If either sequence runs out of elements it should either just stop or repeat the shorter one, doesn't matter.
You can use the map function for this (from clojure.core).
map takes a function as its first argument, and any number of sequences as its subsequent arguments. It constructs each element of the output by taking an element from each input sequence and applying the function with that collection of elements as arguments, just as you require.
So your example would become:
(map * [1 2 3 4] [2 4 6 8])
I need to read through a string (which is a sequence) 3 characters at a time. I know of take-while and of take 3 and since take returns nil when there is no more input it seems like the perfect predicate for take-while but I cannot figure out how to wrap the string sequence so that it returns string of the next 3 characters at a time. If this was an object oriented language I'd wrap the sequence's read call or something, but with Clojure I have no idea how to proceed further.
You can use partition or partition-all
(partition 3 "abcdef")
user=> ((\a \b \c) (\d \e \f))
The docs for both are
clojure.core/partition
([n coll] [n step coll] [n step pad coll])
Returns a lazy sequence of lists of n items each, at offsets step
apart. If step is not supplied, defaults to n, i.e. the partitions
do not overlap. If a pad collection is supplied, use its elements as
necessary to complete last partition upto n items. In case there are
not enough padding elements, return a partition with less than n items.
nil
clojure.core/partition-all
([n coll] [n step coll])
Returns a lazy sequence of lists like partition, but may include
partitions with fewer than n items at the end.
nil
If your string is not guaranteed to be of length that is multiple of three, then you should probably use partition-all. The last partition will contain less than 3 elements though. If you want to use partition instead, then to avoid having characters from the string chopped off, you should use step=3, and a padding collection to fill in the holes in the last partition.
To turn every tuple to a string, you can use apply str on every tuple. So you'd want to use map here.
(map (partial apply str) (partition-all 3 "abcdef"))
user=> ("abc" "def")
You can do this without boxing every character:
(re-seq #"..." "Some words to split")
;("Som" "e w" "ord" "s t" "o s" "pli")
If, as your comment on #turingcomplete's answer indicates, you want every other triple,
(take-nth 2 (re-seq #"..." "Some words to split"))
;("Som" "ord" "o s")
I'm trying to use the lines function to plot a graph, but I can't seem to figure out the exact syntax.
Here's some code I tried:
(require plot)
(define lst '(1 2 3 4 5 6 7 8 9))
(define f (plot-frame (lines lst)))
(send f show #t)
But it gives me the following error message:
lines: contract violation
expected: sequence of length >= 2
given: #<sequence>
The lines function's first argument is supposed to be a sequence of sequences of real numbers (as opposed to just a sequence of real numbers). That's what this contract shown in the documentation means: (sequence/c (sequence/c real?))
For example, this is a valid input: (lines '((1 2) (3 4)))
There's also a full example in the docs: http://www.cs.utah.edu/plt/snapshots/current/doc/plot/renderer2d.html?q=lines#%28def._%28%28lib._plot%2Fmain..rkt%29._lines%29%29