作为更大算法的一部分,我遇到并解决了这个问题,但我的解决方案似乎不够优雅,我会很感激任何见解。
我有一对可以在笛卡尔平面上被视为点的对列表。我需要生成三个列表:排序的x值,排序的y值,以及一个列表,该列表将排序的x值中的索引与排序的y值中的索引相对应,y值对应于最初配对的y值。 / p>
一个具体的例子可能有助于解释。鉴于以下列表:
((3,7),(15,4),(7,11),(5,0),(4,7),(9,12))
x值的排序列表将是(3,4,5,7,9,15),y值的排序列表将是(0,4,7,7,11,12)。
假设基于零的索引方案,将x列表索引映射到其配对y列表索引的索引的列表将是(2,3,0,4,5,1)。
例如,值7在x列表中显示为索引3。索引3处的映射列表中的值为4,y列表中索引4处的值为11,对应于原始配对(7,11)。
生成此映射列表的最简单方法是什么?
答案 0 :(得分:3)
这是一个简单的O(nlog n)方法:
答案 1 :(得分:1)
我提出以下建议。 生成未排序的x和y列表。
xs = [3, 15, 7, 5, 4, 9 ]
ys = [7, 4, 11, 0, 7, 12]
将每个元素转换为元组 - 该对中的第一个是坐标,第二个是原始索引。
xs = [(3, 0), (15, 1), ( 7, 2), (5, 3), (4, 4), ( 9, 5)]
ys = [(7, 0), ( 4, 1), (11, 2), (0, 3), (7, 4), (12, 5)]
对两个列表进行排序。
xs = [(3, 0), (4, 4), (5, 3), (7, 2), ( 9, 5), (15, 1)]
ys = [(0, 3), (4, 1), (7, 0), (7, 4), (11, 2), (12, 5)]
创建一个数组y_positions
。数组的第n个元素包含最初位于索引n的y元素的当前索引。
创建一个空的index_list
。
对于xs
的每个元素,获取original_index
,第二对元组。
使用y_positions
检索具有给定original_index
的y元素的当前索引。将当前索引添加到index_list
。
最后,从xs
和ys
中删除索引值。
以下是Python实现示例。
points = ((3, 7), (15, 4), (7, 11), (5, 0), (4, 7), (9, 12))
#generate unsorted lists
xs, ys = zip(*points)
#pair each element with its index
xs = zip(xs, range(len(xs)))
ys = zip(ys, range(len(xs)))
#sort
xs.sort()
ys.sort()
#generate the y positions list.
y_positions = [None] * len(ys)
for i in range(len(ys)):
original_index = ys[i][1]
y_positions[original_index] = i
#generate `index_list`
index_list = []
for x, original_index in xs:
index_list.append(y_positions[original_index])
#remove tuples from x and y lists
xs = zip(*xs)[0]
ys = zip(*ys)[0]
print "xs:", xs
print "ys:", ys
print "index list:", index_list
输出:
xs: (3, 4, 5, 7, 9, 15)
ys: (0, 4, 7, 7, 11, 12)
index list: [2, 3, 0, 4, 5, 1]
y_positions
和index_list
的生成是O(n)时间,因此整个算法的复杂性由排序步骤决定。
答案 2 :(得分:1)
感谢您的回答。对于它的价值,我所拥有的解决方案与概述的解决方案非常类似,但正如j_random_hacker指出的那样,不需要地图。让我感到震惊的是,这个小问题看起来比初看起来更复杂,我想知道我是否遗漏了一些明显的东西。我已经将我的解决方案重新用于Python进行比较。
points = ((3, 7), (15, 4), (7, 11), (5, 0), (4, 7), (9, 12))
N = len(points)
# Separate the points into their x and y components, tag the values with
# their index into the points list.
# Sort both resulting (value, tag) lists and then unzip them into lists of
# sorted x and y values and the tag information.
xs, s = zip(*sorted(zip([x for (x, y) in points], range(N))))
ys, r = zip(*sorted(zip([y for (x, y) in points], range(N))))
# Generate the mapping list.
t = N * [0]
for i in range(N):
t[r[i]] = i
index_list = [t[j] for j in s]
print "xs:", xs
print "ys:", ys
print "index_list:", index_list
输出:
xs: (3, 4, 5, 7, 9, 15)
ys: (0, 4, 7, 7, 11, 12)
index_list: [2, 3, 0, 4, 5, 1]
答案 3 :(得分:1)
我刚才通过最初对x中的点进行排序来理解j_random_hacker的意义。这样可以很好地整理东西。感谢。
points = ((3, 7), (15, 4), (7, 11), (5, 0), (4, 7), (9, 12))
N = len(points)
ordered_by_x = sorted(points)
ordered_by_y = sorted(zip([y for (x, y) in ordered_by_x], range(N)))
index_list = N * [0]
for i, (y, k) in enumerate(ordered_by_y):
index_list[k] = i
xs = [x for (x, y) in ordered_by_x]
ys = [y for (y, k) in ordered_by_y]
print "xs:", xs
print "ys:", ys
print "index_list:", index_list