我想按连续顺序对元组列表进行排序,因此每个元组的第一个元素等于前一个元素的最后一个元素。
例如:
input = [(10, 7), (4, 9), (13, 4), (7, 13), (9, 10)]
output = [(10, 7), (7, 13), (13, 4), (4, 9), (9, 10)]
我开发了这样的搜索:
output=[]
given = [(10, 7), (4, 9), (13, 4), (7, 13), (9, 10)]
t = given[0][0]
for i in range(len(given)):
# search tuples starting with element t
output += [e for e in given if e[0] == t]
t = output[-1][-1] # Get the next element to search
print(output)
有没有pythonic方式来实现这样的秩序? 并且有一种方法可以“就地”#34; (只有一个清单)?
在我的问题中,输入可以使用所有元组以循环方式重新排序,因此选择的第一个元素并不重要。
答案 0 :(得分:8)
假设list
中的元组为圆形,您可以使用dict
在 O(n)的复杂度内实现它:
input = [(10, 7), (4, 9), (13, 4), (7, 13), (9, 10)]
input_dict = dict(input) # Convert list of `tuples` to dict
elem = input[0][0] # start point in the new list
new_list = [] # List of tuples for holding the values in required order
for _ in range(len(input)):
new_list.append((elem, input_dict[elem]))
elem = input_dict[elem]
if elem not in input_dict:
# Raise exception in case list of tuples is not circular
raise Exception('key {} not found in dict'.format(elem))
new_list
持有的最终价值为:
>>> new_list
[(10, 7), (7, 13), (13, 4), (4, 9), (9, 10)]
答案 1 :(得分:5)
如果你不害怕浪费一些内存,你可以创建一个字典start_dict
,其中包含起始整数作为键,元组作为值,并执行以下操作:
tpl = [(10, 7), (4, 9), (13, 4), (7, 13), (9, 10)]
start_dict = {item[0]: item for item in tpl}
start = tpl[0][0]
res = []
while start_dict:
item = start_dict[start]
del start_dict[start]
res.append(item)
start = item[-1]
print(res)
如果两个元组以相同的数字开头,你将丢失其中一个...如果不是所有的起始编号都被使用,则循环将不会终止。
但也许这是要建立的东西。
答案 2 :(得分:2)
实际上,关于您打算将什么作为输出有很多问题,如果输入列表具有无效结构以满足您的需要,那该怎么办。
假设您有一对输入,其中每个数字仅包含两次。因此,我们可以将此类输入视为图形,其中数字是节点,每对都是边缘。据我了解你的问题,你认为这个图是循环的,看起来像这样:
10 - 7 - 13 - 4 - 9 - 10 (same 10 as at the beginning)
这表明您可以缩小列表以将图表存储到[10, 7, 13, 4, 9]
。以下是对输入列表进行排序的脚本:
# input
input = [(10, 7), (4, 9), (13, 4), (7, 13), (9, 10)]
# sorting and archiving
first = input[0][0]
last = input[0][1]
output_in_place = [first, last]
while last != first:
for item in input:
if item[0] == last:
last = item[1]
if last != first:
output_in_place.append(last)
print(output_in_place)
# output
output = []
for i in range(len(output_in_place) - 1):
output.append((output_in_place[i], output_in_place[i+1]))
output.append((output_in_place[-1], output_in_place[0]))
print(output)
答案 3 :(得分:2)
我首先要创建一个表格
的字典{first_value: [list of tuples with that first value], ...}
然后从那里开始工作:
from collections import defaultdict
chosen_tuples = input[:1] # Start from the first
first_values = defaultdict()
for tup in input[1:]:
first_values[tup[0]].append(tup)
while first_values: # Loop will end when all lists are removed
value = chosen_tuples[-1][1] # Second item of last tuple
tuples_with_that_value = first_values[value]
chosen_tuples.append(tuples_with_that_value.pop())
if not chosen_with_that_value:
del first_values[value] # List empty, remove it
答案 4 :(得分:1)
你可以试试这个:
mapData = function() {
"combinationData": {
"combinationName": "2_2",
"dataGroups": {
"tableType": "2",
"twoAxisData": {
for (var i = 0; i < 5; i++) { //Need to add a loop like this to iterate till its value
"vAxis": $scope.vAxis,
"dataValue": {
"hAxis": "2",
"dataValue": $scope.hrows
},
}
}
}
<强>输出:强>
input = [(10, 7), (4, 9), (13, 4), (7, 13), (9, 10)]
output = [input[0]] # output contains the first element of input
temp = input[1:] # temp contains the rest of elements in input
while temp:
item = [i for i in temp if i[0] == output[-1][1]].pop() # We compare each element with output[-1]
output.append(item) # We add the right item to output
temp.remove(item) # We remove each handled element from temp
答案 5 :(得分:0)
这是一个(效率低于字典版本)变体,其中列表就地更改:
tpl = [(10, 7), (4, 9), (13, 4), (7, 13), (9, 10)]
for i in range(1, len(tpl)-1): # iterate over the indices of the list
item = tpl[i]
for j, next_item in enumerate(tpl[i+1:]): # find the next item
# in the remaining list
if next_item[0] == item[1]:
next_index = i + j
break
tpl[i], tpl[next_index] = tpl[next_index], tpl[i] # now swap the items
这是同一个想法的更高效版本:
tpl = [(10, 7), (4, 9), (13, 4), (7, 13), (9, 10)]
start_index = {item[0]: i for i, item in enumerate(tpl)}
item = tpl[0]
next_index = start_index[item[-1]]
for i in range(1, len(tpl)-1):
tpl[i], tpl[next_index] = tpl[next_index], tpl[i]
# need to update the start indices:
start_index[tpl[next_index][0]] = next_index
start_index[tpl[i][0]] = i
next_index = start_index[tpl[i][-1]]
print(tpl)
列表就地更改;字典只包含元组的起始值及其在列表中的索引。
答案 6 :(得分:0)
以下是使用sorted
函数和自定义键函数的强大解决方案:
input = [(10, 7), (4, 9), (13, 4), (7, 13), (9, 10)]
def consec_sort(lst):
def key(x):
nonlocal index
if index <= lower_index:
index += 1
return -1
return abs(x[0] - lst[index - 1][1])
for lower_index in range(len(lst) - 2):
index = 0
lst = sorted(lst, key=key)
return lst
output = consec_sort(input)
print(output)
未修改原始列表。请注意,对于sorted
长度为5的列表,input
被调用3次。在每次调用中,正确放置一个额外的元组。第一个元组保持其原始位置。
我使用了nonlocal
关键字,这意味着此代码仅适用于Python 3(可以使用global
代替使其成为合法的Python 2代码。)
答案 7 :(得分:0)
我的两分钱:
def match_tuples(input):
# making a copy to not mess up with the original one
tuples = input[:] # [(10,7), (4,9), (13, 4), (7, 13), (9, 10)]
last_elem = tuples.pop(0) # (10,7)
# { "first tuple's element": "index in list"}
indexes = {tup[0]: i for i, tup in enumerate(tuples)} # {9: 3, 4: 0, 13: 1, 7: 2}
yield last_elem # yields de firts element
for i in range(len(tuples)):
# get where in the list is the tuple which first element match the last element in the last tuple
list_index = indexes.get(last_elem[1])
last_elem = tuples[list_index] # just get that tuple
yield last_elem
<强>输出强>:
input = [(10,7), (4,9), (13, 4), (7, 13), (9, 10)]
print(list(match_tuples(input)))
# output: [(10, 7), (7, 13), (13, 4), (4, 9), (9, 10)]
答案 8 :(得分:0)
要获得O(n)
算法,需要确保一个算法不对数组进行双循环。实现此目的的一种方法是将已处理的值保留在某种查找表中(dict
将是一个不错的选择。)
例如类似的东西(我希望内联评论很好地解释了这个功能)。这会就地修改列表,并应避免在列表上进行不必要的(甚至是隐式的)循环:
inp = [(10, 7), (4, 9), (13, 4), (7, 13), (9, 10)]
# A dictionary containing processed elements, first element is
# the key and the value represents the tuple. This is used to
# avoid the double loop
seen = {}
# The second value of the first tuple. This must match the first
# item of the next tuple
current = inp[0][1]
# Iteration to insert the next element
for insert_idx in range(1, len(inp)):
# print('insert', insert_idx, seen)
# If the next value was already found no need to search, just
# pop it from the seen dictionary and continue with the next loop
if current in seen:
item = seen.pop(current)
inp[insert_idx] = item
current = item[1]
continue
# Search the list until the next value is found saving all
# other items in the dictionary so we avoid to do unnecessary iterations
# over the list.
for search_idx in range(insert_idx, len(inp)):
# print('search', search_idx, inp[search_idx])
item = inp[search_idx]
first, second = item
if first == current:
# Found the next tuple, break out of the inner loop!
inp[insert_idx] = item
current = second
break
else:
seen[first] = item