首页 > 解决方案 > Kotlin:直到n的素数列表

问题描述

我正在尝试在 kotlin 中创建一个函数来返回素数列表,直到输入参数 n。我试过下面的代码,但它返回的列表包含多个相同的数字。

/**
 * You can edit, run, and share this code. 
 * play.kotlinlang.org 
 */

fun main() {
    
    fun primes(n : Int):MutableList<Int>{
        var li : MutableList<Int> = mutableListOf(2)
        for(num in 2..n+1){
            for(i in 2..num){
                if(num % i == 0)
                break
                else
                li.add(num)
            }
        }
        return li
    }
    
    print(primes(7))
}

输出 :

[2, 3, 5, 5, 5, 7, 7, 7, 7, 7]

我的代码有什么问题?

标签: kotlin

解决方案


这是一个可以用更多函数式代码替换循环的主要示例(!)——在这种情况下,none()函数:

fun primes(n: Int): MutableList<Int> {
    val li = mutableListOf<Int>()
    for (num in 2..n) {
        if ((2 until num).none{ num % it == 0 })
            li.add(num)
    }
    return li
}

解释一下:none()只有当 lambda 为列表的每个项目都返回 false 时,该函数才返回 true。并且it表示参数值(想象it ->在 lambda 中)。所以它正在检查 num 是否可以除以从 2 到 num-1 的任何数字(这当然是素数的定义)。这不仅更短,而且希望更容易阅读。(当然,一旦你习惯了函数式风格。)

事实上,你也可以替换外循环,让整个事情变成一个单行:

fun primes(n: Int)
    = (2..n).filter{ num -> (2 until num).none{ num % it == 0 } }

该版本纯粹是功能性的,但可能有点过于压缩而难以阅读。它取从 2 到 n 的数字,并且只保留那些是素数的(如上所述)。(filter()返回一个列表,因此无需手动创建。)

然而,在算法方面,没有必要检查每个可能的除数,直到你正在测试的数字——你只需要检查主要的除数。这是一种更有效的方法。因为它使用你已经找到的素数列表,所以你不能filter()像第二个例子那样简单地做到这一点。但是您可以轻松地调整第一个示例来做到这一点:只需将 替换if ((2 until num).none{if (li.none{.


推荐阅读