如何从一个数字中提取每个数字?

15

我能想到的就是反复将数字除以10(直到数字小于10),并记录下次数,但是是否有更好的方法呢?


1
是的,这是正确的解决方案。你指的是什么样的技巧? - Vadim Shender
1
作为一个恶劣的技巧,我将它转换成字符串(使用sprintfsnprintf),然后再将字符值用atoi函数转换成数字。这种方法不使用模运算或者据我所知的除法操作。 - MrMesees
函数(digit){返回("" + (digit)).split("");} - Chris Tobba
11个回答

18

没错,你基本上已经掌握了正确的数学方法。

while (num >= 10)
    digit = num MOD 10   // and save this into an array or whatever
    num = num / 10
在此结束时,num将包含最后一位数字。 以下是一个JavaScript实现:
function getDigits(num) {
    var digits = [];
    while (num >= 10) {
        digits.unshift(num % 10);
        num = Math.floor(num / 10);
    }
    digits.unshift(num);
    return digits;
}

请注意,它只适用于非负整数。


9

为什么要自己实现转换,当已经有一种非常可靠的方法可以做到呢?

伪代码-C:

char digits[10];
sprintf(digits, "%d", number);

现在,您的数字字符数组(字符串)应该由该数字的每个数字组成。大多数其他脚本语言也包含sprintf函数。
如果您想要8进制、16进制或二进制等基数,这将起作用。只需使用不同的格式说明符即可。

但不适用于除16、10或8以外的进制。(二进制在sprintf的标准版本中没有“%”指定符) - Jason S
然后,如果你想将它们用作实际数字,你必须从所有数字中减去“0”。至于为什么...也许你正在做一些娱乐性的计算数学问题,而你不想要那点额外开销。我相信有一些项目欧拉问题使用数字! - Cascabel
我讨厌这种转换成字符串的方式。我会尽快给它点个踩。我认为这是一个非常糟糕的解决方案。 - Bart
就像我之前所说的一样,如果数字太长,它将在9个数字后覆盖内存(一个字节用于空字符)。如果由于某种原因使用宽字符字符串会怎么样呢?number是一个数字,因此有用于此目的的函数divmod - Bart
1
一个32位整数不会超过9个数字(至少在十进制下)。如果要处理64位整数,请进行调整。 至于使用div和mod,这就是sprintf()内部使用的内容。OP只想提取数字,他没有说明目的。如果是为了计算目的,那么我可以想象另一种方法可能更合适,这只是一种方法。 - tchen

4

数学上的解决方法是对10取模并将每个结果添加到列表中,然后反转列表的顺序。下面是一个基本的C#算法:

List<byte> digits = new List<byte>();

while(number > 10)
{
   digits.Add(number % 10);
   number %= 10;
}
//add the last digit
digits.Add(number);

byte temp;
for(var i=0;i<digits.Count/2;i++)
{
   temp = digits[i];
   digits[i] = digits[digits.Count-(i+1)];
   digits[digits.Count-(i+1)] = temp;
}

其他“技巧”通常涉及字符串转换。这是一个使用Linq的C#一行代码,将会给出与上述相同的结果:

var digits = number.ToString().Select(c=>byte.Parse(c)).ToList();

3

使用您的方法编写的 Python 代码:

def digits(n):
  ds = []
  while n > 0:
    ds.append(n % 10)
    n /= 10
  ds.reverse()
  return ds

使用将数据类型转换为字符串的方法:

def digits(n):           
  return map(int, str(n))

1
一个更有效率的算法,如果你的输入数字可能很大的话,是将它们除以10的乘方,比如1000,并使用一个查找表:
s = ""; // or use a string builder appropriate to your language...
table = {"000", "001", ..., "999"};
tableInitial = {"unused", "1", "2", ..., "9", "10", ..., "999"};
while(n >= 1000) {
  m = n%1000;
  n /= 1000;
  s = table[m] + s;
}
s = tableInitial[n] + s;

修改操作对于任何数字N来说,实际上是一个log(n)的操作。即使对于大数值,它也不会更加高效。 - KeithS
1
@KeithS:渐进地说,二分法——使用快速除法(FFT或甚至Karatsuba)将数字模10^k减少k约为log_100 N的速度提高,只要你使用快速除法。实际上,将数字模小于最大整数平方根的最小十次幂减少与模10减少一样快,因此在64位机器上处理大数字时,你可以获得近乎9倍的加速。当你达到某个阈值时,你可以从渐进方法转向实用方法来结合这两种方法。根据我的经验,这个阈值大约是1000位数字,但它会有所不同。 - Charles

1
如果它是一个整数,你可以将字符串表示转换为字符数组,然后将其转换为字节数组(0-9)。

我认为将其转换为字符串表示形式本质上是通过重复除以10来完成的。至少,这就是我会做的方式。 - David Liu
如果它是十六进制呢? - munmunbb
一个整数就是一个整数,在内存中以相同的方式存储,无论你将其显示为十进制、十六进制、二进制或其他任何形式。你是在问如何提取十六进制表示中的单个字符吗?如果是这样,只需获取十六进制表示作为字符串,然后获取该字符串中的字符即可。 - Charles Bretana

0

JavaScript:

function digits(num) {
  return String(num).split('').map(v => +v);
}

0

不确定我是否正确理解您想要的内容...

以下内容适合您吗?它是用C#编写的...

public static List<int> ExtractDigit()
{
    // Input example
    int number = 12345;

    // Convert Integer to string   
    string numberedString = number.ToString();

    // Create a list of integers
    var numList = new List<int>();

    // Convert each character in string back to int and add to list.
    foreach (char c in numberedString)
    {
        numList.Add(Convert.ToInt32(c.ToString()));
    }

    return numList;
}

希望我能够帮到你。


0

给定的Python解决方案可以进一步优化,使用

zerostr = ord('0')
def digits(n): 
    return map(lambda x: ord(x)-zerostr, str(n))

事实上,在将 int -> str 转换方面可能已经完全优化了,为了获得数字值,更好的方法是使用数字字符串的内在字符值,这在每种编码(包括 EBCDIC)中都通过 int 减法而不是 str 解析来给出数字值。

0

以下是处理整数或字符串的 JavaScript 可逆数组函数:

function reverse(array)
{
    var left = null;
    var right = null;
    var length = array.length;
    for (left = 0, right = length - 1; left < right; left += 1, right -= 1)
    {
        var temporary = array[left];
        array[left] = array[right];
        array[right] = temporary;
    }
    return array;
}

function toDigitsArrayFromInteger(integer, isReverse)
{
    var digits = [];

    if (integer > 0)
    {
        var floor = window.Math.floor;
        while (integer > 0)
        {
            digits.push(floor(integer % 10));
            integer = floor(integer / 10);
        }

        // Array is populated in reverse order. Un-reverse it to make it normal.
        if (!isReverse)
        {
            digits = reverse(digits);
        }
    }
    else if (integer < 0)
    {
        digits = toDigitsArrayFromInteger(-integer, isReverse);
    }
    else if (integer === 0)
    {
        digits.push(0);
    }

    return digits;
}

function toDigitsArrayFromString(string, isReverse)
{
    var digits = [];

    string += ""; // Coerce to string.

    var i = null;
    var length = string.length;
    for (i = 0; i < length; i += 1)
    {
        var integer = parseInt(string.charAt(i), 10);
        if (isFinite(integer))
        {
            digits.push(integer);
        }
    }

    if (isReverse)
    {
        digits = reverse(digits);
    }

    return digits;
}

一旦你将数字作为数组获取,你可以轻松地反转数组以从左侧或右侧开始获取数字。

字符串函数更加灵活多变,因为它可以在字符串中查找任何数字,而整数函数仅限于整数。

Benchmarks: http://jsperf.com/todigitsarray

两个函数之间的基准测试显示,在Firefox 10和Chrome 12中,字符串函数比整数函数快30%至60%。而在Opera 12中,整数函数略微快约10%。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接