Kotlin problem with understanding piece of code - kotlin

I've just started learning programming and I'm having a problem understanding a piece of code from a tutorial. Could anyone explain what the Kotlin code below does?
Thank you
fun f(i:Int, list:MutableList<Int>) : Boolean {
for (number in list) {
if (i % number == 0) {
return false
}
}
return true
}
fun main(args:Array<String>) {
val result = mutableListOf<Int>()
for (number in 2..100) {
if (f(number, result)) {
result.append(number)
}
print(result.joinToString())
}

The main method creates a new list of integers. In a loop from 2 to 200 it calls the function f with current number of the loop (number) and the list created.
The function checks if the number handed over can be divided by any number in the list. In case it can be divided, false is returned, else true.
If the number couldn't be divided then the number is stored inside the list.
So it is a simple algorithm to find prime numbers. The list stores all so far found prime numbers. And the function checks if the number can be divided by any of the prime numbers.

f(...) checks whether i divides with any number in the list - if so, returns false.
main(..) loops through all numbers from 2..100 and adds numbers that don't divide with any number previously added to the list.
Basically, it will print all prime numbers between 2..100

Related

How to make an ordered list of boolean array permutations with a given number of trues

Is there an efficient method to generate all possible arrays of booleans with a given number of "true" values?
Right now I'm incrementing a number and checking if its binary representation has the given number of 1s (and if so, adding that array). But this becomes extremely slow for larger givens.
This is the kind of input-output that I'm looking for:
(length: 4, trues: 2) -> [[1,1,0,0],[1,0,1,0],[0,1,1,0],[1,0,0,1],[0,1,0,1],[0,0,1,1]]
The trouble is doing it in less than O(2^N), and so that they're ordered as the little endian binary representations would be.
If it helps the length would be a fixed number at compile time (currently it's 64). I wrote it as an input because I might have to increase it to 128, but it won't vary during runtime.
You can define a recursive solution to this problem.
fn solution(length: u32, trues: u32) -> Vec<Vec<bool>>;
How do we formulate this function recursively? Let's think about the last element of the output arrays. If that last element is false, then the amount of true elements in the 0..length-1 elements must be trues. If that last element is true, then the amount of true elements in the 0..length-1 elements must be trues-1.
So we can just answer the problem for (length-1, trues) and then extend them all with false, and answer the problem for (length-1, trues-1) and extend them all with true, and then we can combine the result (putting the ends-with-true case first for little endian ordering). Adding in some base cases, we get the following code:
fn solution(length: u32, trues: u32) -> Vec<Vec<bool>> {
if trues > length {
// no candidate arrays exist
return vec![];
}
if length == 0 {
// one array exists: the empty array
return vec![vec![]];
}
if trues == 0 {
// one array exists: the all-false array
return vec![vec![false; length as usize]];
}
let mut result = Vec::new();
for mut ones in solution(length-1, trues-1) {
ones.push(true);
result.push(ones);
}
for mut zeroes in solution(length-1, trues) {
zeroes.push(false);
result.push(zeroes);
}
result
}
If the time complexity for solution(L, T) is O(S(L,T)), then the time complexity of solution(L,T) can be recursively expressed as O(S(L-1,T-1) + S(L-1,T)), with the base cases S(0,0) = 1, S(L,L+1)=1, S(L,0) = L. This is the best achievable time complexity, since S(L,T) = S(L-1,T-1) + S(L-1,T) is also the recursive formula for how many arrays of length L and true-count T exist. This is also the same recurrence formula as the binomial recurrence equation, but the base cases are different. I will leave computing the time complexity as an exercise to the reader, and there are a couple of trivial optimizations to the above code that can be done to bring down the computation time further.

How to properly iterate over arrays in kotlin

I am currently learning kotlin and therefore following the kotlin track on exercism. The following exercise required me to calculate the Hamming difference between two Strings (so basically just counting the number of differences).
I got to the solution with the following code:
object Hamming {
fun compute(dnaOne: String, dnaTwo: String): Int {
if (dnaOne.length != dnaTwo.length) throw IllegalArgumentException("left and right strands must be of equal length.")
var counter = 0
for ((index, letter) in dnaOne.toCharArray().withIndex()) {
if (letter != dnaTwo.toCharArray()[index]) {
counter++
}
}
return counter
}
}
however, in the beginning I tried to do dnaOne.split("").withIndex() instead of dnaOne.toCharArray().withIndex() which did not work, it would literally stop after the first iteration and the following example
Hamming.compute("GGACGGATTCTG", "AGGACGGATTCT") would return 1 instead of the correct integer 9 (which only gets returned when using toCharArray)
I would appreciate any explanation
I was able to simplify this by using the built-in CharSequence.zip function because StringimplementsCharSequence` in Kotlin.
According to the documentation for zip:
Returns a list of pairs built from the characters of this and the [other] char sequences with the same index
The returned list has length of the shortest char sequence.
Which means we will get a List<Pair<Char,Char>> back (a list of pairs of letters in the same positions). Now that we have this, we can use Iterable.count to determine how many of them are different.
I implemented this as an extension function on String rather than in an object:
fun String.hamming(other: String): Int =
if(this.length != other.length) {
throw IllegalArgumentException("String lengths must match")
} else {
this.zip(other).count { it.first != it.second }
}
This also becomes a single expression now.
And to call this:
val ham = "GGACGGATTCTG".hamming("AGGACGGATTCT")
println("Hamming distance: $ham")

Returning the smallest value within an Array List

I need to write a method that returns me the smallest distance (which is a whole number value) within an Array List called "babyTurtles". There are 5 turtles within this array list and they all move a random distance each time the program is ran.
I've been trying to figure out how to do it for an hour and all I've accomplished is making myself frustrated and coming here.
p.s.
In my class we wrote this code to find the average distance moved by the baby turtles:
public double getAverageDistanceMovedByChildren() {
if (this.babyTurtles.size() == 0) {
return 0;
}
double sum = 0;
for (Turtle currentTurtle : this.babyTurtles) {
sum = sum + currentTurtle.getDistanceMoved();
}
double average = sum / this.babyTurtles.size();
return average;
}
That's all I've got to work on, but I just can't seem to find out how to do it.
I'd really appreciate it if you could assist me.
This will give you the index in the array list of the smallest number:
int lowestIndex = distanceList.indexOf(Collections.min(distanceList));
You can then get the value using this:
int lowestDistance = distanceList.get(lowestIndex);

Counter as variable in for-in-loops

When normally using a for-in-loop, the counter (in this case number) is a constant in each iteration:
for number in 1...10 {
// do something
}
This means I cannot change number in the loop:
for number in 1...10 {
if number == 5 {
++number
}
}
// doesn't compile, since the prefix operator '++' can't be performed on the constant 'number'
Is there a way to declare number as a variable, without declaring it before the loop, or using a normal for-loop (with initialization, condition and increment)?
To understand why i can’t be mutable involves knowing what for…in is shorthand for. for i in 0..<10 is expanded by the compiler to the following:
var g = (0..<10).generate()
while let i = g.next() {
// use i
}
Every time around the loop, i is a freshly declared variable, the value of unwrapping the next result from calling next on the generator.
Now, that while can be written like this:
while var i = g.next() {
// here you _can_ increment i:
if i == 5 { ++i }
}
but of course, it wouldn’t help – g.next() is still going to generate a 5 next time around the loop. The increment in the body was pointless.
Presumably for this reason, for…in doesn’t support the same var syntax for declaring it’s loop counter – it would be very confusing if you didn’t realize how it worked.
(unlike with where, where you can see what is going on – the var functionality is occasionally useful, similarly to how func f(var i) can be).
If what you want is to skip certain iterations of the loop, your better bet (without resorting to C-style for or while) is to use a generator that skips the relevant values:
// iterate over every other integer
for i in 0.stride(to: 10, by: 2) { print(i) }
// skip a specific number
for i in (0..<10).filter({ $0 != 5 }) { print(i) }
let a = ["one","two","three","four"]
// ok so this one’s a bit convoluted...
let everyOther = a.enumerate().filter { $0.0 % 2 == 0 }.map { $0.1 }.lazy
for s in everyOther {
print(s)
}
The answer is "no", and that's a good thing. Otherwise, a grossly confusing behavior like this would be possible:
for number in 1...10 {
if number == 5 {
// This does not work
number = 5000
}
println(number)
}
Imagine the confusion of someone looking at the number 5000 in the output of a loop that is supposedly bound to a range of 1 though 10, inclusive.
Moreover, what would Swift pick as the next value of 5000? Should it stop? Should it continue to the next number in the range before the assignment? Should it throw an exception on out-of-range assignment? All three choices have some validity to them, so there is no clear winner.
To avoid situations like that, Swift designers made loop variables in range loops immutable.
Update Swift 5
for var i in 0...10 {
print(i)
i+=1
}

Generate combinations ordered by an attribute

I'm looking for a way to generate combinations of objects ordered by a single attribute. I don't think lexicographical order is what I'm looking for... I'll try to give an example. Let's say I have a list of objects A,B,C,D with the attribute values I want to order by being 3,3,2,1. This gives A3, B3, C2, D1 objects. Now I want to generate combinations of 2 objects, but they need to be ordered in a descending way:
A3 B3
A3 C2
B3 C2
A3 D1
B3 D1
C2 D1
Generating all combinations and sorting them is not acceptable because the real world scenario involves large sets and millions of combinations. (set of 40, order of 8), and I need only combinations above the certain threshold.
Actually I need count of combinations above a threshold grouped by a sum of a given attribute, but I think it is far more difficult to do - so I'd settle for developing all combinations above a threshold and counting them. If that's possible at all.
EDIT - My original question wasn't very precise... I don't actually need these combinations ordered, just thought it would help to isolate combinations above a threshold. To be more precise, in the above example, giving a threshold of 5, I'm looking for an information that the given set produces 1 combination with a sum of 6 ( A3 B3 ) and 2 with a sum of 5 ( A3 C2, B3 C2). I don't actually need the combinations themselves.
I was looking into subset-sum problem, but if I understood correctly given dynamic solution it will only give you information is there a given sum or no, not count of the sums.
Thanks
Actually, I think you do want lexicographic order, but descending rather than ascending. In addition:
It's not clear to me from your description that A, B, ... D play any role in your answer (except possibly as the container for the values).
I think your question example is simply "For each integer at least 5, up to the maximum possible total of two values, how many distinct pairs from the set {3, 3, 2, 1} have sums of that integer?"
The interesting part is the early bailout, once no possible solution can be reached (remaining achievable sums are too small).
I'll post sample code later.
Here's the sample code I promised, with a few remarks following:
public class Combos {
/* permanent state for instance */
private int values[];
private int length;
/* transient state during single "count" computation */
private int n;
private int limit;
private Tally<Integer> tally;
private int best[][]; // used for early-bail-out
private void initializeForCount(int n, int limit) {
this.n = n;
this.limit = limit;
best = new int[n+1][length+1];
for (int i = 1; i <= n; ++i) {
for (int j = 0; j <= length - i; ++j) {
best[i][j] = values[j] + best[i-1][j+1];
}
}
}
private void countAt(int left, int start, int sum) {
if (left == 0) {
tally.inc(sum);
} else {
for (
int i = start;
i <= length - left
&& limit <= sum + best[left][i]; // bail-out-check
++i
) {
countAt(left - 1, i + 1, sum + values[i]);
}
}
}
public Tally<Integer> count(int n, int limit) {
tally = new Tally<Integer>();
if (n <= length) {
initializeForCount(n, limit);
countAt(n, 0, 0);
}
return tally;
}
public Combos(int[] values) {
this.values = values;
this.length = values.length;
}
}
Preface remarks:
This uses a little helper class called Tally, that just isolates the tabulation (including initialization for never-before-seen keys). I'll put it at the end.
To keep this concise, I've taken some shortcuts that aren't good practice for "real" code:
This doesn't check for a null value array, etc.
I assume that the value array is already sorted into descending order, required for the early-bail-out technique. (Good production code would include the sorting.)
I put transient data into instance variables instead of passing them as arguments among the private methods that support count. That makes this class non-thread-safe.
Explanation:
An instance of Combos is created with the (descending ordered) array of integers to combine. The value array is set up once per instance, but multiple calls to count can be made with varying population sizes and limits.
The count method triggers a (mostly) standard recursive traversal of unique combinations of n integers from values. The limit argument gives the lower bound on sums of interest.
The countAt method examines combinations of integers from values. The left argument is how many integers remain to make up n integers in a sum, start is the position in values from which to search, and sum is the partial sum.
The early-bail-out mechanism is based on computing best, a two-dimensional array that specifies the "best" sum reachable from a given state. The value in best[n][p] is the largest sum of n values beginning in position p of the original values.
The recursion of countAt bottoms out when the correct population has been accumulated; this adds the current sum (of n values) to the tally. If countAt has not bottomed out, it sweeps the values from the start-ing position to increase the current partial sum, as long as:
enough positions remain in values to achieve the specified population, and
the best (largest) subtotal remaining is big enough to make the limit.
A sample run with your question's data:
int[] values = {3, 3, 2, 1};
Combos mine = new Combos(values);
Tally<Integer> tally = mine.count(2, 5);
for (int i = 5; i < 9; ++i) {
int n = tally.get(i);
if (0 < n) {
System.out.println("found " + tally.get(i) + " sums of " + i);
}
}
produces the results you specified:
found 2 sums of 5
found 1 sums of 6
Here's the Tally code:
public static class Tally<T> {
private Map<T,Integer> tally = new HashMap<T,Integer>();
public Tally() {/* nothing */}
public void inc(T key) {
Integer value = tally.get(key);
if (value == null) {
value = Integer.valueOf(0);
}
tally.put(key, (value + 1));
}
public int get(T key) {
Integer result = tally.get(key);
return result == null ? 0 : result;
}
public Collection<T> keys() {
return tally.keySet();
}
}
I have written a class to handle common functions for working with the binomial coefficient, which is the type of problem that your problem falls under. It performs the following tasks:
Outputs all the K-indexes in a nice format for any N choose K to a file. The K-indexes can be substituted with more descriptive strings or letters. This method makes solving this type of problem quite trivial.
Converts the K-indexes to the proper index of an entry in the sorted binomial coefficient table. This technique is much faster than older published techniques that rely on iteration. It does this by using a mathematical property inherent in Pascal's Triangle. My paper talks about this. I believe I am the first to discover and publish this technique, but I could be wrong.
Converts the index in a sorted binomial coefficient table to the corresponding K-indexes.
Uses Mark Dominus method to calculate the binomial coefficient, which is much less likely to overflow and works with larger numbers.
The class is written in .NET C# and provides a way to manage the objects related to the problem (if any) by using a generic list. The constructor of this class takes a bool value called InitTable that when true will create a generic list to hold the objects to be managed. If this value is false, then it will not create the table. The table does not need to be created in order to perform the 4 above methods. Accessor methods are provided to access the table.
There is an associated test class which shows how to use the class and its methods. It has been extensively tested with 2 cases and there are no known bugs.
To read about this class and download the code, see Tablizing The Binomial Coeffieicent.
Check out this question in stackoverflow: Algorithm to return all combinations
I also just used a the java code below to generate all permutations, but it could easily be used to generate unique combination's given an index.
public static <E> E[] permutation(E[] s, int num) {//s is the input elements array and num is the number which represents the permutation
int factorial = 1;
for(int i = 2; i < s.length; i++)
factorial *= i;//calculates the factorial of (s.length - 1)
if (num/s.length >= factorial)// Optional. if the number is not in the range of [0, s.length! - 1]
return null;
for(int i = 0; i < s.length - 1; i++){//go over the array
int tempi = (num / factorial) % (s.length - i);//calculates the next cell from the cells left (the cells in the range [i, s.length - 1])
E temp = s[i + tempi];//Temporarily saves the value of the cell needed to add to the permutation this time
for(int j = i + tempi; j > i; j--)//shift all elements to "cover" the "missing" cell
s[j] = s[j-1];
s[i] = temp;//put the chosen cell in the correct spot
factorial /= (s.length - (i + 1));//updates the factorial
}
return s;
}
I am extremely sorry (after all those clarifications in the comments) to say that I could not find an efficient solution to this problem. I tried for the past hour with no results.
The reason (I think) is that this problem is very similar to problems like the traveling salesman problem. Until unless you try all the combinations, there is no way to know which attributes will add upto the threshold.
There seems to be no clever trick that can solve this class of problems.
Still there are many optimizations that you can do to the actual code.
Try sorting the data according to the attributes. You may be able to avoid processing some values from the list when you find that a higher value cannot satisfy the threshold (so all lower values can be eliminated).
If you're using C# there is a fairly good generics library here. Note though that the generation of some permutations is not in lexicographic order
Here's a recursive approach to count the number of these subsets: We define a function count(minIndex,numElements,minSum) that returns the number of subsets of size numElements whose sum is at least minSum, containing elements with indices minIndex or greater.
As in the problem statement, we sort our elements in descending order, e.g. [3,3,2,1], and call the first index zero, and the total number of elements N. We assume all elements are nonnegative. To find all 2-subsets whose sum is at least 5, we call count(0,2,5).
Sample Code (Java):
int count(int minIndex, int numElements, int minSum)
{
int total = 0;
if (numElements == 1)
{
// just count number of elements >= minSum
for (int i = minIndex; i <= N-1; i++)
if (a[i] >= minSum) total++; else break;
}
else
{
if (minSum <= 0)
{
// any subset will do (n-choose-k of them)
if (numElements <= (N-minIndex))
total = nchoosek(N-minIndex, numElements);
}
else
{
// add element a[i] to the set, and then consider the count
// for all elements to its right
for (int i = minIndex; i <= (N-numElements); i++)
total += count(i+1, numElements-1, minSum-a[i]);
}
}
return total;
}
Btw, I've run the above with an array of 40 elements, and size-8 subsets and consistently got back results in less than a second.