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

Это должно сделать это:

CREATE OR REPLACE FUNCTION device_bid_modifiers_count_per()
  RETURNS TRIGGER AS
$func$
DECLARE
   devices_count int      := device_types_count();
   table_name    regclass := TG_ARGV[0];
   column_name   text     := TG_ARGV[1];
BEGIN
   LOCK TABLE device_types IN EXCLUSIVE MODE;
   EXECUTE format('LOCK TABLE %s IN EXCLUSIVE MODE', table_name);

   IF TG_OP = 'DELETE' THEN
      PERFORM validate_bid_modifiers_count(table_name
                                         , column_name
                                         , (row_to_json(OLD) ->> column_name)::bigint
                                         , devices_count);
   ELSE
      PERFORM validate_bid_modifiers_count(table_name
                                         , column_name
                                         , (row_to_json(NEW) ->> column_name)::bigint
                                         , devices_count);
   END IF;

   RETURN NEW;
END
$func$  LANGUAGE plpgsql;

Непосредственной причиной сообщения об ошибке была внешняя SELECT. Без цели вам нужно заменить ее на PERFORM в plpgsql. Но внутреннее PERFORM в строке запроса, переданной EXECUTE, тоже было неверным. PERFORM - это команда plpgsql, недопустимая в строке SQL, переданной в EXECUTE, которая ожидает код SQL. Вы должны использовать SELECT там. Наконец, OLD и NEW не видны внутри EXECUTE, и каждый из них вызовет свое собственное исключение, как у вас. Все проблемы устранены путем удаления EXECUTE.

Простой и быстрый способ получить значение динамического имени столбца из типов строк OLD и NEW: приведение к json, затем вы можете параметризовать имя ключа, как показано , Должно быть немного проще и быстрее, чем альтернатива с динамическим SQL - что также возможно, например:

  ...
  EXECUTE format('SELECT validate_bid_modifiers_count(table_name
                                                    , column_name
                                                    , ($1.%I)::bigint
                                                    , devices_count)', column_name)
  USING OLD;
  ...

Связанный:

В стороне: не уверен, зачем нужны тяжелые блокировки.

В сторону 2: рассмотрите возможность написания отдельной функции триггера для каждого триггера. Более шумный DDL, но проще и быстрее для выполнения.

77
задан Dinah 31 March 2009 в 14:53
поделиться

21 ответ

Вот то, как

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

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

124
ответ дан Anton Gogolev 24 November 2019 в 10:41
поделиться

Вот более простой путь, который не включает цикличное выполнение

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

Это дало бы нам 1234/математика. Голова (10, 4 - 1) = 1234/1000 = 1

-2
ответ дан Ross Goddard 24 November 2019 в 10:41
поделиться
int start = curr;
while (start >= 10)
  start /= 10;

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

0
ответ дан Dinah 24 November 2019 в 10:41
поделиться
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);
}
0
ответ дан sdellysse 24 November 2019 в 10:41
поделиться

Не повторяющаяся формула:

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

    return (int)((double)num / Math.Pow(10f, Math.Floor(Math.Log10(num))));
}
0
ответ дан Mitch Wheat 24 November 2019 в 10:41
поделиться

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

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

while(curr>=10)
     curr /= 10;
0
ответ дан JoshJordan 24 November 2019 в 10:41
поделиться
while (i > 10)
{
   i = (Int32)Math.Floor((Decimal)i / 10);
}
// i is now the first int
0
ответ дан cjk 24 November 2019 в 10:41
поделиться

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

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)
2
ответ дан Keltex 24 November 2019 в 10:41
поделиться

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

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

$ 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
$
3
ответ дан Ian Boyd 24 November 2019 в 10:41
поделиться

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

int firstDigit = (int)(i / Math.Pow(10, (int)Math.Log10(i))));
3
ответ дан mqp 24 November 2019 в 10:41
поделиться
int temp = i;
while (temp >= 10)
{
    temp /= 10;
}

Результат в temp

3
ответ дан Douglas Leeder 24 November 2019 в 10:41
поделиться
int myNumber = 8383;
char firstDigit = myNumber.ToString()[0];
// char = '8'
3
ответ дан cjk 24 November 2019 в 10:41
поделиться

Если Вы думаете, что ответ 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 имел ту же идею.

4
ответ дан Mike Dunlavey 24 November 2019 в 10:41
поделиться

вариация на ответ Anton:

 // 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;
18
ответ дан Mike Dunlavey 24 November 2019 в 10:41
поделиться

Имел ту же идею как Lennaert

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

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

5
ответ дан aquinas 24 November 2019 в 10:41
поделиться

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

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

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

...

Не очень симпатичный :)

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

[Редактирование 2: Я, вероятно, советовал бы строковым решениям для управления, хотя]

[Редактирование 3: форматирование кода хорошо :)]

26
ответ дан Lennaert 24 November 2019 в 10:41
поделиться

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

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

Править

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

public static int GetFirstDigitLoop(int number)
{
    while (number >= 10)
    {
        number = (number - (number % 10)) / 10;
    }
    return number;
}
31
ответ дан JaredPar 24 November 2019 в 10:41
поделиться

Сравнительные тесты

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

Я выполнил каждый из этих примеров 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

Условные выражения

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

213
ответ дан John Rasch 24 November 2019 в 10:41
поделиться

Провел несколько тестов с одним из моих коллег здесь и обнаружил, что большинство решений не работают для чисел ниже 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);
    }
1
ответ дан 24 November 2019 в 10:41
поделиться

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

int myInt = 1821;

int lastDigit = myInt - ((myInt/10)*10); // 1821 - 1820 = 1
0
ответ дан 24 November 2019 в 10:41
поделиться
int i = 4567789;
int digit1 = int.Parse(i.ToString()[0].ToString());
-2
ответ дан 24 November 2019 в 10:41
поделиться
Другие вопросы по тегам:

Похожие вопросы: