ByteArray to DoubleArray in Kotlin

huangapple go评论84阅读模式
英文:

ByteArray to DoubleArray in Kotlin

问题

以下是翻译好的内容:

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

我知道如何在Java中实现。但是AS转换器对此无效... ByteArray to DoubleArray in Kotlin

这是我想在Kotlin中编写的类:

class ByteArrayToDoubleArrayConverter {

    fun invoke(bytes: ByteArray): DoubleArray {
        val doubles = DoubleArray(bytes.size / 2)
        var i = 0

        for (n in 0 until bytes.size step 2) {
            doubles[i] = (bytes[n].toInt() and 0xFF) or (bytes[n + 1].toInt() shl 8)
            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])
    }
}

有什么想法吗?谢谢!

英文:

I want to extrapolate a byte array into a double array.

I know how to do it in Java. But the AS converter doesn't work for this... ByteArray to DoubleArray in Kotlin

This is the class I want to write in 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;
    }
}

This would be a typical example of what results are expected:

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])
    }
}

Any idea? Thanks!!!

答案1

得分: 3

我认为使用一个辅助函数会更清晰。下面是一个使用 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 那样自动进行类型提升;它也没有字节的位运算符重载。因此,在调用 andshl 之前,你需要显式地在每个字节上调用 toInt(),然后在结果上调用 toDouble()

结果是一段代码,代码长度更短,希望更易读,并且非常高效!(没有中间数组或列表,而且由于使用了 inline,甚至没有不必要的函数调用。)

(相比大多数 Kotlin 代码,它略显繁琐,因为原始数组不如基于引用的数组得到支持,而这些数组本身也不如列表得到支持。这主要是出于与 Java 兼容性相关的遗留原因。但可惜的是,ByteArray 没有 chunked() 的实现,否则就可以避免辅助函数了,尽管代价是一个临时列表。)

英文:

I think this would be clearest with a helper function.  Here's an extension function that uses a lambda to convert pairs of bytes into a DoubleArray:

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

That uses the DoubleArray constructor which takes an initialisation lambda as well as a size, so you don't need to loop through setting values after construction.

The required function then simply needs to know how to convert each pair of bytes into a double.  Though it would be more idiomatic as an extension function rather than a class:

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

You can then call it with e.g.:

bytes.toDoubleSamples()

(.toXxx() is the conventional name for a function which returns a transformed version of an object.  The standard name for this sort of function would be toDoubleArray(), but that normally converts each value to its own double; what you're doing is more specialised, so a more specialised name would avoid confusion.)

The only awkward thing there (and the reason why the direct conversion from Java fails) is that Kotlin is much more fussy about its numeric types, and won't automatically promote them the way Java and C do; it also doesn't have byte overloads for its bitwise operators.  So you need to call toInt() explicitly on each byte before you can call and and shl, and then call toDouble() on the result.

The result is code that is a lot shorter, hopefully much more readable, and also very efficient!  (No intermediate arrays or lists, and — thanks to the inline — not even any unnecessary function calls.)

(It's a bit more awkward than most Kotlin code, as primitive arrays aren't as well-supported as reference-based arrays — which are themselves not as well-supported as lists.  This is mainly for legacy reasons to do with Java compatibility.  But it's a shame that there's no chunked() implementation for ByteArray, which could have avoided the helper function, though at the cost of a temporary list.)

huangapple
  • 本文由 发表于 2020年10月1日 13:58:28
  • 转载请务必保留本文链接:https://go.coder-hub.com/64149846.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定