相当于我的F#功能代码的Kotlin代码

时间:2018-02-10 15:55:56

标签: kotlin

任何人都可以帮助我将以下F#代码转换为Kotlin

//namespace SysIO

open System.Collections.Generic  // for Dictionary

printf "Hi, Let's start \n"

let series = [|30;21;29;31;40;48;53;47;37;39;31;29;17;9;20;24;27;35;41;38;
          27;31;27;26;21;13;21;18;33;35;40;36;22;24;21;20;17;14;17;19;
          26;29;40;31;20;24;18;26;17;9;17;21;28;32;46;33;23;28;22;27;
          18;8;17;21;31;34;44;38;31;30;26;32|]

let initialSeasonalComponents (series : int []) slen : IDictionary<int, double>  =
    let nSeasons = float  (series.Length / slen)
    let grouped = 
        series 
            |> Array.map float 
            |> Array.chunkBySize slen
    let seasonAverages = grouped |> Array.map Array.average
    Array.init slen (fun i -> i, (Array.zip grouped seasonAverages 
                                    |> Array.fold (fun s (els, av) -> els.[i] + s - av) 0.)
                                        / nSeasons) |> dict

printfn "Seasons Averageß: \n %A" (initialSeasonalComponents series 12)

let initialTrend (series : int []) (slen : int) : double =
     series |> Array.windowed slen
            |> Array.fold (fun s x -> 
                            (x |> Array.rev |> Array.head) -  (x |> Array.head) + s) 0
            |> float
            |> fun x -> x / (float slen)

printfn "Initial Trend: \n %A" (initialTrend series 12)

let tripleExponentialSmoothing series slen alpha beta gamma nPreds =
    let mutable smooth = 0.
    let mutable trend = 0.
    let seasonals = initialSeasonalComponents series 12 |> Dictionary 
    seq {
        for i in 0..(series.Length+nPreds-1) do
          match i with
          | 0 ->     // initial values        
              smooth <- series |> Array.head |> float
              trend <- initialTrend series slen
              yield series |> Array.head |> float
          | i when i >= series.Length -> // we are forecasting
              let m = i - series.Length + 1
              yield (smooth + float m * trend) + seasonals.[i%slen]
          | _ -> 
              let v = series |> Array.head  |> float
              let lastSmooth = smooth
              smooth <- alpha*(v-seasonals.Item(i%slen)) + (1.-alpha)*(smooth+trend)
              trend <- beta * (smooth-lastSmooth) + (1.-beta)*trend
              seasonals.[i%slen] <- gamma*(v-smooth) + (1.-gamma)*seasonals.[i%slen]
              yield smooth + trend + seasonals.Item(i%slen) }
   // result

let f = tripleExponentialSmoothing series 12 0.716 0.029 0.993 24
printfn "Forecast: \n %A" f

1 个答案:

答案 0 :(得分:0)

我发现的主要问题是找到一个与pipeOperator |>等效的运算符,然后我找到了三个可能的替代方案:

使用.let 使用.run 使用infix function

以下示例对我来说是一个很好的启动来解决我的问题:

fun main(args: Array<String>) {
    var a = 3
    val b: Int = 6


    println("Hello World! doubling, then tripling the sume of $a and $b is " +
            "${(sumx(a,b)
                    next ::dbl
                    next ::trpl
                    )}")

    println("Hello World! doubling, then tripling the sume of $a and $b is " +
            "${(sumx(a,b)
                    .let (::dbl)
                    .let (::trpl)
                    )}")
    println("Hello World! doubling, then tripling the sume of $a and $b is " +
            "${(sumx(a,b)
                    .run (::dbl)
                    .run (::trpl)
                    )}")

    println("Hello World! doubling, then tripling the sume of $a and $b is " +
            "${(sumx(a,b)
                    into (::dbl)
                    into (::trpl)
                    )}")
}

fun sumx (x: Int, y: Int) : Int = x + y
fun dbl (x: Int): Int = x * 2
fun trpl (x: Int): Int = x * 3

infix fun <T, R> T.next(map : (T) -> R) : R = map(this)
infix fun <T, R> T.into(func: (T) -> R) = func(this)

<强>更新

我使用此命令创建了gradle项目:gradle init --type java-library

删除了src/mainsrc/test文件夹

创建了src/kotlinsrc/resources个文件夹

src/kotlin/Main.kt创建我的文件,如下所示:

import kotlin.coroutines.experimental.buildSequence

fun main(args: Array<String>) {
    println("Hi, Let's start")

    val series = listOf(
            30, 21, 29, 31, 40, 48, 53, 47, 37, 39, 31, 29, 17, 9, 20, 24, 27, 35, 41, 38,
            27, 31, 27, 26, 21, 13, 21, 18, 33, 35, 40, 36, 22, 24, 21, 20, 17, 14, 17, 19,
            26, 29, 40, 31, 20, 24, 18, 26, 17, 9, 17, 21, 28, 32, 46, 33, 23, 28, 22, 27,
            18, 8, 17, 21, 31, 34, 44, 38, 31, 30, 26, 32
    )

    fun initialSeasonalComponents(series: List<Int>, slen: Int): Map<Int, Double> {
        val nSeasons = (series.size / slen).toFloat()
        val grouped = series.map { it.toFloat() }.chunked(slen)
        val seasonAverages = grouped.map { it.average() }
        return (0 until slen).associate {
            Pair(it, grouped.zip(seasonAverages)
                    .fold(0.0) { s, (els, av) -> els[it] + s - av }
                    / nSeasons)
        }
    }

    println("Seasons Averageß: \n ${initialSeasonalComponents(series, 12)}")

    fun initialTrend(series: List<Int>, slen: Int): Double =
            series.windowed(slen)
                    .fold(0) { s, x -> x.last() - x.first() + s }
                    .toFloat() / slen.toDouble()

    println("Initial Trend: \n ${initialTrend(series, 12)}")

    fun tripleExponentialSmoothing(series: List<Int>, slen: Int, alpha: Double, beta: Double, gamma: Double, nPreds: Int): Sequence<Double> {
        var smooth = 0.0
        var trend = 0.0
        val seasonals = initialSeasonalComponents(series, 12).toMutableMap()
        return buildSequence {
            for (i in 0 until (series.size + nPreds)) {
                when {
                    i == 0 -> {
                        smooth = series.first().toDouble()
                        trend = initialTrend(series, slen)
                        yield(series.first().toDouble())
                    }
                    i >= series.size -> {
                        val m = i - series.size + 1
                        yield((smooth + m * trend) + (seasonals[i % slen] ?: 0.0 /* Need default values because of null safety */))
                    }
                    else -> {
                        val v = series.first().toDouble()
                        val lastSmooth = smooth
                        smooth = alpha * (v - (seasonals[i % slen] ?: 0.0)) + (1.0 - alpha) * (smooth + trend)
                        trend = beta * (smooth - lastSmooth) + (1.0 - beta) * trend
                        seasonals[i % slen] = gamma * (v - smooth) + (1.0 - gamma) * (seasonals[i % slen] ?: 0.0)
                        yield(smooth + trend + (seasonals[i % slen] ?: 0.0))
                    }
                }
            }
        }
    }

    val f = tripleExponentialSmoothing(series, 12, 0.716, 0.029, 0.993, 24).toList()
    val res = f.map {it.format(2)} // used to format the numbers, can be avoided.

    println("Forecast: \n $res")
}

fun Double.format(digits: Int) = java.lang.String.format("%.${digits}f", this) // Extension function to format the numbers

0.0fold函数的初始状态,{ s, (els, av) -> }是应用于每个元素的操作,其中s是累加器,(els, av)是当前元素(在本例中为地图的条目),已经解构1,将els作为关键字,av作为当前条目的值。

我的gradle.build是:

buildscript {
    ext.kotlin_version = '1.2.21'

    repositories {
        mavenCentral()
    }
    dependencies {
        classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"   // for gradle build
    }
}
apply plugin: 'kotlin'

repositories {     jcenter()    }

dependencies {
    compile "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
}

sourceSets.main {
    kotlin.srcDirs += 'src/kotlin'
    resources.srcDirs += 'src/resources'
}

jar {
    baseName 'myApp'
    manifest.attributes 'Main-Class': 'MainKt'  // '[namespace].[arctifact/file]Kt'
    from { configurations.compile.collect { it.isDirectory() ? it : zipTree(it) } }
}

生成的jar文件保存在build/libs/MyApp.jar,我使用命令java -jar myApp.jar

运行它