2012-04-25 44 views
8

Tôi đã tạo một phương thức để chuyển đổi một số int thành bitfield (trong danh sách) và nó hoạt động, nhưng tôi chắc chắn có giải pháp thanh lịch hơn - tôi vừa mới nhìn chằm chằm vào nó cho đến lâu.Integer to bitfield dưới dạng danh sách

Tôi tò mò, làm cách nào bạn chuyển đổi một int thành bitfield được thể hiện trong một list?

def get(self): 
    results = [] 

    results.append(1 if (self.bits & 1) else 0) 
    results.append(1 if (self.bits & 2) else 0) 
    results.append(1 if (self.bits & 4) else 0) 
    results.append(1 if (self.bits & 8) else 0) 
    results.append(1 if (self.bits & 16) else 0) 
    results.append(1 if (self.bits & 32) else 0) 
    results.append(1 if (self.bits & 64) else 0) 
    results.append(1 if (self.bits & 128) else 0) 

    return results 

def set(self, pin, direction): 
    pin -= 1 
    if pin not in range(0, 8): raise ValueError 

    if direction: self.bits |= (2 ** pin) 
    else: self.bits &=~(2 ** pin) 

Trả lời

22

Làm thế nào về điều này:

def bitfield(n): 
    return [int(digit) for digit in bin(n)[2:]] # [2:] to chop off the "0b" part 

này mang đến cho bạn

>>> bitfield(123) 
[1, 1, 1, 1, 0, 1, 1] 
>>> bitfield(255) 
[1, 1, 1, 1, 1, 1, 1, 1] 
>>> bitfield(1234567) 
[1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 1, 1, 0, 1, 0, 0, 0, 0, 1, 1, 1] 

này chỉ làm việc cho các số nguyên dương, mặc dù.

EDIT:

chuyển đổi để sử dụng intint() là một chút quá mức cần thiết ở đây. Đây là nhanh hơn rất nhiều:

def bitfield(n): 
    return [1 if digit=='1' else 0 for digit in bin(n)[2:]] 

Xem timings:

>>> import timeit 
>>> timeit.timeit("[int(digit) for digit in bin(123)[2:]]") 
7.895014818543946 
>>> timeit.timeit("[123 >> i & 1 for i in range(7,-1,-1)]") 
2.966295244250407 
>>> timeit.timeit("[1 if digit=='1' else 0 for digit in bin(123)[2:]]") 
1.7918431924733795 
+1

1 cho cân nhắc thời gian thoải mái – snugglo

+0

'[123 >> i & 1 cho i trong phạm vi (7, -1, -1)] 'là nhanh nhất trên máy của tôi. – tMC

+0

@tMC: Tôi đã làm lại thời gian trên cả PC của tôi (Win 7 Ultimate 64bit), theo Python 2.7.3 và 3.2.3, và giải pháp của tôi luôn nhanh hơn ít nhất 20% (Python 2) và 45% (Python 3). –

4

Hãy thử

>>>n=1794 
>>>bitfield=list(bin(n))[2:] 
>>>bitfield 
['1', '1', '1', '0', '0', '0', '0', '0', '0', '1', '0'] 

này không làm việc cho n tiêu cực mặc dù và như bạn thấy mang đến cho bạn một danh sách các chuỗi

+1

+1, tôi dường như quên rằng có 'list()' constructor tất cả các thời gian. – Fenikso

+0

Mặc dù nó không trả về danh sách các số nguyên. – Fenikso

+0

Đây không phải là những gì tMC yêu cầu. Anh ta cần một danh sách các số nguyên, bạn cho anh ta một danh sách các chuỗi. Tốt đẹp như hàm tạo 'list()', nó không phải là công cụ thích hợp ở đây. –

16

Điều này không sử dụng bin:

b = [n >> i & 1 for i in range(7,-1,-1)] 

và đây là làm thế nào để xử lý bất kỳ số nguyên theo cách này:

b = [n >> i & 1 for i in range(n.bit_length() - 1,-1,-1)] 

Xem bit_length.

Nếu bạn muốn chỉ số 0 của danh sách để tương ứng với LSB của int, thay đổi thứ tự phạm vi, tức là

b = [n >> i & 1 for i in range(0, n.bit_length()-1)] 

Cũng lưu ý rằng việc sử dụng n.bit_length() có thể là một điểm lỗi nếu bạn đang cố gắng trình bày các giá trị nhị phân có độ dài cố định. Nó trả về số bit tối thiểu để biểu diễn n.

+0

Điều này là hoàn hảo- Tôi biết có một danh sách hiểu tôi đã mất – tMC

+3

Tất nhiên điều này chỉ xử lý 8-bit số nguyên. –

+1

Có thể xử lý bất kỳ số nguyên nào theo cách này: [n >> i & 1 cho i trong phạm vi (n.bit_length() - 1, -1, -1)] – mennanov

0

tôi đang làm điều này cho chương trình của tôi, nơi bạn có thể chỉ định một mẫu để có được giá trị của bạn từ một int:

def field(template, value): 
    sums = [int(v) if v.__class__==str else len(bin(v))-2 for v in template] 
    return [(value>> (sum(sums[:i]) if i else 0))&(~(~0<<int(t)) if t.__class__==str else t) for i,t in enumerate(template)] 

làm thế nào để sử dụng
trong mẫu, xác định ints liên quan đến bit- của bạn kích thước:

field([0b1,0b111,0b1111], 204) #>>> [0, 6, 12] 

hoặc bạn có thể chỉ định các bit-kích thước của mỗi giá trị cần sử dụng chuỗi: (Noob thân thiện)

field(['1','3','4'], 204) #>>> [0, 6, 12] 

EDIT: và ngược lại: (mã riêng biệt)

field(['1','3','4'], [0, 6, 12]) #>>> 204 
field([0b1,0b111,0b1111], [0,3,9]) #>>> 150 

mã:

def field(template, value): 
    res = 0 
    for t, v in zip(template, value)[::-1]: res = (res << (t.bit_length() if t.__class__ is int else int(t)))|v 
    return res 

EDIT2: Mã nhanh^

Các vấn đề liên quan