Подтвердить что ты не робот

Как вы можете получить первую цифру в int (С#)?

В С#, какой лучший способ получить 1-ю цифру в int? Метод, который я придумал, состоит в том, чтобы превратить int в строку, найти 1-ю строку char строки, а затем вернуть ее обратно к int.

int start = Convert.ToInt32(curr.ToString().Substring(0, 1));

В то время как это выполняет эту работу, похоже, что существует такая проблема, как хорошее, простое математическое решение этой проблемы. Строгое манипулирование кажется неуклюжим.

Изменить:, независимо от разницы в скорости, mystring [0] вместо Substring() все еще просто манипулирует строкой

4b9b3361

Ответ 1

Вот как

int i = Math.Abs(386792);
while(i >= 10)
    i /= 10;

и i будут содержать то, что вам нужно

Ответ 2

Бенчмарки

Во-первых, вы должны решить, что вы подразумеваете под "лучшим" решением, конечно, это учитывает эффективность алгоритма, его читаемость/ремонтопригодность и вероятность появления ошибок в будущем. Однако тщательные модульные тесты могут вообще избежать этих проблем.

Я запускал каждый из этих примеров 10 миллионов раз, а значение результата - это число ElapsedTicks, которое прошло.

Без дальнейших шуток, от самых медленных до самых быстрых, алгоритмы:

Преобразование в строку принимает первый символ

int firstDigit = (int)(Value.ToString()[0]) - 48;

Результаты:

12,552,893 ticks

Использование логарифма

int firstDigit = (int)(Value / Math.Pow(10, (int)Math.Floor(Math.Log10(Value))));

Результаты:

9,165,089 ticks

Циклическое

while (number >= 10)
    number /= 10;

Результаты:

6,001,570 ticks

Conditionals

int firstdigit;
if (Value < 10)
     firstdigit = Value;
else if (Value < 100)
     firstdigit = Value / 10;
else if (Value < 1000)
     firstdigit = Value / 100;
else if (Value < 10000)
     firstdigit = Value / 1000;
else if (Value < 100000)
     firstdigit = Value / 10000;
else if (Value < 1000000)
     firstdigit = Value / 100000;
else if (Value < 10000000)
     firstdigit = Value / 1000000;
else if (Value < 100000000)
     firstdigit = Value / 10000000;
else if (Value < 1000000000)
     firstdigit = Value / 100000000;
else
     firstdigit = Value / 1000000000;

Результаты:

1,421,659 ticks

Развернутый и оптимизированный цикл

if (i >= 100000000) i /= 100000000;
if (i >= 10000) i /= 10000;
if (i >= 100) i /= 100;
if (i >= 10) i /= 10;

Результаты:

1,399,788 ticks

Примечание:

каждый тест вызывает Random.Next(), чтобы получить следующий int

Ответ 3

Попробуйте это

public int GetFirstDigit(int number) {
  if ( number < 10 ) {
    return number;
  }
  return GetFirstDigit ( (number - (number % 10)) / 10);
}

EDIT

Несколько человек запросили версию цикла

public static int GetFirstDigitLoop(int number)
{
    while (number >= 10)
    {
        number = (number - (number % 10)) / 10;
    }
    return number;
}

Ответ 4

Лучшее, что я могу придумать, это:

int numberOfDigits = Convert.ToInt32(Math.Floor( Math.Log10( value ) ) );

int firstDigit = value / Math.Pow( 10, numberOfDigits );

...

Не очень красиво:)

[Отредактировано: первый ответ был очень плохим:)]

[Редактировать 2: я бы, вероятно, советовал решениям, управляющим строкой)

[Редактировать 3: форматирование кода приятно:)]

Ответ 5

вариант ответа Антона:

 // cut down the number of divisions (assuming i is positive & 32 bits)
if (i >= 100000000) i /= 100000000;
if (i >= 10000) i /= 10000;
if (i >= 100) i /= 100;
if (i >= 10) i /= 10;

Ответ 6

Имел ту же идею, что и Lennaert

int start = number == 0 ? 0 : number / (int) Math.Pow(10,Math.Floor(Math.Log10(Math.Abs(number))));

Это также работает с отрицательными числами.

Ответ 7

Если вы считаете, что ответ Keltex уродлив, попробуйте это, он ДЕЙСТВИТЕЛЬНО некрасиво и даже быстрее. Он разворачивает двоичный поиск, чтобы определить длину.

 ... leading code along the same lines
/* i<10000 */
if (i >= 100){
  if (i >= 1000){
    return i/1000;
  }
  else /* i<1000 */{
    return i/100;
  }
}
else /* i<100*/ {
  if (i >= 10){
    return i/10;
  }
  else /* i<10 */{
    return i;
  }
}

P.S. У MartinStettner была та же идея.

Ответ 8

int myNumber = 8383;
char firstDigit = myNumber.ToString()[0];
// char = '8'

Ответ 9

int temp = i;
while (temp >= 10)
{
    temp /= 10;
}

Результат в temp

Ответ 10

Очевидный, но медленный, математический подход:

int firstDigit = (int)(i / Math.Pow(10, (int)Math.Log10(i))));

Ответ 11

Я знаю, что это не С#, но удивительно, что в python "получить первый char строкового представления числа" быстрее!

EDIT: нет, я допустил ошибку, я забыл построить снова int, извините. Развернутая версия это самая быстрая.

$ cat first_digit.py
def loop(n):
    while n >= 10:
        n /= 10
    return n

def unrolled(n):
    while n >= 100000000: # yea... unlimited size int supported :)
        n /= 100000000
    if n >= 10000:
        n /= 10000
    if n >= 100:
        n /= 100
    if n >= 10:
        n /= 10
    return n

def string(n):
    return int(str(n)[0])
$ python -mtimeit -s 'from first_digit import loop as test' \
    'for n in xrange(0, 100000000, 1000): test(n)'
10 loops, best of 3: 275 msec per loop
$ python -mtimeit -s 'from first_digit import unrolled as test' \
    'for n in xrange(0, 100000000, 1000): test(n)'
10 loops, best of 3: 149 msec per loop
$ python -mtimeit -s 'from first_digit import string as test' \
    'for n in xrange(0, 100000000, 1000): test(n)'
10 loops, best of 3: 284 msec per loop
$

Ответ 12

Я просто наткнулся на этот старый вопрос и почувствовал склонность предлагать другое предложение, так как ни один из других ответов до сих пор не возвращает правильный результат для всех возможных входных значений, и он все равно может быть выполнен быстрее:/p >

public static int GetFirstDigit( int i )
{
    if( i < 0 && ( i = -i ) < 0 ) return 2;
    return ( i < 100 ) ? ( i < 1 ) ? 0 : ( i < 10 )
            ? i : i / 10 : ( i < 1000000 ) ? ( i < 10000 )
            ? ( i < 1000 ) ? i / 100 : i / 1000 : ( i < 100000 )
            ? i / 10000 : i / 100000 : ( i < 100000000 )
            ? ( i < 10000000 ) ? i / 1000000 : i / 10000000
            : ( i < 1000000000 ) ? i / 100000000 : i / 1000000000;
}

Это работает для всех значащих целочисленных значений inclusive -2147483648, который является наименьшим знаковым целым и не имеет положительного аналога. Math.Abs( -2147483648 ) запускает a System.OverflowException и - -2147483648 вычисляет -2147483648.

Реализация может рассматриваться как комбинация преимуществ двух самых быстрых реализаций. Он использует двоичный поиск и избегает лишних делений. Быстрый тест с индексом цикла с 100 000 000 итераций показывает, что он в два раза быстрее, чем самая быстрая реализация.

Он заканчивается после 2,829,581 тиков.

Для сравнения я также измерил скорректированный вариант самой быстрой реализации, которая занимала 5,664,627.

public static int GetFirstDigitX( int i )
{
    if( i < 0 && ( i = -i ) < 0 ) return 2;
    if( i >= 100000000 ) i /= 100000000;
    if( i >= 10000 ) i /= 10000;
    if( i >= 100 ) i /= 100;
    if( i >= 10 ) i /= 10;
    return i;
}

Принятый ответ с той же самой коррекцией потребовал 16,561,929 тиков для этого теста на моем компьютере.

public static int GetFirstDigitY( int i )
{
    if( i < 0 && ( i = -i ) < 0 ) return 2;
    while( i >= 10 )
        i /= 10;
    return i;
}

Простые функции, подобные этим, могут быть легко доказаны для правильности, так как итерация всех возможных значений целых чисел занимает не более нескольких секунд на текущем оборудовании. Это означает, что менее важно реализовать их в исключительно читабельном виде, поскольку в дальнейшем их не будет вообще исправлять ошибку.

Ответ 13

Очень простой (и, вероятно, довольно быстрый, потому что он включает только сравнения и одно разделение):

if(i<10)
   firstdigit = i;
else if (i<100)
   firstdigit = i/10;
else if (i<1000)
   firstdigit = i/100;
else if (i<10000)
   firstdigit = i/1000;
else if (i<100000)
   firstdigit = i/10000;
else (etc... all the way up to 1000000000)

Ответ 14

Были ли некоторые тесты с одним из моих сотрудников здесь, и выяснили, что большинство решений не работают для чисел под 0.

  public int GetFirstDigit(int number)
    {
        number = Math.Abs(number); <- makes sure you really get the digit!

        if (number < 10)
        {
            return number;
        }
        return GetFirstDigit((number - (number % 10)) / 10);
    }

Ответ 15

Используя все приведенные ниже примеры для получения этого кода:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;

namespace Benfords
{
    class Program
    {
        static int FirstDigit1(int value)
        {
            return Convert.ToInt32(value.ToString().Substring(0, 1));
        }

        static int FirstDigit2(int value)
        {
            while (value >= 10) value /= 10;
            return value;
        }


        static int FirstDigit3(int value)
        {
            return (int)(value.ToString()[0]) - 48;
        }

        static int FirstDigit4(int value)
        {
            return (int)(value / Math.Pow(10, (int)Math.Floor(Math.Log10(value))));
        }

        static int FirstDigit5(int value)
        {
            if (value < 10) return value;
            if (value < 100) return value / 10;
            if (value < 1000) return value / 100;
            if (value < 10000) return value / 1000;
            if (value < 100000) return value / 10000;
            if (value < 1000000) return value / 100000;
            if (value < 10000000) return value / 1000000;
            if (value < 100000000) return value / 10000000;
            if (value < 1000000000) return value / 100000000;
            return value / 1000000000;
        }

        static int FirstDigit6(int value)
        {
            if (value >= 100000000) value /= 100000000;
            if (value >= 10000) value /= 10000;
            if (value >= 100) value /= 100;
            if (value >= 10) value /= 10;
            return value;
        }

        const int mcTests = 1000000;

        static void Main(string[] args)
        {
            Stopwatch lswWatch = new Stopwatch();
            Random lrRandom = new Random();

            int liCounter;

            lswWatch.Start();
            for (liCounter = 0; liCounter < mcTests; liCounter++)
                FirstDigit1(lrRandom.Next());
            lswWatch.Stop();
            Console.WriteLine("Test {0} = {1} ticks", 1, lswWatch.ElapsedTicks);

            lswWatch.Reset();
            lswWatch.Start();
            for (liCounter = 0; liCounter < mcTests; liCounter++)
                FirstDigit2(lrRandom.Next());
            lswWatch.Stop();
            Console.WriteLine("Test {0} = {1} ticks", 2, lswWatch.ElapsedTicks);

            lswWatch.Reset();
            lswWatch.Start();
            for (liCounter = 0; liCounter < mcTests; liCounter++)
                FirstDigit3(lrRandom.Next());
            lswWatch.Stop();
            Console.WriteLine("Test {0} = {1} ticks", 3, lswWatch.ElapsedTicks);

            lswWatch.Reset();
            lswWatch.Start();
            for (liCounter = 0; liCounter < mcTests; liCounter++)
                FirstDigit4(lrRandom.Next());
            lswWatch.Stop();
            Console.WriteLine("Test {0} = {1} ticks", 4, lswWatch.ElapsedTicks);

            lswWatch.Reset();
            lswWatch.Start();
            for (liCounter = 0; liCounter < mcTests; liCounter++)
                FirstDigit5(lrRandom.Next());
            lswWatch.Stop();
            Console.WriteLine("Test {0} = {1} ticks", 5, lswWatch.ElapsedTicks);

            lswWatch.Reset();
            lswWatch.Start();
            for (liCounter = 0; liCounter < mcTests; liCounter++)
                FirstDigit6(lrRandom.Next());
            lswWatch.Stop();
            Console.WriteLine("Test {0} = {1} ticks", 6, lswWatch.ElapsedTicks);

            Console.ReadLine();
        }
    }
}

Я получаю эти результаты на AMD Ahtlon 64 X2 Dual Core 4200+ (2,2 ГГц):

Test 1 = 2352048 ticks
Test 2 = 614550 ticks
Test 3 = 1354784 ticks
Test 4 = 844519 ticks
Test 5 = 150021 ticks
Test 6 = 192303 ticks

Но получайте их на AMD FX 8350 Eight Core (4.00 ГГц)

Test 1 = 3917354 ticks
Test 2 = 811727 ticks
Test 3 = 2187388 ticks
Test 4 = 1790292 ticks
Test 5 = 241150 ticks
Test 6 = 227738 ticks

Итак, зависит от того, быстрее или быстрее работает метод 5 или 6, зависит от процессора, я могу только предположить, что это связано с тем, что предсказание ветвления в командном процессоре процессора более умное для нового процессора, но я не совсем уверен.

У меня нет процессоров Intel, может быть, кто-то может проверить его для нас?

Ответ 16

Чтобы дать вам альтернативу, вы можете разделить целое число на 10, а затем отбросить одно значение, как только достигнете нуля. Поскольку операции с строкой, как правило, медленные, это может быть быстрее, чем манипуляция строк, но отнюдь не изящна.

Что-то вроде этого:

while(curr>=10)
     curr /= 10;

Ответ 17

while (i > 10)
{
   i = (Int32)Math.Floor((Decimal)i / 10);
}
// i is now the first int

Ответ 18

start = getFirstDigit(start);   
public int getFirstDigit(final int start){
    int number = Math.abs(start);
    while(number > 10){
        number /= 10;
    }
    return number;
}

или

public int getFirstDigit(final int start){
  return getFirstDigit(Math.abs(start), true);
}
private int getFirstDigit(final int start, final boolean recurse){
  if(start < 10){
    return start;
  }
  return getFirstDigit(start / 10, recurse);
}

Ответ 19

int start = curr;
while (start >= 10)
  start /= 10;

Это более эффективно, чем подход ToString(), который внутренне должен реализовывать аналогичный цикл и должен построить (и разобрать) строковый объект на пути...

Ответ 20

Нетеративная формула:

public static int GetHighestDigit(int num)
{
    if (num <= 0)
       return 0; 

    return (int)((double)num / Math.Pow(10f, Math.Floor(Math.Log10(num))));
}

Ответ 21

Очень простой способ получить последнюю цифру:

int myInt = 1821;

int lastDigit = myInt - ((myInt/10)*10); // 1821 - 1820 = 1

Ответ 22

Это то, что я обычно делаю, пожалуйста, обратитесь к моей функции ниже:

Эта функция может извлекать первую цифру из любой строки, которую вы можете изменить, и использовать эту функцию в соответствии с вашим использованием

   public static int GetFirstNumber(this string strInsput)
    {
        int number = 0;
        string strNumber = "";
        bool bIsContNo = true;
        bool bNoOccued = false;

        try
        {
            var arry = strInsput.ToCharArray(0, strInsput.Length - 1);

            foreach (char item in arry)
            {
                if (char.IsNumber(item))
                {
                    strNumber = strNumber + item.ToString();

                    bIsContNo = true;

                    bNoOccued = true;
                }
                else
                {
                    bIsContNo = false;
                }

                if (bNoOccued && !bIsContNo)
                {
                    break;
                }


            }

            number = Convert.ToInt32(strNumber);

        }
        catch (Exception ex)
        {

            return 0;
        }

        return number;

    }

Ответ 23

Проверьте это тоже:

int get1digit(Int64 myVal)
{
    string q12 = myVal.ToString()[0].ToString();
    int i = int.Parse(q12);
    return i;
}

Также хорошо, если вы хотите несколько номеров:

int get3digit(Int64 myVal) //Int64 or whatever numerical data you have
{
    char mg1 = myVal.ToString()[0];
    char mg2 = myVal.ToString()[1];
    char mg3 = myVal.ToString()[2];
    char[] chars = { mg1, mg2, mg3 };
    string q12= new string(chars);
    int i = int.Parse(q12);
    return i;
}

Ответ 24

Вот более простой способ, который не связан с циклом

int number = 1234
int firstDigit = Math.Floor(number/(Math.Pow(10, number.ToString().length - 1))

Это даст нам 1234/Math.Pow(10, 4 - 1) = 1234/1000 = 1

Ответ 25

int i = 4567789;
int digit1 = int.Parse(i.ToString()[0].ToString());