C#中的整数转整数数组

30

我需要将一个int类型的“123456”拆分成每个数字并存入Int数组中,我已经有了一种解决方案,但我不知道是否有更好的方法:

public static int[] intToArray(int num){
    String holder = num.ToString();
    int[] numbers = new int[Holder.ToString().Length]; 
    for(int i=0;i<numbers.length;i++){
        numbers[i] = Convert.toInt32(holder.CharAt(i));
    }
    return numbers;
}

@Hans Passant,我对数组长度非常确定,因为我将拥有的最长数字可能是999996,因此6是数组的最高长度,并且由于该数字限制,性能也不是问题。 - Rosmarine Popcorn
15个回答

31

使用LINQ的简单解决方案

int[] result = yourInt.ToString().Select(o=> Convert.ToInt32(o) - 48 ).ToArray()

1
值得注意的是,这种方法只是该帖子中代码的漂亮无副作用实现的有趣副产品:许多常见的同类列表上的命令式操作都有简单干净的“函数式”对应物。 - user166390
然而,边缘情况(例如,-12)仍应考虑在内,即使它只是函数定义域上的限制文档。原始帖子本身并没有做出这个限制。 - user166390
13
这是错误的,检查下面的MarkXA的答案,因为上面返回的是字符的字节码,而不是数字本身。 - Ali
当我使用长数字时,它无法正常工作。 - Ali Zedan
@Ali,终于,我更新了解决方案来解决你的问题! - Jahan Zinedine
糟糕的决定,仅适用于快速解决问题。但在生产环境中,将值转换为字符串,然后再将其转换回值会对性能造成非常大的影响。 - Евгений Елисеев

27

我认为这种方法比来回转换更好。与JBSnorro的答案相反,我在将其转换为数组后进行反转,因此避免了使用IEnumerable,我认为这将有助于稍微加快代码运行速度。该方法适用于非负数,所以0将返回new int [1] {0}

如果它应该适用于负数,您可以执行n = Math.Abs(n),但我认为这没有意义。

此外,如果要更高效,我可以通过创建类似于二分查找的if语句组合来确定数字位数,并一开始就创建最终数组。

public static int[] digitArr(int n)
{
    if (n == 0) return new int[1] { 0 };

    var digits = new List<int>();

    for (; n != 0; n /= 10)
        digits.Add(n % 10);

    var arr = digits.ToArray();
    Array.Reverse(arr);
    return arr;
}

更新 2018:

public static int numDigits(int n) {
    if (n < 0) {
        n = (n == Int32.MinValue) ? Int32.MaxValue : -n;
    }
    if (n < 10) return 1;
    if (n < 100) return 2;
    if (n < 1000) return 3;
    if (n < 10000) return 4;
    if (n < 100000) return 5;
    if (n < 1000000) return 6;
    if (n < 10000000) return 7;
    if (n < 100000000) return 8;
    if (n < 1000000000) return 9;
    return 10;
}

public static int[] digitArr2(int n)
{
    var result = new int[numDigits(n)];
    for (int i = result.Length - 1; i >= 0; i--) {
        result[i] = n % 10;
        n /= 10;
    }
    return result;
}

我曾经考虑过是先创建一个数组还是先反转列表。但我想,为什么不同时进行呢(使用IEnumerable扩展方法)。我意识到这只是微小的优化,因为列表不会很长。我想到的另一个(更重要的)论点是优雅。 - JBSnorro
我认为你的观点非常有道理 :) 我只是想让Burim Shala知道我为什么这样做以及我为什么认为这样做更好。我看到你已经更新了你的答案,这很好 :) - Lasse Espeholt
更好的方法是先找到数字的数量(可以快速完成),然后再构建数组。这样可以避免使用ListReverse - Lasse Espeholt

13
int[] outarry = Array.ConvertAll(num.ToString().ToArray(), x=>(int)x);

但如果你想将它转换为1,2,3,4,5:

int[] outarry = Array.ConvertAll(num.ToString().ToArray(), x=>(int)x - 48);

int没有ToCharArray。输入是int而不是string。 - Rune FS
@Rune FS,什么意思?holder是字符串,我从OP的示例中获取它。 - Saeed Amiri
从你的回答中看不出来它只是解决方案的一部分,这让我感到困惑。 - Rune FS
@Rune FS,是的,如果你没有仔细阅读问题,那么这一点就不明显。我已经进行了编辑,使其独立于问题。 - Saeed Amiri

11

我会这样做:

var result = new List<int>();
while (num != 0) {
    result.Insert(0, num % 10);
    num = num / 10;
}
return result.ToArray();

性能略低但可能更优雅的方法是:

return num.ToString().Select(c => Convert.ToInt32(c.ToString())).ToArray();

注意,这两者都会返回1,2,3,4,5,6而不是49,50,51,52,53,54(即字符'1','2','3','4','5','6'的字节码),这与您的代码返回值不同。我假设这才是实际意图?


7
使用将整数转换为字符串然后再转回来的方法可能并不那么快。我建议使用以下方法:
public static int[] ToDigitArray(int i)
{
    List<int> result = new List<int>();
    while (i != 0)
    {
        result.Add(i % 10);
        i /= 10;
    }
    return result.Reverse().ToArray();
}

我必须指出这仅适用于严格正整数。
编辑:
我想到了一种替代方案。如果性能真的是一个问题,这可能会更快,尽管你只有通过为你的特定用途和应用程序自己检查它才能确定。
public static int[] ToDigitArray(int n)
{
    int[] result = new int[GetDigitArrayLength(n)];
    for (int i = 0; i < result.Length; i++)
    {
        result[result.Length - i - 1] = n % 10;
        n /= 10;
    }
    return result;
}
private static int GetDigitArrayLength(int n)
{
    if (n == 0)
        return 1;
    return 1 + (int)Math.Log10(n);
}

当n为非负数时,此方法有效。


1
它对于零也不起作用,它返回一个空数组而不是一个只有一个数字的数组。 - Guffa
@Guffa,我已经说过了。我说它只适用于正整数,而零不是正数。事实上,我说它仅适用于严格的正整数,因此使用“严格”这个词,我明确说明了i = 0的情况不适用。 - JBSnorro
将函数名 GetDigitArrayLength 更改为int digits = 0; do { n /= 10; digits++; } while (n != 0); return digits; - TheJackal
好的,结果是一样的。当然,根据次要动机,你可能更喜欢其中的一种解决方案... - JBSnorro

4
感谢ASCII字符表。使用LINQ 以上的简单答案得出答案+ 48。
要么
int[] result = youtInt.ToString().Select(o => Convert.ToInt32(o) - 48).ToArray();

或者

int[] result = youtInt.ToString().Select(o => int.Parse(o.ToString())).ToArray();

可以使用

2
您可以不需要将其转换为字符串然后再转回去,就可以完成该操作:
public static int[] intToArray(int num) {
  List<int> numbers = new List<int>();
  do {
    numbers.Insert(0, num % 10);
    num /= 10;
  } while (num > 0);
  return numbers.ToArray();
}

当然,它仅适用于正值,但是您的原始代码也有这种限制。

2
我会采用以下方式进行转换。
if (num == 0)  return new int[1] { 0 };           
var digits = new List<int>();
while (num > 0)
{
   digits.Add(num % 10);
   num /= 10;
}
 var arr = digits.ToArray().Reverse().ToArray();


1
string DecimalToBase(int iDec, int numbase)
        {
            string strBin = "";
            int[] result = new int[32];
            int MaxBit = 32;
            for(; iDec > 0; iDec/=numbase)
            {
                int rem = iDec % numbase;
                    result[--MaxBit] = rem;
            } 
            for (int i=0;i<result.Length;i++)
                if ((int)result.GetValue(i) >= base10)
                    strBin += cHexa[(int)result.GetValue(i)%base10];
                else
                    strBin += result.GetValue(i);
            strBin = strBin.TrimStart(new char[] {'0'});
            return strBin;
        }
        int BaseToDecimal(string sBase, int numbase)
        {
            int dec = 0;
            int b;
            int iProduct=1;
            string sHexa = "";
            if (numbase > base10)
                for (int i=0;i<cHexa.Length;i++)
                    sHexa += cHexa.GetValue(i).ToString();
            for(int i=sBase.Length-1; i>=0; i--,iProduct *= numbase)
            {
                string sValue = sBase[i].ToString();
                if (sValue.IndexOfAny(cHexa) >=0)
                    b=iHexaNumeric[sHexa.IndexOf(sBase[i])];
                else 
                    b= (int) sBase[i] - asciiDiff;
                dec += (b * iProduct);
            } 
            return dec; 
        }

3
你能否解释一下这段代码,以便有人知道它是如何回答所提出的问题的? - Andrew Barber

1
我有类似的需求...我从许多好的想法中汲取了灵感,并添加了几个缺失的部分...很多人没有处理零或负值。这就是我想出来的:
    public static int[] DigitsFromInteger(int n)
    {
        int _n = Math.Abs(n);
        int length = ((int)Math.Log10(_n > 0 ? _n : 1)) + 1;
        int[] digits = new int[length];
        for (int i = 0; i < length; i++)
        {
            digits[(length - i) - 1] = _n % 10 * ((i == (length - 1) && n < 0) ? -1 : 1);
            _n /= 10;
        }
        return digits;
    }

我认为这很简洁..虽然,我们在每次迭代中都进行条件检查和几个不必要的计算..虽然我认为它们在这种情况下是微不足道的,但你可以通过以下方式进一步优化:

    public static int[] DigitsFromInteger(int n)
    {
        int _n = Math.Abs(n);
        int length = ((int)Math.Log10(_n > 0 ? _n : 1)) + 1;
        int[] digits = new int[length];
        for (int i = 0; i < length; i++)
        {
            //digits[(length - i) - 1] = _n % 10 * ((i == (length - 1) && n < 0) ? -1 : 1);
            digits[(length - i) - 1] = _n % 10;
            _n /= 10;
        }
        if (n < 0)
            digits[0] *= -1;
        return digits;
    }

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