在Python列表中查找重叠的元组并对它们进行混洗

时间:2017-06-25 23:32:11

标签: python list tuples shuffle

我在Python3.x中有以下元组列表,其中每个元组由(start, end)格式的两个整数组成:

list_tuple = [(20, 35), (125, 145), (156, 178), (211, 233), (220, 321), 
                              (227, 234), (230, 231), (472, 498), (4765, 8971)] 
 ## list already sorted except for last tuple

这个元组作为沿实线的间隔,例如, (1,10)是1到10之间的间隔。

我有三种方法可以对这个元组进行排序,可以是单独的第一个元素,单独的第二个元素,也可以是第一个和第二个元素。

仅按第一个元素排序:

sorted_by_first = sorted(list_tuple, key=lambda element: (element[0]) )  ## (first_element, second_element)

输出

print(sorted_by_first)
[(20, 35), (125, 145), (156, 178), (211, 233), (220, 321), (227, 234), (230, 231), (472, 498), (4765, 8971)]

并基于第二个元素进行排序:

sorted_by_second = sorted(list_tuple, key=lambda element: (element[1]) )

输出

print(sorted_by_second)
[(20, 35), (125, 145), (156, 178), (230, 231), (211, 233), (227, 234), (220, 321), (472, 498), (4765, 8971)]

和两者:

sorted_by_both = sorted(list_tuple, key=lambda element: (element[0], element[1]) )

输出

print(sorted_by_both)
[(20, 35), (125, 145), (156, 178), (211, 233), (220, 321), (227, 234), (230, 231), (472, 498), (4765, 8971), ...]

请注意,每个排序的输出都按不同的顺序排列。排序不同的那些元组是“重叠间隔”,例如,应(227, 234) (230, 231)放置在def find_overlaps(input_tuple_list, search_interval): results = [] for tup in input_tuple_list: if ((tup[0] >= search_interval[0] and tup[0] <= search_interval[1]) or (tup[1] >= search_interval[0] and tup[1] <= search_interval[1])): results.append(tup) return results 之前或之后,因为这些区间重叠。

我的目标是创建一个功能,其中(1)搜索已排序的输出中的“重叠间隔”,然后(2)随后在它们之间随机置换它们。

我可以想到一个输出与给定元组重叠的所有元组的函数,例如

foo = (130, 150)
overlapping_foo = find_overlaps(list_tuple, foo)
print(overlapping_foo)
[(125, 145)]

的工作原理如下

list_tuple

但是,为了实现目标(1),我需要编写一个函数来查找total_overlaps = [] for tupp in list_tuple: total_overlaps.append(find_overlaps(list_tuple, tupp)) 中所有重叠的元组。

我尝试了什么:我原本以为我可以自己搜索原始元组,例如

overlap_list = [(211, 233), (220, 321), (227, 234), (230, 231), (6491, 7000), (6800, 7200)]

这显然是错误的,因为输出是原始元组本身。

更大的问题是我无法看到如何执行目标(2)。我必须只是改组/重新排序彼此重叠的元组。假设我有一个从(1)找到的重叠元组列表:

from random import shuffle
reordered = [shuffle(tupp) for tupp in overlap_list]

以下列表理解失败

TypeError: 'tuple' object does not support item assignment

(6491, 7000)

同样重要的是,我不要将(211, 233)<android.support.design.widget.TextInputLayout android:id="@+id/firstNameTextInputLayout" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="20dp"> <android.support.design.widget.TextInputEditText android:id="@+id/firstNameTextInputEditText" android:layout_width="match_parent" android:layout_height="wrap_content" android:hint="@string/firstName" android:inputType="textPersonName" tools:ignore="MissingPrefix" /> </android.support.design.widget.TextInputLayout> 混为一谈,因为这些不相关。

如何在元组列表中找到重叠区间,然后单独将这些重叠的元组混合在一起。

2 个答案:

答案 0 :(得分:2)

请注意我非常清楚你对shuffle的要求。但您可以使用itertools食谱pairwise配对元素,然后使用itertools.groupby()对序列重叠进行分组,即从(211, 233)分割(6491, 7000)

import itertools as it

def pairwise(iterable):
    "s -> (s0,s1), (s1,s2), (s2, s3), ..."
    a, b = it.tee(iterable)
    next(b, None)
    return zip(a, b)

>>> overlap_list = [(211, 233), (220, 321), (227, 234), (230, 231), (6491, 7000), (6800, 7200)]
>>> [list(p) for k, p in it.groupby(pairwise(overlap_list), lambda x: x[0][0] < x[1][0] < x[0][1]) if k]
[[((211, 233), (220, 321)), ((220, 321), (227, 234)), ((227, 234), (230, 231))],
 [((6491, 7000), (6800, 7200))]]

您可以unpairwise这些列表:

def unpairwise(iterable):
    a, b = zip(*iterable)
    yield a[0]
    yield from b

所以:

>>> [list(unpairwise(p)) for k, p in it.groupby(pairwise(overlap_list), lambda x: x[0][0] < x[1][0] < x[0][1]) if k]
[[(211, 233), (220, 321), (227, 234), (230, 231)], [(6491, 7000), (6800, 7200)]]

答案 1 :(得分:1)

@AChampion扩展答案,应该很容易随机播放重叠元组列表列表以获得您想要的内容:

>>> overlaps = [[(211, 233), (220, 321), (227, 234), (230, 231)], [(6491, 7000), (6800, 7200)]]
>>> for x in overlaps: 
...     random.shuffle(x)
...
>>> overlaps
[[(227, 234), (230, 231), (220, 321), (211, 233)], [(6491, 7000), (6800, 7200)]]
>>> for x in overlaps:
...     random.shuffle(x)
...
>>> overlaps
[[(220, 321), (227, 234), (230, 231), (211, 233)], [(6491, 7000), (6800, 7200)]]
>>> for x in overlaps:
...     random.shuffle(x)
...
>>> overlaps
[[(227, 234), (211, 233), (220, 321), (230, 231)], [(6800, 7200), (6491, 7000)]]

请注意random.shuffle已到位。