CHỈNH SỬA 2: Để trả lời yêu cầu mới của OP
ranges = []
for key, group in groupby(enumerate(data), lambda (index, item): index - item):
group = map(itemgetter(1), group)
if len(group) > 1:
ranges.append(xrange(group[0], group[-1]))
else:
ranges.append(group[0])
Đầu ra:
[xrange(2, 5), xrange(12, 17), 20]
Bạn có thể thay thế xrange bằng dải ô hoặc bất kỳ lớp tùy chỉnh nào khác.
Tài liệu Python có một công thức rất gọn gàng cho việc này:
from operator import itemgetter
from itertools import groupby
data = [2, 3, 4, 5, 12, 13, 14, 15, 16, 17]
for k, g in groupby(enumerate(data), lambda (i,x):i-x):
print map(itemgetter(1), g)
Đầu ra:
[2, 3, 4, 5]
[12, 13, 14, 15, 16, 17]
Nếu bạn muốn nhận được cùng một đầu ra, bạn có thể làm như sau:
ranges = []
for k, g in groupby(enumerate(data), lambda (i,x):i-x):
group = map(itemgetter(1), g)
ranges.append((group[0], group[-1]))
đầu ra:
[(2, 5), (12, 17)]
CHỈNH SỬA: Ví dụ đã được giải thích trong tài liệu nhưng có lẽ tôi nên giải thích thêm:
Chìa khóa của giải pháp là phân biệt với một phạm vi để các số liên tiếp xuất hiện trong cùng một nhóm.
Nếu dữ liệu là: [2, 3, 4, 5, 12, 13, 14, 15, 16, 17]
Thì groupby(enumerate(data), lambda (i,x):i-x)
tương đương như sau:
groupby(
[(0, 2), (1, 3), (2, 4), (3, 5), (4, 12),
(5, 13), (6, 14), (7, 15), (8, 16), (9, 17)],
lambda (i,x):i-x
)
Hàm lambda trừ chỉ số phần tử khỏi giá trị phần tử. Vì vậy, khi bạn áp dụng lambda trên mỗi mục. Bạn sẽ nhận được các khóa sau để chia nhóm:
[-2, -2, -2, -2, -8, -8, -8, -8, -8, -8]
groupby nhóm các phần tử theo giá trị khóa bằng nhau, vì vậy 4 phần tử đầu tiên sẽ được nhóm lại với nhau, v.v.
Tôi hy vọng điều này làm cho nó dễ đọc hơn.
python 3
phiên bản có thể hữu ích cho người mới bắt đầu
nhập các thư viện cần thiết trước
from itertools import groupby
from operator import itemgetter
ranges =[]
for k,g in groupby(enumerate(data),lambda x:x[0]-x[1]):
group = (map(itemgetter(1),g))
group = list(map(int,group))
ranges.append((group[0],group[-1]))