Get Factors of Numbers in Kotlin

2019-09-21 09:51发布

问题:

Brand new to Kotlin, how can I find the factors of a number?

For example 24 should give 1, 2, 3, 4, 6, 8, 12, 24?

I know how to do this python with a list comprehension but not sure how to do it properly in Kotlin.

回答1:

Not sure how you could do a "list comprehension" in Kotlin but instead you can use a function like factorsOfNumbers below:

fun factorsOfNumber(num: Int) : MutableList<Int> {
  val factors = mutableListOf<Int>()
  if (num < 1) 
    return factors
  (1..num / 2)
    .filter { num % it == 0 }
    .forEach { factors.add(it) }
  factors.add(num)
  return factors
}

fun main(args: Array<String>) {
  val number = 24
  println("The factors of $number are: " + factorsOfNumber(number).joinToString())
}

Output:

The factors of 24 are: 1, 2, 3, 4, 6, 8, 12, 24

Relevant documentation to understand how it works is below:

  • Collections: List, Set, Map (MutableList stuff)
  • Ranges (The (1..num / 2) part)
  • Kotlin Idioms (Everything else)


回答2:

Let's see the exact equivalent between Python and Kotlin...

In Python, the code would be:

N = 24

factors = [n for n in range(1, N + 1) if N % n == 0]

print(factors)
# outputs [1, 2, 3, 4, 6, 8, 12, 24]

Which is not lazy, and materializes as a list. In Kotlin this is:

val N = 24

val factors = (1..N).filter { N % it == 0 }

println(factors)
// outputs [1, 2, 3, 4, 6, 8, 12, 24]

If you want to make this slightly more efficient:

val factors = (1..N/2).filter { N % it == 0 } + N

Now since this is not lazy, it does one copy of the factor results to add the final N value, although that list would be a lot smaller than the original. And sometimes an eager copy of smaller data structures is faster than a lazy evaluation.

You can make this whole thing lazy lazy, and process it incrementally taking only the values you want:

val factors = (1..N).asSequence().filter { N % it == 0 }

or the variant of only processing half the values:

val factors = (1..N/2).asSequence().filter { N % it == 0 } + N

Both of these result in a sequence that can be read lazily and chained with other functions.

You can also use co-routines to write a function that lazily yields the values, and here is written as an extension function on Int:

fun Int.factorsSequence(): Sequence<Int> {
    val N = this
    return buildSequence {
        (1..N/2).forEach {
            if (N % it == 0) yield(it)
        }
        yield(N)
    }
}

Which can be called like:

val factors = 24.factorsSequence()
println(factors.toList()) // convert to list just for printing

Of course, any of the other implementations can be made extension functions as well.

fun Int.factorsList(): List<Int> = 
    (1..this/2).filter { this % it == 0 } + this

val factors = 24.factorsList()
println(factors) 


标签: python kotlin