我有四种颜色的线段 - 粉红色,绿色,橙色,红色 - 如下图所示。
例如,第一个粉红色细分具有开始和结束位置(5258,5422)
。
坐标存储在这个元组字典中:
mycoord = { 'pink' :[(5258,5422), (5479,5864)],
'green' :[(5425,5450)],
'orange':[(5266,5770)],
'red' :[(5258,5864)] }
我想要做的是获取所有可能的交叉点的开始值和结束值,如下图所示:
因此,期望的答案是:
sect1/pink-red : 5258,5266
sect2/pink-orange-red : 5266,5422
sect3/orange-red : 5422,5425
sect4/green-orange-red: 5425,5450
sect5/orange-red : 5450,5479
sect6/pink-orange-red : 5479,5770
sect7/pink-red : 5770,5864
请注意,我想保留每个交叉点的颜色指示符(例如, pink-red
)。我怎样才能用Python实现这个目标?
答案 0 :(得分:1)
使用Michael Laszlo的支撑开/关概念:
>>> mycoord = { 'pink' :[(5258,5422), (5479,5864)],
'green' :[(5425,5450)],
'orange':[(5266,5770)],
'red' :[(5258,5864)] }
>>> labeled_values=[]
# make tuples of (value, brace status (open/close), color)
>>> for color,color_ranges in mycoord.items():
for color_range in color_ranges:
labeled_values.append((color_range[0],True,color))
labeled_values.append((color_range[1],False,color))
# labeled_values are now like (5258, True, 'pink'), (5422, False, 'pink') ...
>>> sects = []
# traverse the sorted values and maintain a color-set
>>> color_set_so_far=set()
>>> range_start = -1
>>> for value,range_open,color in sorted(labeled_values):
if not range_open or range_start != value:
sects.append(("-".join(color_set_so_far), range_start, value))
if range_open:
color_set_so_far.add(color)
else:
color_set_so_far.remove(color)
range_start = value
>>> sects = [s for s in sects if s[0] and s[1]!=s[2]] # filter out empty ranges
>>> sects
# [('pink-red', 5258, 5266), ('pink-orange-red', 5266, 5422), ('orange-red', 5422, 5425), ('orange-green-red', 5425, 5450), ('orange-red', 5450, 5479), ('pink-orange-red', 5479, 5770), ('pink-red', 5770, 5864)]
答案 1 :(得分:1)
我建议你按照以下步骤进行操作。
对端点进行排序,记住每个端点的颜色以及它是左(开始)还是右(关闭)端点。
迭代端点,使用哈希跟踪开放跨度,该哈希将每种颜色映射到该颜色的开放跨度数。打开给定颜色的跨度时递增,当关闭跨度时递减。当计数达到零时删除颜色。对于每个不同的端点,将该点上所有打开的跨度的颜色放入一个集合中。
迭代连续的不同端点对。这些形成了您感兴趣的跨度的左右端点。对于每个端点,您都知道该点处的活动颜色。在跨度期间处于活动状态的颜色集是左端活动颜色的set intersection和右端活动的颜色。
注意:如果两个端点之间的颜色为空,则表示您在跨距之间找到了间隙,因此您知道应该跳过它。您可能还想跳过只有一种颜色的跨度。下面的实现没有。您可以通过修改此行轻松更改它以跳过单色跨度:
if len(colors) > 0:
所以它写着:
if len(colors) > 1:
如果您对查看跨距之间的差距感兴趣,可以将阈值更改为-1
或完全删除条件。
实现:
mycoord = { 'pink' :[(5258,5422), (5479,5864)],
'green' :[(5425,5450)],
'orange':[(5266,5770)],
'red' :[(5258,5864)] }
# Sort the endpoints. Remember their color and whether they open or close.
points = []
for color, spans in mycoord.items():
for open, close in spans:
points.append((open, 'open', color))
points.append((close, 'close', color))
points.sort()
# Iterate over the endpoints. Keep track of open spans. Mark intersections.
active_spans = {}
intersections = []
for point, kind, color in points:
if len(intersections) != 0 and intersections[-1][0] == point:
intersections[-1][1].add(color)
else:
color_set = set([color] + list(active_spans.keys()))
intersections.append((point, color_set))
if kind == 'close':
active_spans[color] -= 1
if active_spans[color] == 0:
del active_spans[color]
else:
active_spans[color] = active_spans.setdefault(color, 0) + 1
# Iterate over consecutive pairs of unique intersections. Intersect the color sets.
tab_width = sum(map(len, mycoord)) + len(mycoord)
count = 0
for i in range(1, len(intersections)):
a, b = intersections[i - 1], intersections[i]
colors = sorted(a[1] & b[1])
if len(colors) > 0:
count += 1
print('sect{0}/{1:<{2}}: {3},{4}'.format(count, '-'.join(colors), tab_width,
a[0], b[0]))
结果:
sect1/pink-red : 5258,5266
sect2/orange-pink-red : 5266,5422
sect3/orange-red : 5422,5425
sect4/green-orange-red : 5425,5450
sect5/orange-red : 5450,5479
sect6/orange-pink-red : 5479,5770
sect7/pink-red : 5770,5864