繁体   English   中英

有没有一种简单的方法可以将 int 转换为每个数字的 int 数组?

[英]Is there an easy way to turn an int into an array of ints of each digit?

说我有

var i = 987654321;

有没有一种简单的方法来获取数字数组,相当于

var is = new int[] { 9, 8, 7, 6, 5, 4, 3, 2, 1 };

没有.ToString() ing 并使用int.Parse(x)迭代字符?

public Stack<int> NumbersIn(int value)
{
    if (value == 0) return new Stack<int>();

    var numbers = NumbersIn(value / 10);

    numbers.Push(value % 10);

    return numbers;
}

var numbers = NumbersIn(987654321).ToArray();

没有递归的替代方案:

public int[] NumbersIn(int value)
{
    var numbers = new Stack<int>();

    for(; value > 0; value /= 10)
        numbers.Push(value % 10);

    return numbers.ToArray();
}

我知道可能有比这更好的答案,但这是另一个版本:

您可以使用yield return以升序返回数字(根据权重或任何名称)。

public static IEnumerable<int> Digits(this int number)
{
    do
    {
        yield return number % 10;
        number /= 10;
    } while (number > 0);
}

12345 => 5, 4, 3, 2, 1

另一种不使用递归并使用避免在每次插入时重新分配的堆栈的替代方法(至少对于前 32 位数字):

var list = new Stack<int>(32);
var remainder = 123456;
do
{
    list.Push(remainder % 10);
    remainder /= 10;
} while (remainder != 0);

return list.ToArray();

是的,这种方法也适用于 0 和负数。

有趣的是,给这个算法一个负数 -123456,你会得到 {-1, -2, -3, -4, -5, -6}

更新:从使用列表切换到堆栈,因为这会自动给出正确的顺序。

var x = new Stack<int>();
do
{
    x.Push(i % 10);
    i /= 10;
} while (i > 0);
return x.ToArray();

刚刚对不同的方法做了一个基准测试,结果如下:

BenchmarkDotNet=v0.12.0, OS=Windows 10.0.19041
Intel Core i7-8705G CPU 3.10GHz (Kaby Lake G), 1 CPU, 8 logical and 4 physical cores
.NET Core SDK=3.1.301
  [Host]     : .NET Core 3.1.5 (CoreCLR 4.700.20.26901, CoreFX 4.700.20.27001), X64 RyuJIT
  DefaultJob : .NET Core 3.1.5 (CoreCLR 4.700.20.26901, CoreFX 4.700.20.27001), X64 RyuJIT


                         Method |      Mean |    Error |   StdDev |  Gen 0 | Gen 1 | Gen 2 | Allocated |
------------------------------- |----------:|---------:|---------:|-------:|------:|------:|----------:|
                          Stack |  89.06 ns | 2.130 ns | 6.179 ns | 0.0592 |     - |     - |     248 B |
                    SharedArray |  84.64 ns | 1.765 ns | 3.685 ns | 0.0153 |     - |     - |      64 B |
 PreallocateUsingNumberOfDigits |  39.15 ns | 0.861 ns | 2.499 ns | 0.0153 |     - |     - |      64 B |
                    IEnumerable | 246.53 ns | 4.926 ns | 9.372 ns | 0.0610 |     - |     - |     256 B |

按平均速度排序:

PreallocateUsingNumberOfDigits

平均值:~39.15ns 错误:0.861ns 分配:64 B

public static int[] GetDigits(int n)
{
    if (n == 0)
        return new[] {0};
    
    var x = Math.Abs(n);

    var numDigits = NumberOfDigits(x);

    var res = new int[numDigits];
    var count = 0;

    while (x > 0)
    {
        res[count++] = x % 10;
        
        x /= 10;
    }
    
    Array.Reverse(res);

    return res;
}

public static int NumberOfDigits(int n)
{
    if (n >= 0)
    {
        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;
    }
    else
    {
        if (n > -10) return 2;
        if (n > -100) return 3;
        if (n > -1000) return 4;
        if (n > -10000) return 5;
        if (n > -100000) return 6;
        if (n > -1000000) return 7;
        if (n > -10000000) return 8;
        if (n > -100000000) return 9;
        if (n > -1000000000) return 10;
        return 11;
    }
}

共享数组

平均值:~84.64ns 错误:1.765ns 分配:64 B

public static int[] GetDigits_SharedPool(int n)
{
    if (n == 0)
        return new[] {0};
    
    var x = Math.Abs(n);
    
    var pool = ArrayPool<int>.Shared.Rent(11);
    var count = 0;

    while (x > 0)
    {
        pool[count++] = x % 10;
        
        x /= 10;
    }

    var res = new int[count];
    
    Array.Copy(pool, res, count);
    
    Array.Reverse(res);
    
    ArrayPool<int>.Shared.Return(pool);

    return res;
}

平均值:~89.06ns 错误:2.130ns 分配:248 B

来自: @Peter Lillevold 回答

public int[] Stack()
{
    var list = new Stack<int>(32);
    var remainder = digit;
    do
    {
        list.Push(remainder % 10);
        remainder /= 10;
    } while (remainder != 0);

    return list.ToArray();
}

IEnumerable

平均值:~246.53ns 错误:4.926ns 分配:256 B

来自@Svish 的回答

public static IEnumerable<int> Digits_IEnumerable(int number)
{
    do
    {
        yield return number % 10;
        number /= 10;
    } while (number > 0);
}

代码

见这里: michal-ciechan/GetDigitsBenchmark

简而言之:使用将数字除以 10 (%) 的循环来获取提醒(每个数字)并将其放入数组。

字符串并且可以很有趣(其他一些选项会更快......但这很容易)

var @is = 987654321.ToString().Select(c => c - 48).ToArray();

.NET 4.7.1 或更高版本:

IEnumerable<long> GetDigits(long value) =>
  value == 0 ? new long[0] : GetDigits(value / 10).Append(value % 10)

.NET 3.5 - 4.7:

IEnumerable<long> GetDigits(long value) =>
  value == 0 ? new long[0] : GetDigits(value / 10).Concat(new[] { value % 10 });

这会将 int 值转换为字符串,然后转换为字符数组,最后转换为 int 数组。

var myInt = 31337;
var myIntArray = Array.ConvertAll(myInt.ToString().ToCharArray(), x => (int)Char.GetNumericValue(x));

我使用.ToCharArray()因为它应该比.ToArray()快。

对于 LINQ 爱好者作为 ONE LINER =>

var number = 8892366;
var splittedList = number.ToString().ToCharArray().Select(x => Int32.Parse(x.ToString())).ToList();

// Output : List<int> {8, 8, 9, 2, 3, 6, 6} 

这确实会转换为字符串并遍历字符,但它会自动地以单行方式进行:

var i = 987654321;
var @is = i.ToString().Select(c => c - '0').ToArray();

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM