首页 > 解决方案 > Kotlin 中的 ByteArray 到 DoubleArray

问题描述

我想将一个字节数组外推为一个双精度数组。

我知道如何在 Java 中做到这一点。但是 AS 转换器不适用于此... :-D

这是我想用 Kotlin 编写的课程:

class ByteArrayToDoubleArrayConverter {

    public double[] invoke(byte[] bytes) {
        double[] doubles = new double[bytes.length / 2];
        int i = 0;

        for (int n = 0; n < bytes.length; n = n + 2) {
            doubles[i] = (bytes[n] & 0xFF) | (bytes[n + 1] << 8);
            i = i + 1;
        }

        return doubles;
    }
}

这将是预期结果的典型示例:

class ByteArrayToDoubleArrayConverterTest {

    @Test
    fun `check typical values`() {
        val bufferSize = 8
        val bytes = ByteArray(bufferSize)
        bytes[0] = 1
        bytes[1] = 0

        bytes[2] = 0
        bytes[3] = 1

        bytes[4] = 0
        bytes[5] = 2

        bytes[6] = 1
        bytes[7] = 1
        val doubles = ByteArrayToDoubleArrayConverter().invoke(bytes)
        assertTrue(1.0 == doubles[0])
        assertTrue(256.0 == doubles[1])
        assertTrue(512.0 == doubles[2])
        assertTrue(257.0 == doubles[3])
    }
}

任何想法?谢谢!!!

标签: javaarrayskotlin

解决方案


我认为使用辅助功能会最清楚。这是一个使用 lambda 将字节对转换为 DoubleArray 的扩展函数:

inline fun ByteArray.mapPairsToDoubles(block: (Byte, Byte) -> Double)
    = DoubleArray(size / 2){ i -> block(this[2 * i], this[2 * i + 1]) }

这使用了 DoubleArray 构造函数,该构造函数接受初始化 lambda 和大小,因此您无需在构造后循环设置值。

然后,所需的函数只需要知道如何将每对字节转换为双精度。虽然它作为扩展函数而不是类会更惯用:

fun ByteArray.toDoubleSamples() = mapPairsToDoubles{ a, b ->
    (a.toInt() and 0xFF or (b.toInt() shl 8)).toDouble()
}

然后你可以用例如调用它:

bytes.toDoubleSamples()

(.toXxx()是返回对象的转换版本的函数的常规名称。这种函数的标准名称是toDoubleArray(),但通常会将每个值转换为自己的双精度值;您正在做的事情更专业,所以更专业的名称会避免混淆。)

那里唯一尴尬的事情(以及从 Java 直接转换失败的原因)是 Kotlin 对其数字类型更加挑剔,并且不会像 Java 和 C 那样自动提升它们;它的位运算符也没有字节重载。因此,您需要在调用andtoInt()之前显式调用每个字节,然后调用结果。andshltoDouble()

结果是代码更短,希望更具可读性,而且非常高效!(没有中间数组或列表,而且——多亏了inline——甚至没有任何不必要的函数调用。)

(它比大多数 Kotlin 代码更尴尬,因为原始数组不像基于引用的数组那样得到很好的支持——它们本身不像列表那样得到很好的支持。这主要是出于与 Java 兼容性有关的遗留原因。但遗憾的是,没有chunked()实现 ByteArray,它本可以避免使用辅助函数,尽管代价是临时列表。)


推荐阅读