побитовое ИЛИ сокращение python списков - PullRequest
0 голосов
/ 18 июня 2020

У меня есть два списка из нулей и единиц. Оба списка имеют одинаковую длину. Ниже приведен пример: я ищу общее c решение для списков любого размера и с нулями и единицами в любом индексе.

l1 = [1,1,0,1,1,1,1]
l2 = [0,0,0,1,0,0,0]

Цель состоит в том, чтобы использовать первый список l1 как mask, чтобы создать новый список l2_new из l2, который логически OR объединяет все элементы индизов, где l1 равно 1, и принимает элементы без изменений, где l1 равно 0.

Что приведет к:

l2_new = [0,0,1]

Графическое объяснение:

enter image description here

Ответы [ 5 ]

2 голосов
/ 18 июня 2020

Это идеальная настройка для np.bitwise_or.reduceat, который делает на основе фрагментов OR-ing -

# Based on https://stackoverflow.com/a/62430810/ @Divakar
def squash1s_mask(a):
    a = np.asarray(a)
    m = a==1
    return np.r_[True,m[:-1]!=m[1:]] | (a==0)

out = np.bitwise_or.reduceat(l2, np.flatnonzero(squash1s_mask(l1)))
1 голос
/ 18 июня 2020

Подобно ответу @ ExplodingGayFi sh, но я применяю groupby в обоих списках одновременно и использую функциональный подход для вычисления ИЛИ.

from functools import reduce
from itertools import groupby
from operator import or_


def fn(l1, l2):
    result = []

    # group both lists by the values in l1
    for key, group in groupby(zip(l1, l2), key=lambda x: x[0]):
        # extract values from l2
        group_from_l2 = [x[1] for x in group]
        if key == 1:
            # bitwise OR of all values in group_from_l2
            result.append(reduce(or_, group_from_l2))
        else:
            # group_from_l2 unchanged
            result.extend(group_from_l2)

    return result
>>> fn([1, 1, 0, 1, 1, 1, 1], [0, 0, 0, 1, 0, 0, 0])
[0, 0, 1]
>>> fn([1, 1, 0, 0, 1, 1, 0, 0], [0, 1, 1, 0, 1, 1, 0, 1])
[1, 1, 0, 1, 0, 1]
1 голос
/ 18 июня 2020

Один из способов - использовать itertools.groupby:

import itertools 
l1 = [1,1,0,1,1,1,1]
l2 = [0,0,0,1,0,0,0]
pos = [(item, pos) for pos, item in enumerate(l1)]
#[(1, 0), (1, 1), (0, 2), (1, 3), (1, 4), (1, 5), (1, 6)]

result = []
for key, group in itertools.groupby(pos, lambda x: x[0]):
    if key == 0:
        #if group is all 0 then we don't change anything
        result.extend(l2[g[1]] for g in group)
    else:
        #else do OR operation in current group and append to final list
        current = 0
        for g in group:
            current |= l2[g[1]]
        result.append(current)
result
#[0, 0, 1]
1 голос
/ 18 июня 2020

Это может помочь; простой l oop без множества дополнительных переменных.

l1 = [1, 1, 0, 1, 1, 1, 1]
l2 = [0, 0, 0, 1, 0, 0, 0]

answer = []
or_result = 0
index = 0

while index < len(l1):
    # while 1, OR the elements of l2
    while index < len(l1) and l1[index] == 1:
        or_result ^= l2[index]
        index += 1

    answer.append(or_result)

    # while 0, append the elements of l2 as they are
    while index < len(l1) and l1[index] == 0:
        answer.append(l2[index])
        index += 1

    or_result = 0

print(answer)
1 голос
/ 18 июня 2020

Это должно работать. Подход прост.

Где бы вы ни находили 1, проверьте наличие последовательных 1 и отметьте индекс начала и конца. ИЛИ записи для этого диапазона от l2.

Где бы вы ни находили 0, скопируйте соответствующий элемент из l2

index = 0

prev = 0
res = []
while index < len(l1):
    if l1[index] == 1:
        prev = index
        while index < len(l1) and l1[index] == 1:
            index += 1

        tmp = 0
        for i in range(prev,index):
            tmp = tmp|l2[i]
        res.append(tmp)

    elif l1[index] == 0:
        res.append(l2[index])
        index += 1

print(res)
...