Python первая значащая цифра в элементах массива

229 просмотра
0
0 Комментариев

Есть два массива (ниже a и b) с произвольными положительными числами. Вообще говоря, они не обязательно целые, но если вдруг требуется, можно добавить и такое условие. Требуется получить третий массив (ниже — c), в котором:

  • c(i) = 1, если (первая цифра в b(i) > первой цифры в a(i) И длина целой части a(i) == длине целой части b(i)) или длина целой части b(i) больше длины целой части a(i);
  • c(i) = -1, в аналогичной ситуации, только a(i) и b(i) меняются местами;
  • c(i) = 0 во всех остальных случаях.

Интересует, по возможности, максимально эффективный по быстродействию алгоритм.

import numpy as np
 
a = np.array([11, 17, 183, 736, 89, 107, 1231, 1928])
b = np.array([10, 21, 179, 799, 81, 99,  1971, 2010])
 
c = np.array([0, 1, 0, 0, 0, -1, 0, 1])


Добавить комментарий

3 Answers

Python Опубликовано 09.12.2018
0

Рассмотрите логику, реализованную в следующем коде (работает, но нужно добавить проверки и вообще окультурить, т.к. я не спец в Python):

Найдём длину чисел через десятичный логарифм ( здесь длина уменьшена на 1, т.е. для 107 получим 2)

Сравним длины, если по ним всё ясно, вернем результат

Иначе выделяем целочисленным делением первую цифру с использованием таблицы степеней десяти

import numpy as np
 
def digcomp(aa, bb):
    table = np.array([1,10,100,1000,10000,100000,1000000])
    la = int(np.log10(aa))
    lb = int(np.log10(bb))
    if la > lb:
        return(-1)
    elif lb > la:
         return(1)
    else:
       da = aa // table[la]
       db = bb // table[la]
       if da > db:
           return(-1)
       elif db > da:
           return(1)
       else:
          return(0)
 
 
a = np.array([11, 17, 183, 736, 89, 107, 1231, 1928])
b = np.array([10, 21, 179, 799, 81, 99,  1971, 2010])
c = np.array([2, 2, 2, 2, 2, 2, 2, 2])
for i in range(len(a)):
    c[i] = digcomp(a[i], b[i])
print(c)

Добавить комментарий
0

Я бы воспользовался Pandas:

In [10]: import pandas as pd
 
In [11]: sa = pd.Series(a.astype(str))
 
In [12]: sb = pd.Series(b.astype(str))
 
In [13]: res = np.where(sa.str[0] > sb.str[0], 1, np.where(sa.str[0] < sb.str[0], -1, 0))

Результат:

In [14]: res
Out[14]: array([ 0, -1,  0,  0,  0, -1,  0, -1])

Замеры скорости для массива из 80.000 элементов:

In [15]: sa = pd.concat([sa] * 10**4)
 
In [16]: sb = pd.concat([sb] * 10**4)
 
In [17]: sa.shape
Out[17]: (80000,)
 
In [18]: sb.shape
Out[18]: (80000,)
 
In [19]: %timeit np.where(sa.str[0] > sb.str[0], 1, np.where(sa.str[0] < sb.str[0], -1, 0))
174 ms ± 5.25 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)

Добавить комментарий
0

Получилось хотя и длинновато, но только с операциями умножения/сложения/возведения в степень матриц,

import numpy as np
 
a = np.array([11, 17, 183, 736, 89, 107, 1231, 1928])
b = np.array([10, 21, 179, 799, 81, 99,  1971, 2010])
 
la = np.floor(np.log10(a))
lb = np.floor(np.log10(b))
 
arr_plus_1  = np.ones (8)
arr_minus_1 = np.ones (8) * -1
arr_zero    = np.zeros(8)
t           = np.ones (8) * 10
 
x = arr_zero + (lb > la) * arr_plus_1 \
    + (la > lb) * arr_minus_1 \
    + (la == lb) * (np.floor(b / np.power(t, la)) > np.floor(a / np.power(t, la))) \
    + (la == lb) * (np.floor(a / np.power(t, la)) > np.floor(b / np.power(t, la)))
print(x)


[ 0.  1.  0.  0.  0. -1.  0.  1.]

Добавить комментарий
Напишите свой ответ на данный вопрос.
Scroll Up