英文:
Most efficient way to convert digits in an int to ASCII values?
问题
我有一个方法,它接受一个1到8位的正数或负数 int
作为输入,并将每个数字转换为其对应的ASCII值,同时保持数字的顺序。我希望它尽可能地内存和时间高效,因此我想避免不必要的循环、临时变量和引用数据类型。
例如,参见下表,其中列出了每个数字的ASCII值:
输入:int value = 185
输出:byte[] byteArray = [49, 56, 53]
数字 | ASCII值 |
---|---|
1 | 49 |
8 | 56 |
5 | 53 |
我目前有一个天真的方法,首先必须将其转换为一个字符串,但是否有更好的解决方案?
public byte[] DigitsToAsciiArr(int value) {
String strValue = String.valueOf(value);
byte[] byteArray = new byte[strValue.length()];
for (int i = 0; i < strValue.length(); i++) {
byteArray[i] = (byte) strValue.charAt(i);
}
return byteArray;
}
英文:
I got a method which takes a positive or negative int
of 1 - 8 digits as input and converts every digit into its corresponding ASCII value while preserving the order of the digits. I want it to be as memory and time efficient as possible, so I want to avoid unnecessary loops, temporary variables and reference data types.
Example, see table below with ASCII values for each digit:
input: int value = 185
output: byte[] byteArray = [49, 56, 53]
Digit | ASCII-value |
---|---|
1 | 49 |
8 | 56 |
5 | 53 |
What I currently have is this naive method where I first have to convert it to a String, but is there a better solution?
public byte[] DigitsToAsciiArr(int value) {
String strValue = String.valueOf(value);
byte[] byteArray = new byte[strValue.length()];
for (int i = 0; i < strValue.length(); i++) {
byteArray[i] = (byte) strValue.charAt(i);
}
return byteArray;
}
答案1
得分: 3
以下是已翻译的代码部分:
这是一个相对简单的实现。为了简单起见,它不支持负数。支持负数的版本如下。代码中有注释。
public static byte[] asciiDigits(int value) {
if (value < 0) throw new IllegalArgumentException();
// 从最低有效位开始迭代
byte[] reverseOrder = new byte[10];
int digits = 0;
for (; value > 0; ++digits) {
int digit = value % 10;
reverseOrder[digits] = (byte) ('0' + digit);
value /= 10;
}
// 现在将数组大小调整到正确的大小并反转它
byte[] bytes = new byte[digits];
for (int i = 0; i < digits; ++i) {
bytes[i] = reverseOrder[digits - i - 1];
}
return bytes;
}
这个版本支持负数。基本思路是将其转换为正数,执行相同的步骤,然后附加负号。
public static byte[] asciiDigits(int value) {
boolean isNegative = false;
if (value < 0) {
// 唯一不可表示绝对值的值,因此只需硬编码数组
if (value == Integer.MIN_VALUE) {
return new byte[] { 45, 50, 49, 52, 55, 52, 56, 51, 54, 52, 56 };
}
value = -value;
isNegative = true;
}
// 从最低有效位开始迭代。
// 我们还不知道可能有多少位数,但是一个int可能有的最多位数是10
byte[] reverseOrderBytes = new byte[10];
int digits = 0;
for (; value > 0; ++digits) {
int digit = value % 10;
reverseOrderBytes[digits] = (byte) ('0' + digit);
value /= 10;
}
// 现在将数组大小调整为正确的大小,并反转它,可能会添加一个减号
int signAdjustment = isNegative ? 1 : 0;
byte[] bytes = new byte[digits + signAdjustment];
if (isNegative) {
bytes[0] = 45; // 减号
}
for (int i = 0; i < digits; ++i) {
bytes[i + signAdjustment] = reverseOrderBytes[digits - i - 1];
}
return bytes;
}
临时数组似乎是最明显的要删除的候选项,因此我编写了一个版本,首先计算数字的数量(进行了几次比较),然后从最低有效位开始迭代,但是从后向前写入数组。
public static byte[] asciiDigits(int value) {
if (value == Integer.MIN_VALUE) {
return new byte[] { 45, 50, 49, 52, 55, 52, 56, 51, 54, 52, 56 };
}
int numDigits = numDigits(value);
boolean isNegative = value < 0;
int signAdjustment = isNegative ? 1 : 0;
byte[] bytes = new byte[numDigits + signAdjustment];
if (isNegative) {
bytes[0] = 45; // 减号
value = -value;
}
for (int i = 0; i < numDigits; ++i) {
int digit = value % 10;
bytes[numDigits + signAdjustment - i - 1] = (byte) ('0' + digit);
value /= 10;
}
return bytes;
}
private static int numDigits(int n) {
if (n < 0) {
n = -n;
}
if (n < 100000) {
if (n < 100) {
if (n < 10) return 1;
return 2;
}
else {
if (n < 1000) return 3;
if (n < 10000) return 4;
return 5;
}
}
else {
if (n < 10000000) {
if (n < 1000000) return 6;
return 7;
}
else {
if (n < 100000000) return 8;
if (n < 1000000000) return 9;
return 10;
}
}
}
请注意,这些代码段是Java代码,已经翻译成中文。
英文:
Here's a relatively simple implementation. It doesn't support negative numbers, for simplicity. A version that does is below. Comments are in-line in the code.
public static byte[] asciiDigits(int value) {
if (value < 0) throw new IllegalArgumentException();
// Iterate through least-significant digits first
byte[] reverseOrder = new byte[10];
int digits = 0;
for (; value > 0; ++digits) {
int digit = value % 10;
reverseOrder[digits] = (byte) ('0' + digit);
value /= 10;
}
// Now size down the array to the right size and reverse it
byte[] bytes = new byte[digits];
for (int i = 0; i < digits; ++i) {
bytes[i] = reverseOrder[digits - i - 1];
}
return bytes;
}
And this one supports negatives. The basic idea is to convert it to a positive number, do all the same steps, and append the minus sign.
public static byte[] asciiDigits(int value) {
boolean isNegative = false;
if (value < 0) {
// The only value where the absolute value is not representable, so just hardcode the array
if (value == Integer.MIN_VALUE) {
return new byte[] { 45, 50, 49, 52, 55, 52, 56, 51, 54, 52, 56 };
}
value = -value;
isNegative = true;
}
// Iterate through least-significant digits first.
// We don't yet know how many digits there may be, but 10 is the most digits an int could have
byte[] reverseOrderBytes = new byte[10];
int digits = 0;
for (; value > 0; ++digits) {
int digit = value % 10;
reverseOrderBytes[digits] = (byte) ('0' + digit);
value /= 10;
}
// Now reduce the size of the array to the correct size and reverse it, possibly prepending a minus sign
int signAdjustment = isNegative ? 1 : 0;
byte[] bytes = new byte[digits + signAdjustment];
if (isNegative) {
bytes[0] = 45; // minus sign
}
for (int i = 0; i < digits; ++i) {
bytes[i + signAdjustment] = reverseOrderBytes[digits - i - 1];
}
return bytes;
}
The temporary array seems like the most obvious candidate for removal, so I wrote a version that calculates the number of digits first (a couple of comparisons), then iterates through the least-significant digits first, but writes to the array back-to-front.
The numDigits
method was from this answer to another question.
public static byte[] asciiDigits(int value) {
if (value == Integer.MIN_VALUE) {
return new byte[] { 45, 50, 49, 52, 55, 52, 56, 51, 54, 52, 56 };
}
int numDigits = numDigits(value);
boolean isNegative = value < 0;
int signAdjustment = isNegative ? 1 : 0;
byte[] bytes = new byte[numDigits + signAdjustment];
if (isNegative) {
bytes[0] = 45; // minus sign
value = -value;
}
for (int i = 0; i < numDigits; ++i) {
int digit = value % 10;
bytes[numDigits + signAdjustment - i - 1] = (byte) ('0' + digit);
value /= 10;
}
return bytes;
}
private static int numDigits(int n) {
if (n < 0) {
n = -n;
}
if (n < 100000) {
if (n < 100) {
if (n < 10) return 1;
return 2;
}
else {
if (n < 1000) return 3;
if (n < 10000) return 4;
return 5;
}
}
else {
if (n < 10000000) {
if (n < 1000000) return 6;
return 7;
}
else {
if (n < 100000000) return 8;
if (n < 1000000000) return 9;
return 10;
}
}
}
I haven't benchmarked any of these. The third version intuitively seems the best, but it's often hard to predict.
答案2
得分: 1
以下是翻译好的部分:
主要问题在于从以二进制形式存储的数字中提取各个十进制数字。最简单的方法是将其转换为可读的形式(本质上是一个字符串),然后迭代处理每个数字。但这正是您想要避免的。
您还可以使用模运算符逐个处理每个数字,该运算符在每次迭代中输出最后一个数字。因此,您需要颠倒输出的顺序。
public static byte[] digitsToAsciiArr(int value) {
Stack<Byte> stack = new Stack<>();
while(value != 0) {
//这获取了最后一个数字:
int digit = value%10;
//+48将数字转换为其ASCII值
stack.push((byte) (digit+48));
value /= 10;
}
//由于上面的循环处理了从最后到第一个的数字,
// 使用堆栈来颠倒顺序以得到输出。
// 从这里,只需将堆栈转换为byte[]
// 如果您愿意返回Byte[]而不是byte[],
// 可以简化为:
// return stack.toArray(Byte[]::new);
byte[] ret = new byte[stack.size()];
int index = 0;
while(!stack.isEmpty()) {
ret[index++] = stack.pop();
}
return ret;
}
请注意,上述代码是用Java编写的,用于将整数的各个数字转换为ASCII字符数组。
英文:
The main problem here is extracting individual decimal digits from a number that is stored in binary. The easiest way is to convert it into a human-readable form (a String essentially), then iterating over the digits. But that is what you want to avoid
You can also handle each digit one by one by using the modulo operator, which spits out the last digit on each iteration. So you need to reverse the order of the output.
public static byte[] digitsToAsciiArr(int value) {
Stack<Byte> stack = new Stack<>();
while(value != 0) {
//this gets the last digit:
int digit = value%10;
//the +48 shifts the digit to its ascii value
stack.push((byte) (digit+48));
value /= 10;
}
//since the loop above handles the digits from last to first,
// a stack is used to reverse the order for the output.
//From here, just convert the stack to a byte[]
//If you are fine returning Byte[] instead of byte[],
// this can be shortened to just
// return stack.toArray(Byte[]::new);
byte[] ret = new byte[stack.size()];
int index = 0;
while(!stack.isEmpty()) {
ret[index++] = stack.pop();
}
return ret;
}
答案3
得分: 0
假设只有数字,最多有8位非负数:
byte[] digits(int n) {
byte[] b = new byte[8];
int i = b.length - 1;
while (n != 0) {
b[i] = (byte)('0' + (n % 10));
--i;
n /= 10;
}
return b;
}
未处理的特殊情况:
- 负数
- 0应该产生48;这里是0
- 超过8位数
它是最佳的,因为循环会在数字的位数上退出。
英文:
Assuming only digits, non-negative numbers of at most 8 digits:
byte[] digits(int n) {
byte[] b = new byte[8];
int i = b.length - 1;
while (n != 0) {
b[i] = (byte)('0'| (n % 10));
--i;
n /= 10;
}
return b;
}
The special cases not dealt with:
- negative numbers
- 0 which should yield 48; here 0
- more than 8 digits
It is optimal as the loop exits on the number of digits.
答案4
得分: 0
以下是您提供的代码的翻译部分:
// 如果值为0,则返回包含'0'的数组。这种特殊情况可以减少后续所需的代码。
// 然后确定值是否为负数。如果是,将其转换为正数并将ndigits增加1以腾出负号的位置。
// 然后通过使用余数函数来确定最大位数,以调整原始值中的nDigits。最大幂为10_000_000,对应八位数。(发现这比使用Math.log更快)。
// 然后基于位数和符号(如果存在)分配数组大小。
// 假设为负数,并将减号添加到数组的第一个位置,如果是正数则会被覆盖。
public static byte[] DigitsToAsciiArr(int value) {
if (value == 0) {
return new byte[]{'0'};
}
int power = 10_000_000; // 最大位数的最大幂。
int nDigits = 8; // 最大位数。
if (value <= 0) {
value = -value;
nDigits++;
}
// 调整以分配数组大小
while (value % power == value) {
power /= 10;
nDigits--;
}
byte[] bytes = new byte[nDigits];
bytes[0] = '-'; // 可能会被覆盖。
while (value > 0) {
bytes[--nDigits] = (byte) (value % 10 + '0');
value /= 10;
}
return bytes;
}
演示代码:
int[] testData = new int[] {0, -1, 1, 185, -185, 12345678, -12345678};
for (int value : testData) {
byte[] bytes = DigitsToAsciiArr(value);
System.out.printf("%9d -> %s%n", value, Arrays.toString(bytes));
}
打印结果:
0 -> [48]
-1 -> [45, 49]
1 -> [49]
185 -> [49, 56, 53]
-185 -> [45, 49, 56, 53]
12345678 -> [49, 50, 51, 52, 53, 54, 55, 56]
-12345678 -> [45, 49, 50, 51, 52, 53, 54, 55, 56]
请注意,这是提供的代码的翻译版本,没有其他额外的内容。
英文:
- First, return array of
'0'
if value is0
. Special case reduces required code later. - Then determine if value is negative. If so, convert to positive and increase
ndigits
by by 1 to make room for minus sign. - then determine max digits by using the remainder function for change in the original value adjusting
nDigits
in the process. Max power would be10_000_000
for eight digits. (found this was faster than using Math.log). - then allocate array size based on digits and sign if present.
- assume negative and add minus sign in first position of array.
- then get each digit using the remainder operator, convert to a byte and store in reverse order. Minus sign will be overwritten if positive number.
public static byte[] DigitsToAsciiArr(int value) {
if (value == 0) {
return new byte[]{'0'};
}
int power = 10_000_000; // max power for max digits.
int nDigits = 8; // max digits.
if (value <= 0) {
value = -value;
nDigits++;
}
// adjust to allocate array size
while (value % power == value) {
power /= 10;
nDigits--;
}
byte[] bytes = new byte[nDigits];
bytes[0] = '-'; // may be overwritten.
while (value > 0) {
bytes[--nDigits] = (byte) (value % 10 + '0');
value /= 10;
}
return bytes;
}
Demo
int[] testData = new int[] {0, -1, 1,185,-185, 12345678, -12345678};
for (int value : testData) {
byte[] bytes = DigitsToAsciiArr(value);
System.out.printf("%9d -> %s%n", value, Arrays.toString(bytes));
}
prints
0 -> [48]
-1 -> [45, 49]
1 -> [49]
185 -> [49, 56, 53]
-185 -> [45, 49, 56, 53]
12345678 -> [49, 50, 51, 52, 53, 54, 55, 56]
-12345678 -> [45, 49, 50, 51, 52, 53, 54, 55, 56]
</details>
# 答案5
**得分**: -3
By adding "0" to the integer in C/C++, we can convert ASCII.
```cpp
#include <iostream>
using namespace std;
int intToAscii(int number) {
return '0' + number;
}
int main()
{
int number;
cout<<"The ASCII of " << 5 << " is " << intToAscii(5)<<endl;
intToAscii(5);
cout<<"The ASCII of "<< 8 << " is " << intToAscii(8)<<endl;
intToAscii(8);
}
英文:
By adding "0" to the integer in C/C++, we can convert ASCII.
#include <iostream>
using namespace std;
int intToAscii(int number) {
return '0' + number;
}
int main()
{
int number;
cout<<"The ASCII of " << 5 <<" is " <<intToAscii(5)<<endl;
intToAscii(5);
cout<<"The ASCII of "<< 8 <<" is " <<intToAscii(8)<<endl;
intToAscii(8);
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论