I am reading a piece of code like this:
(apply min-key {:1 1, :2 0, :3 1, :4 10000, :5 1} #{:1 :3 :4 :5}) => :3
I'm not sure why this returns :3 and not :1
Can someone clarify it for me ?
if you take a look at min-key source, you'll see that it compares value with
(if (< v1 v2) v1 v2) , that means if they are equal, it takes the second one. So for multiple keys provided that have equal values it will always choose the last one, in your case :3
That is happening, because you use a set of values, whose internal order differs from the input:
in repl:
user> #{:1 :3 :4 :5}
#{:4 :1 :5 :3}
so, in this order, :3 is the last key checked.
min-key returns an element x from #{:1 :3 :4 :5} such as (k x) is minimal, where k is your map. The value associated with :3 in that map is 1, which is the minimal value. Granted, other keys, like :1 and :5 have the same value, but keys are not compared, only values. Which of the keys returning the minimal value is returned probably depends on arbitrary factors such as the internal order of traversal of your set.
Related
I'm trying to make a sudoku solver program which gets a vector of vectors as an input where each vector inside the vector is a row of the sudoku, where each '0' is an empty cell in the sudoku.
Until now, I've found every possible number a cell with '0' can get.
So the problem is this, after finding which cell has only one possible solution, how will i put that unique solution onto its position despite the immutability of Clojure?
The program needs to return that same vector of vectors where each '0' is replaced by a number which meets the requirements.
If you have a vector of vectors, you can set a cell value using assoc-in e.g.
(def cells [[1 3 0]
[4 2 1]
[6 3 0]])
(defn set-cell-value [board row col value]
(assoc-in board [row col] value))
(set-cell-value cells 0 2 2)
If you need to have state, put it into atom https://clojuredocs.org/clojure.core/atom It is a mutable reference type which holds immutable values.
Clojure provides means for lazy evaluation of values in (infinite) sequences. With this, values will only be computed when they get actually consumed.
An example of an infinite sequence of one repeated element:
(take 3 (repeat "Hello StackOverflow"))
//=> ("Hello StackOverflow" "Hello StackOverflow" "Hello StackOverflow")
Using take helps to only consume as many elements from the sequence as we want. Without it, an OutOfMemoryError would kill the process quickly.
Another example of an infinite sequence is the following:
(take 5 (iterate inc 1))
//(1 2 3 4 5)
Or a more advanced sequence providing the factorial function:
((defn factorial [n]
(apply * (take n (iterate inc 1)))) 5)
Does Kotlin provide similar sequences? How do they look like?
I answered the question myself in order to document the knowledge here. This is fine according to Can I answer my own question?
In Kotlin, we can also make use of lazy evaluation using Sequences, too. In order to create a sequence, we may use generateSequence (with or without providing a seed.
fun <T : Any> generateSequence(
seed: T?,
nextFunction: (T) -> T?
): Sequence<T> (source)
Returns a sequence defined by the starting value seed and the function nextFunction, which is invoked to calculate the next value based on the previous one on each iteration.
The following will show some examples comparing Clojure with Kotlin sequences.
1. A simple take from an infinite sequence of one static value
Clojure
(take 3 (repeat "Hello StackOverflow"))
Kotlin
generateSequence { "Hello StackOverflow" }.take(3).toList()
These are pretty similar. In Clojure we can use repeat and in Kotlin it's simply generateSequence with a static value that will be yielded for ever. In both cases, take is being used in order to define the number of elements we want to compute.
Note: In Kotlin, we transform the resulting sequence into a list with toList()
2. A simple take from an infinite sequence of an dynamic value
Clojure
(take 5 (iterate inc 1))
Kotlin
generateSequence(1) { it.inc() }.take(5).toList()
This example is a bit different because the sequences yield the increment of the previous value infinitely. The Kotlin generateSequence can be invoked with a seed (here: 1) and a nextFunction (incrementing the previous value).
3. A cyclic repetition of values from a list
Clojure
(take 5 (drop 2 (cycle [:first :second :third ])))
// (:third :first :second :third :first)
Kotlin
listOf("first", "second", "third").let { elements ->
generateSequence(0) {
(it + 1) % elements.size
}.map(elements::get)
}.drop(2).take(5).toList()
In this example, we repeat the values of a list cyclically, drop the first two elements and then take 5. It happens to be quite verbose in Kotlin because repeating elements from the list isn't straightforward. In order to fix it, a simple extension function makes the relevant code more readable:
fun <T> List<T>.cyclicSequence() = generateSequence(0) {
(it + 1) % this.size
}.map(::get)
listOf("first", "second", "third").cyclicSequence().drop(2).take(5).toList()
4. Factorial
Last but not least, let's see how the factorial problem can be solved with a Kotlin sequence. First, let's review the Clojure version:
Clojure
(defn factorial [n]
(apply * (take n (iterate inc 1))))
We take n values from a sequence that yields an incrementing number starting with 1 and accumulate them with the help of apply.
Kotlin
fun factorial(n: Int) = generateSequence(1) { it.inc() }.take(n).fold(1) { v1, v2 ->
v1 * v2
}
Kotlin offers fold which let's us accumulate the values easily.
I would like to loop through a vector starting from the nth element not 0;
How it looks like in Java:
for(int i = firstIndex; i <= lastIndex; i++) {
newText += contents[i] + " ";
}
If you are always dealing with a vector, then subvec is a good choice. For example:
(subvec contents firstIndex)
If you want to be compatible with sequences in general, you'll want to use drop. drop is O(n) w.r.t. the number of elements dropped, which subvec is always O(1). If you're only ever dropping a few elements, the difference is negligible. But for dropping a large number of elements (i.e., large firstIndex), subvec will be a clear winner. But subvec is only available on vectors.
You can use the drop function to skip first n elements and then loop over the result. For example, if you want to skip two first elements:
user=> (drop 2 [1 2 3 4])
(3 4)
The following can possibly do the same that the Java form you provided:
(require '[clojure.string :as str])
(str/join " " (drop first-index contents))
I expect the following code to return the (0,0) value. Yet I get a java object
(let [axs (make-array Long 5 5 0)]
(aget axs 0 0))
Also I got a type mismatch when trying to mutate index (0,0)
(let [axs (make-array Long 5 5 0)]
(aset axs 0 0 1))
I expect to have initialized a Long[5][5] java array to zero. What am I missing here?
Thanks
Third argument to make-array doesn't initialize your array with zeros, but adds third array dimension, which size is equal to zero. As a result, the size of your array is zero as well. To fix the issue, create your array as follows:
(make-array Long/TYPE 5 5)
This will create array of primitive longs and will initialize it with zeros.
vector<int> nums = {1, 2, 3};
vector<vector<int>> subsets = {{}};
for(int i=0; i<3; i++)
for(auto subset : subsets)
{
subset.push_back(nums[i]);
subsets.push_back(subset);
}
The content of subsets, after running, turns out to be:
[[] [1] [2] [2] [3] [3] [3] [3]]
However, I was expecting:
[[] [1] [2] [1 2] [3] [1 3] [2 3] [1 2 3]]
It seems like only the first element, which is an empty vector<int>, being considered.
Could you please tell me what exactly happened in terms of memory allocation?
PS: I also changed subsets.push_back(subset) into subsets.push_back(vector<int>(subset)), but it still gives the same incorrect result.
There are a few things that will not work as expected:
for(auto subset : subsets) Says "Give me a modifiable copy of the element."
Change auto to auto& to receive a modifiable reference.
Range-based for-loops are intended to be used to view a constant range of elements. If you modify the range the iterators will be invalidated. Use a standard for loop instead.