我正在尝试在我的课程作业中解决这个练习:
创建一个名为 detector_ranges 的函数,该函数获取整数列表作为参数。 然后,该函数应该对该列表进行排序,并将该列表转换为另一个列表,其中对用于所有检测到的间隔。 因此 3,4,5,6 被替换为 (3,7) 对。 不属于任何区间的数字仅产生单个数字。 结果列表由这些数字和数字对组成,以逗号分隔。该功能如何工作的示例:
print(detect_ranges([2,5,4,8,12,6,7,10,13]))
[2,(4,9),10,(12,14)]
我无法理解练习主题,也无法想象如何检测范围。你们有什么提示或技巧吗?
另一种方法。虽然这种方法的效率不如另一种方法,但由于它是一种练习,所以会更容易遵循。
我在Python中使用了
zip
函数来做一些我在下面解释的事情,你可以检查它这里以了解更多信息。
1。首先对列表数据进行排序,这样就得到:
[2, 4, 5, 6, 7, 8, 10, 12, 13]
2。然后找出列表中递增值的差异。就像
(4-2)
,(5-4)
,..如果差异是<=1
,那么它将成为范围的一部分:
(另外,在前面插入一个
0
,只是为了占第一个元素,使得到的列表长度等于原始列表)
>>> diff = [j-i for i, j in zip(lst[:-1], lst[1:])]
>>> diff.insert(0, 0)
>>> diff
[0, 2, 1, 1, 1, 1, 2, 2, 1]
3.现在获取上面列表中差异为
>= 2
的位置。这是为了检测范围:
(再次在前面插入一个
0
,只是为了说明第一个元素,并确保它在范围检测中被选中)
>>> ind = [i for i,v in enumerate(diff) if v >= 2]
>>> ind.insert(0, 0)
>>> ind
[0, 1, 6, 7]
因此,原始列表中的范围为
0 to 1
、1 to 6
和 6 to 7
。
4。使用获得的
ind
列表将元素分组在一起形成范围:
>>> groups = [lst[i:j] for i,j in zip(ind, ind[1:]+[None])]
>>> groups
[[2], [4, 5, 6, 7, 8], [10], [12, 13]]
5。最后得到你想要的范围:
>>> ranges = [(i[0],i[-1]+1) if len(i)>1 else i[0] for i in groups]
>>> ranges
[2, (4, 9), 10, (12, 14)]
将其全部放入一个函数中
detect_ranges
:
def detect_ranges(lst):
lst = sorted(lst)
diff = [j-i for i, j in zip(lst[:-1], lst[1:])]
diff.insert(0, 0)
ind = [i for i,v in enumerate(diff) if v >= 2]
ind.insert(0, 0)
groups = [lst[i:j] for i,j in zip(ind, ind[1:]+[None])]
ranges = [(i[0],i[-1]+1) if len(i)>1 else i[0] for i in groups]
return ranges
示例:
>>> lst = [2,6,1,9,3,7,12,45,46,13,90,14,92]
>>> detect_ranges(lst)
[(1, 4), (6, 8), 9, (12, 15), (45, 47), 90, 92]
>>> lst = [12,43,43,11,4,3,6,6,9,9,10,78,32,23,22,98]
>>> detect_ranges(lst)
[(3, 5), (6, 7), (9, 13), (22, 24), 32, (43, 44), 78, 98]
迭代元素并保存每个区间的
start
。
def detect_ranges(xs):
it = iter(xs)
try:
start = next(it)
except StopIteration:
return
prev = start
for x in it:
if prev + 1 != x:
yield start, prev + 1
start = x
prev = x
yield start, prev + 1
用途:
>>> xs = [2, 4, 5, 6, 7, 8, 10, 12, 13]
>>> ranges = list(detect_ranges(xs))
>>> ranges
[(2, 3), (4, 9), (10, 11), (12, 14)]
如果您想减少单个项目的间隔,例如
(2, 3)
到 2
,您可以这样做:
>>> ranges = [a if a + 1 == b else (a, b) for a, b in ranges]
>>> ranges
[2, (4, 9), 10, (12, 14)]
def detect_ranges(L):
L = sorted(L)
result = []
lo, hi = L[0], L[0]
for i in L[1:]:
if i == hi+1:
hi = i
else:
if hi == lo:
result.append(lo)
else:
result.append((lo, hi+1))
lo = i
hi = i
if lo == hi:
result.append(lo)
else:
result.append((lo, hi+1))
return result