Список двоичных чисел: сколько позиций имеют единицу и ноль

#python #numpy #numba #binary-operators

#python #numpy #numba #бинарные операторы

Вопрос:

У меня есть список целых чисел, например i=[1,7,3,1,5] . который я сначала преобразую в список соответствующих двоичных представлений длины L , например b=["001","111","011","001","101"] . with L=3 .

Теперь я хочу вычислить, на скольких L позициях в двоичном представлении есть a 1 , а также ноль 0 . В моем примере результатом будет return=2 , поскольку 1 в третьей (последней) позиции для этих записей всегда есть a . Я был бы рад любому комментарию. Я думаю, в идеале я должен выполнять много операций Xor одновременно. Однако я не уверен, как я могу сделать это эффективно.

Редактировать: Спасибо за множество ответов!! Я должен проверить, какой из них самый быстрый.

Комментарии:

1. Разве ответ не должен быть 3?

2. Обратите внимание, что я откатил ваш вопрос до предыдущей версии, так как вы не должны использовать ответ, чтобы превратить его в следующий вопрос. Рад видеть, что вы опубликовали этот последующий вопрос в обзоре кода

Ответ №1:

Одно из наблюдений заключается в том, что если вы берете И для всех чисел, а также ИЛИ для всех чисел, то XOR этих двух результатов будет иметь 1, где условие выполняется.

Итак:

 from functools import reduce
from operator import and_, or_

def count_mixed_bits(lst):
    xor = reduce(and_, lst) ^ reduce(or_, lst)
    return bin(xor).count("1")


count_mixed_bits([1,7,3,1,5])  # 2
  

Комментарии:

1. Спасибо за объяснение. Для меня это имеет большой смысл и кажется довольно простым

2. Мне это нужно для работы внутри функции numba. Поэтому я попытался изменить ваш код. Может быть, у вас также есть некоторый опыт работы с numba? Я не уверен, что моя модификация оптимальна.

3. Пожалуйста, не изменяйте свой вопрос, чтобы добавить следующий вопрос. Если у вас есть дополнительный вопрос, рассмотрите возможность публикации нового вопроса, посвященного только этому. Однако, если ваш последующий вопрос касается размера кода и / или эффективности (пока у вас есть рабочий код), рассмотрите возможность публикации его в Code Review

Ответ №2:

Существует numpy.binary_repr метод, который принимает длину. К сожалению, он не может обрабатывать массивы. Но вместо этого вы можете применить функциональность np.unravel_index :

 def check(arr, lenght):
    positions = np.array(np.unravel_index(i, (2,)*lenght))
    return positions, np.sum(np.sum(positions, axis=1) != len(arr))

>>> positions, output = check(i, 3)
>>> print(positions)
>>> print(output)
[[0 1 0 0 1]
 [0 1 1 0 0]
 [1 1 1 1 1]]
2
  

Ответ №3:

Вот решение, я подозреваю, что оно не очень эффективное, но его легко понять.

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

 # create a binary list of 3 elements from input list of integers
i=[1,7,3,1,5]
b=['{0:03b}'.format(x) for x in i]

# loop over the digit position (1,2,3)
cnt=[]
for pos in range(3):
    cnt.append(len(set([c[pos] for c in b])))

# cnt now contains a list of either 2(=both 1 and 0 present) or 1 (unique)
# so now we count the number of entries with "2"
result=cnt.count(2)
print (result)
  

ответ:

 2
  

Ответ №4:

Прежде всего, ваш вопрос помечен как numpy, но ваш массив не является массивом numpy. Вот решение, которое использует numpy:

 import numpy as np

def has_zeroes_and_ones_at_index(arr, index_from_right):
    shifted_arr = np.right_shift(arr, index_from_right)
    has_one_at_index = shifted_arr % 2 == 1
    return(True in has_one_at_index and False in has_one_at_index)

arr = np.array([1, 7, 3, 1, 5])
res= has_zeroes_and_ones_at_index(arr, 1)
print(res)
  

Поскольку числа хранятся в двоичном формате, мы можем использовать сдвиг битов, чтобы переместить все биты чисел вправо, а затем посмотреть на последний бит. Нам не нужно приводить их к двоичному формату раньше.
5 (101) сдвиг вправо на единицу -> 2 (010)

Затем мы создаем маску, чтобы увидеть, какие числа имеют единицу в последнем бите, и возвращаем True, когда в маске есть хотя бы один элемент True и один элемент false .

Комментарии:

1. хорошее использование сдвига битов, я исправил массив в соответствии с вопросом, потому что ваше добавление 2 сделало результат всегда истинным. Кроме того, просто чтобы отметить, что это не совсем отвечает на вопрос, поскольку все еще нужно перебирать позиции битов и подсчитывать количество истин.

Ответ №5:

Для этой задачи вы можете использовать побитовые операторы python.

 def find(aList, nn):
    return sum( 
      filter( 
        lambda bb: bb > 0 ,
        (
          ( 1 <= (sum( (aa amp; 1<<kk) > 0 for aa in aList)) < len(aList) )
          for kk in range(nn)
        )
      )
    )
  

 >>> find([1,7,3,1,5],3)
2
>>> find([],3)
0
>>> find([7],3)
0
>>> find([7,1],3)
2
>>> find([7,1,7],3)
2