我有一个列表
results = [100, 100, -100, 100, -100, -100]
我想弄清楚第一次出现相反的数字。所以前100个匹配第一个-100,第二个100匹配第二个-100。
我希望将输出定位为:
[0, 2], [1, 4], [3, 5]
即:[0,2]
代表results[0]
和results[2]
,其中第一次出现的100与第一次出现的-100匹配
编辑:您可以假设总是会有相同数量的正面/负数,而且该列表只包含1个数字
任何帮助都会被批评
答案 0 :(得分:3)
对于列表中只包含2个整数(x
和-x
)的简单情况,您可以简单地zip()
将索引放在一起:
indexes = [[],[]]
for i,x in enumerate(results):
indexes[0].append(i) if x > 0 else indexes[1].append(i)
list(zip(*indexes))
示例:
>>> results = [100, 100, -100, 100, -100, -100]
>>> indexes = [[],[]]
>>> for i,x in enumerate(results): indexes[0].append(i) if x > 0 else indexes[1].append(i)
...
>>> list(zip(*indexes))
[(0, 2), (1, 4), (3, 5)]
注意小输入2个单独的列表推导(例如[i for i,x in enumerate(results) if x > 0]
可能比追加for
循环更快。
答案 1 :(得分:2)
这应该有效:
results = [100, 100, -100, 100, -100, -100]
solution = []
for i, x in enumerate(results):
if x > 0 and isinstance(x, int):
y = results.index(-x)
results[results.index(-x)] = 'found'
solution.append([i,y])
print solution
答案 2 :(得分:2)
这对于出现不同数字的一般情况也适用:
solutions = []
for x in set(abs(x) for x in results):
solutions += list(zip([i for i, x2 in enumerate(results) if x2 == x],
[i for i, x2 in enumerate(results) if x2 == x*-1]))
答案 3 :(得分:2)
我们可以分两个阶段有效地完成这项工作。在分析阶段中,我们过滤掉正数,对它们进行排序并按索引对它们进行分组,例如:
from itertools import groupby
subresult = dict(map(lambda x:(x[0],iter(tuple(x[1]))),
groupby(sorted(filter(lambda x:x[1] < 0,enumerate(results)),
key=lambda x:x[::-1]),lambda x:x[1])
))
或者我们可以逐步生成 ,例如:
subresult = filter(lambda x:x[1] < 0,enumerate(results)) # filter negative values
subresult = sorted(subresult,key=lambda x:x[::-1]) # sort them on value and then on index
subresult = groupby(subresult,lambda x:x[1]) # group them on the value
subresult = map(lambda x:(x[0],iter(tuple(x[1]))),subresult) # construct a sequence of tuples (value,list of indices)
subresult = dict(subresult) # make it a dictionary
这会生成一个字典:
{-100: <itertools._grouper object at 0x7fedfb523ef0>}
接下来在构建阶段中,我们迭代所有正整数,并始终从subresult
字典中取出下一个相反的整数。像:
end_result = [[i,next(subresult[-v])[0]] for i,v in enumerate(results) if v > 0]
这会产生:
>>> subresult = dict(map(lambda x:(x[0],iter(tuple(x[1]))),groupby(sorted(filter(lambda x:x[1] < 0,enumerate(results)),key=lambda x:x[::-1]),lambda x:x[1])))
>>> [[i,next(subresult[-v])[0]] for i,v in enumerate(results) if v > 0]
[[0, 2], [1, 4], [3, 5]]
通常由于字典查找,并且因为我们使用迭代器(因此我们对哪个索引进行簿记),这将非常有效。
答案 4 :(得分:2)
IMO,最快的方法(对于大输入)应该是以下一种方法(但是,我的解决方案并不假设输入列表只包含一个值及其相反的值,所以如果这样做可以更快假设被添加):
x = [100, 300, -300, 100, -100, -100]
from collections import defaultdict, deque
unmatched_positives = defaultdict(deque)
solution=[]
for i, val in enumerate(x):
if val > 0:
unmatched_positives[val].append(i)
else:
solution.append( (unmatched_positives[-val].popleft(), i) )
print('Unsorted solution:', solution)
# If you need the result to be sorted
print('Sorted solution:', sorted(solution))
输出:
Unsorted solution: [(1, 2), (0, 4), (3, 5)]
Sorted solution: [(0, 4), (1, 2), (3, 5)]
答案 5 :(得分:2)
这种基于观察的简单方法怎么样?使用列表推导将其拆分为两个列表,然后按照您希望的顺序将它们zip
分开。
使用列表理解
In [18]: neg_list = [idx for idx, el in enumerate(results) if el < 0]
In [19]: pos_list = [idx for idx, el in enumerate(results) if el > 0]
In [20]: neg_list
Out[20]: [2, 4, 5]
In [21]: pos_list
Out[21]: [0, 1, 3]
In [22]: list(zip(pos_list, neg_list))
Out[22]: [(0, 2), (1, 4), (3, 5)]
您还可以从zip
的订单中修改所需的索引。
NumPy版本: 对于较大的列表(或等效的数组),numpy版本应该更快。
In [30]: res = np.array(results)
In [38]: pos_idx = np.where(res > 0)[0]
In [39]: pos_idx
Out[39]: array([0, 1, 3])
In [40]: neg_idx = np.where(res < 0)[0]
In [42]: neg_idx
Out[42]: array([2, 4, 5])
In [44]: list(zip(pos_idx, neg_idx))
Out[44]: [(0, 2), (1, 4), (3, 5)]
# If you want to avoid using zip, then
# just use np.vstack and transpose the result
In [59]: np.vstack((pos_idx, neg_idx)).T
Out[59]:
array([[0, 2],
[1, 4],
[3, 5]])
P.S。:您也可以使用generator comprehension
来获得相同的结果,但请注意,将生成器转换为列表一次后它将会耗尽。
使用生成器理解
In [24]: neg_gen = (idx for idx, el in enumerate(results) if el < 0)
In [25]: pos_gen = (idx for idx, el in enumerate(results) if el > 0)
In [27]: list(zip(pos_gen, neg_gen))
Out[27]: [(0, 2), (1, 4), (3, 5)]
# on 2nd run, there won't be any element in the generator.
In [28]: list(zip(pos_gen, neg_gen))
Out[28]: []
答案 6 :(得分:1)
pos = {}
for i,item in enumerate(results ):
if item < 0: continue
if item not in pos:
pos[item] = []
pos[item].append(i)
[ [pos[-item].pop(0), i] for i,item in enumerate(results ) if item < 0]
[[0, 2], [1, 4], [3, 5]]
答案 7 :(得分:1)
对于results
仅包含两个不同整数的示例案例:
import numpy as np
results = np.array([100, 100, -100, 100, -100, -100])
output = list(zip(np.where(results > 0)[0], np.where(results < 0)[0]))
输出:
[(0, 2), (1, 4), (3, 5)]
~0.002
的时间为results * 1000
。