2012-12-31 43 views
33

Chức năng phạm vi có cho phép ghép nối không? Giống như tôi muốn thực hiện một range(30) & ghép nối nó với range(2000, 5002). Vì vậy, phạm vi nối của tôi sẽ 0, 1, 2, ... 29, 2000, 2001, ... 5001Kết hợp hai kết quả chức năng phạm vi

Mã như thế này không hoạt động trên python mới nhất của tôi (ver: 3.3.0)

range(30) + range(2000, 5002) 
+0

Phiên bản python? –

+0

phiên bản python của tôi là phiên bản 3.3.0 .. tôi cũng đã cập nhật trong câu hỏi của tôi – MAG

+1

Bạn muốn nhận được kết quả gì (như trong, loại dữ liệu nào - danh sách đơn giản, trình tạo, cái gì khác)? Bạn muốn làm gì với kết quả? –

Trả lời

34

Bạn có thể sử dụng itertools.chain cho việc này:

from itertools import chain 
concatenated = chain(range(30), range(2000, 5002)) 
for i in concatenated: 
    ... 

Nó hoạt động cho các vòng lặp tùy ý. Lưu ý rằng có sự khác biệt trong hành vi của range() giữa Python 2 và 3 mà bạn nên biết: trong Python 2 range trả về một danh sách và trong Python3 một trình lặp, có hiệu quả về bộ nhớ, nhưng không phải lúc nào cũng mong muốn.

Danh sách có thể được nối với +, trình lặp không thể.

3

range() bằng Python 2.x trả về một danh sách:

>>> range(10) 
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9] 

xrange() bằng Python 2.x trả về một iterator:

>>> xrange(10) 
xrange(10) 

Và trong Python 3 range() cũng trả về một iterator:

>>> r = range(10) 
>>> iterator = r.__iter__() 
>>> iterator.__next__() 
0 
>>> iterator.__next__() 
1 
>>> iterator.__next__() 
2 

Vì vậy, rõ ràng là bạn không thể nối các trình vòng lặp khác bằng cách sử dụng chain() như một người khác đã chỉ ra.

+1

câu trả lời của bạn hữu ích, nhưng không cung cấp giải pháp. –

23

Có thể thực hiện bằng cách sử dụng list-comprehension.

>>> [i for j in (range(10), range(15, 20)) for i in j] 
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 15, 16, 17, 18, 19] 

Làm việc theo yêu cầu của bạn, nhưng đó là câu trả lời dài vì vậy tôi sẽ không đăng nó ở đây.

lưu ý: có thể được làm thành một máy phát điện cho hiệu suất tăng:

for x in (i for j in (range(30), range(2000, 5002)) for i in j): 
    # code 

hoặc thậm chí vào một biến máy phát điện.

gen = (i for j in (range(30), range(2000, 5002)) for i in j) 
for x in gen: 
    # code 
+3

+1 không có phụ thuộc bổ sung – mkind

+0

@mkind cảm ơn, tôi ghét phụ thuộc, mọi người luôn nhảy và trả lời với hàng tấn và thư viện, nhưng chúng không phải lúc nào cũng có sẵn, và chúng thường làm điều tương tự như mã bình thường trong một gói, nó không phải là ma thuật. :) –

+7

Tôi không nghĩ rằng _không sử dụng thư viện chuẩn_ là một đức hạnh của riêng nó, nhưng đây là một câu trả lời hay. –

17

Tôi thích các giải pháp đơn giản nhất có thể (bao gồm cả hiệu quả). Nó không phải là luôn luôn rõ ràng cho dù các giải pháp là như vậy. Dù sao, các range() trong Python 3 là một máy phát điện. Bạn có thể bọc nó vào bất kỳ cấu trúc nào lặp lại. Các list() có khả năng xây dựng một giá trị danh sách từ bất kỳ iterable. Toán tử + cho danh sách nối. Tôi đang sử dụng các giá trị nhỏ hơn trong ví dụ:

>>> list(range(5)) 
[0, 1, 2, 3, 4] 
>>> list(range(10, 20)) 
[10, 11, 12, 13, 14, 15, 16, 17, 18, 19] 
>>> list(range(5)) + list(range(10,20)) 
[0, 1, 2, 3, 4, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19] 

Đây là những gì range(5) + range(10, 20) chính xác đã làm trong Python 2.5 - bởi vì range() trả một danh sách.

Trong Python 3, nó chỉ hữu ích nếu bạn thực sự muốn xây dựng danh sách. Nếu không, tôi khuyên bạn nên sử dụng giải pháp Lev Levitsky's với itertools.chain.Tài liệu cũng cho thấy việc triển khai rất đơn giản:

def chain(*iterables): 
    # chain('ABC', 'DEF') --> A B C D E F 
    for it in iterables: 
     for element in it: 
      yield element 

Giải pháp bởi Inbar Rose là tốt và tương đương với chức năng. Dù sao, +1 của tôi đi đến Lev Levitsky và lập luận của ông về việc sử dụng các thư viện chuẩn. Từ Thiền của Python ...

Khi đối mặt với sự mơ hồ, từ chối sự cám dỗ để đoán.

#!python3 
import timeit 
number = 10000 

t = timeit.timeit('''\ 
for i in itertools.chain(range(30), range(2000, 5002)): 
    pass 
''', 
'import itertools', number=number) 
print('itertools:', t/number * 1000000, 'microsec/one execution') 

t = timeit.timeit('''\ 
for x in (i for j in (range(30), range(2000, 5002)) for i in j): 
    pass 
''', number=number) 
print('generator expression:', t/number * 1000000, 'microsec/one execution') 

Theo tôi, các itertools.chain là dễ đọc hơn. Nhưng điều thực sự quan trọng ...

itertools: 264.4522138986938 microsec/one execution 
generator expression: 785.3081048010291 microsec/one execution 

... nhanh hơn khoảng 3 lần.

+0

điều này là tuyệt vời, tôi sẽ thừa nhận thất bại bằng cách xây dựng các mô-đun thư viện chuẩn hiệu quả. nhưng thời gian của bạn là lạ, trên máy tính của tôi sau khi thử nghiệm rất nhiều, tôi thấy rằng giải pháp của tôi là chỉ khoảng 1,8 lần chậm hơn, như trái ngược với 3 lần chậm hơn. nhưng nó vẫn còn chậm hơn. –

+0

Nó chắc chắn là phần cứng phụ thuộc và có thể cũng phụ thuộc vào hệ điều hành. Tôi đã sử dụng máy tính khá lỗi thời của tôi với bộ xử lý lõi kép AMD Athlon 64 X2 3800+ ở tốc độ 2.01 GHz, với bộ nhớ 3 GB. Hệ điều hành là Windows 7 Home Premium 64 bit (cả bộ vi xử lý và điểm bộ nhớ chỉ là 4,9 - http://windows.microsoft.com/en-US/windows7/What-is-the-Windows-Experience-Index) . Tôi không chắc về triển khai Python. Nói, bạn có thể có nhiều nhân xử lý hơn. – pepr

2

Với sự trợ giúp của phương pháp mở rộng, chúng tôi có thể nối hai danh sách.

>>> a = list(range(1,10)) 
>>> a.extend(range(100,105)) 
>>> a 
[1, 2, 3, 4, 5, 6, 7, 8, 9, 100, 101, 102, 103, 104] 
+2

Điều này là dành cho Python 2, OP sử dụng Python 3. –

+1

Mở rộng không phải là một từ khóa, nó là một phương pháp trên danh sách Python. – user7610

1

tôi đến câu hỏi này bởi vì tôi đã cố gắng để nối một số không rõ các phạm vi, có thể chồng chéo lên nhau, và không muốn giá trị lặp đi lặp lại trong iterator thức. Giải pháp của tôi là sử dụng số set và toán tử union như sau:

range1 = range(1,4) 
range2 = range(2,6) 
concatenated = set.union(set(range1), set(range2) 
for i in concatenated: 
    print(i) 
Các vấn đề liên quan