我正在用python编写代码来查找整数的因子对。但是配对时也会导致反向配对。我想使用一种简单的方法消除这些反向对,而无需导入任何模块。 例如。
[[1, 200], [2, 100], [4, 50], [5, 40], [8, 25], [10, 20], [20, 10], [25, 8], [40, 5], [50, 4], [100, 2], [200, 1]]
输出应为:
[[1, 200], [2, 100], [4, 50], [5, 40], [8, 25], [10, 20]]
这是到目前为止我得到的:
N = []
J = []
F = []
Z = []
S = []
num = input("Enter no. of elements in list")
print ('Enter numbers')
prod = 1
for i in range(int(num)):
n = input("num :")
N.append(int(n))
for x in N:
prod = prod*x
print (prod)
k = input("Enter no. of splits:")
for o in range(1,prod+1):
if prod%o == 0:
J.append(o)
F.append(o)
print (J)
Z = [[a, b] for a in J for b in F if a*b == prod]
print (Z)
答案 0 :(得分:7)
使用set
删除重复项。
例如:
lst = [[1, 200], [2, 100], [4, 50], [5, 40], [8, 25], [10, 20], [20, 10], [25, 8], [40, 5], [50, 4], [100, 2], [200, 1]]
lst = set([tuple(sorted(i)) for i in lst]) #Sort inner list and then use set
lst = list(map(list, lst)) #Converting back to list
print(lst)
输出:
[[8, 25], [4, 50], [1, 200], [10, 20], [2, 100], [5, 40]]
答案 1 :(得分:5)
如果输入很大,则使用集合而不是列表将具有显着的性能优势。
>>> unique = set(map(frozenset, pairs))
>>> unique
{frozenset({1, 200}),
frozenset({10, 20}),
frozenset({5, 40}),
frozenset({2, 100}),
frozenset({8, 25}),
frozenset({4, 50})}
内部集合必须为frozenset
,因为常规集合是可变的,并且集合只能包含不可变的子代。
要转换回列表列表。
>>> list(map(list, unique))
[[200, 1], [10, 20], [40, 5], [2, 100], [8, 25], [50, 4]]
集合是可迭代的,因此根据您的使用情况,可能不需要此步骤。
这是一个既执行步骤又将结果作为嵌套列表返回的函数。
def unique_pairs(pairs):
return list(map(list,set(map(frozenset, pairs))))
请注意,将列表转换为集合会将包含相同对(例如[20,20]
)的列表转换为单个元素集({20}
)。因此,如果您的输入可以包含相同的对,则可能需要执行额外的最后一步,将单例扩展回对。
def unique_pairs(pairs):
return [(2*[*p])[:2] for p in set(map(frozenset,pairs))]
这将适用于机器人双胞胎对和混合对。
>>> pairs = [[10, 2], [2, 10], [10, 10], [2, 2]]
>>> unique_pairs(pairs)
[[10, 10], [2, 2], [10, 2]]
答案 2 :(得分:4)
>>> l = [[1, 200], [2, 100], [4, 50], [5, 40], [8, 25], [10, 20], [20, 10], [25, 8], [40, 5], [50, 4], [100, 2], [200, 1]]
>>> new_l = []
>>> for e in l:
... if e not in new_l and sorted(e) not in new_l:
... new_l.append(e)
...
>>> new_l
[[1, 200], [2, 100], [4, 50], [5, 40], [8, 25], [10, 20]]
>>>
答案 3 :(得分:3)
您可以保留一个集合以跟踪所看到的内容,并使用frozenset()
将列表散列到所看到的集合中:
seen = set()
result = []
for sublst in lst:
curr = frozenset(sublst)
if curr not in seen:
seen.add(curr)
result.append(sublst)
print(result)
哪些输出:
[[1, 200], [2, 100], [4, 50], [5, 40], [8, 25], [10, 20]]
如果以后要使用库,则可以使用collections.OrderedDict()
:
lst = [[1, 200], [2, 100], [4, 50], [5, 40], [8, 25], [10, 20], [20, 10], [25, 8], [40, 5], [50, 4], [100, 2], [200, 1]]
d = OrderedDict()
for sublist in lst:
d.setdefault(frozenset(sublist), sublist)
print(list(d.values()))
# [[1, 200], [2, 100], [4, 50], [5, 40], [8, 25], [10, 20]]
答案 4 :(得分:2)
myList = [[1, 200], [2, 100], [4, 50], [5, 40], [8, 25], [10, 20], [20, 10], [25, 8], [40, 5], [50, 4], [100, 2], [200, 1]]
newList = myList.copy()
for i, j in newList:
newList.remove([j,i])
print (newList)
#[[1, 200], [2, 100], [4, 50], [5, 40], [8, 25], [10, 20]]
答案 5 :(得分:2)
您可以使用toolz.unique
来维护外部级别的排序。如果您无权访问第三方toolz
库,则可以使用官方文档中的unique_everseen
食谱。
L = [[1, 200], [2, 100], [4, 50], [5, 40], [8, 25], [10, 20],
[20, 10], [25, 8], [40, 5], [50, 4], [100, 2], [200, 1]]
from toolz import unique
res = list(unique(map(tuple, map(sorted, L))))
print(res)
[(1, 200), (2, 100), (4, 50),
(5, 40), (8, 25), (10, 20)]
由于unique
使用哈希,因此需要进行元组转换;元组可散列,而列表则不可。如果重要的是要有列表列表,则可以应用额外的转化:
res = list(map(list, unique(map(tuple, map(sorted, L)))))
在此阶段,它不是特别可读,所以我建议您分成几个步骤:
sorter = map(sorted, L)
uniquify = unique(map(tuple, sorter))
res = list(map(list, uniquify))
答案 6 :(得分:2)
我期待投票,因为我的回答似乎与话题无关。
首先,您只需要检查不超过int((prod + 1)** 0.5)+1的值即可确保没有重复项。
N = []
J = []
F = []
Z = []
S = []
num = input("Enter no. of elements in list: ")
print ('Enter numbers')
prod = 1
for i in range(int(num)):
n = input("num :")
N.append(int(n))
for x in N:
prod = prod*x
print (prod)
k = input("Enter no. of splits:")
for o in range(1,int(prod**0.5)+1):
if prod%o == 0:
Z.append([o,prod//o])
print (Z)
结果:
Enter no. of elements in list: 1
Enter numbers
num :200
Enter no. of splits:0
[1, 2, 4, 5, 8, 10]
[[1, 200], [2, 100], [4, 50], [5, 40], [8, 25], [10, 20]]
答案 7 :(得分:1)
我认为在这种情况下,您可以在此处使用一些领域知识。具体来说,您将获得[x, y]
对(我建议您将其设为一个元组(特别是2元组,也称为 pair )而不是数组),以及{{1} },除非[y,x]
仅获得一次。因此,您可以编写一个简单的函数:
x=y
答案 8 :(得分:1)
以一般方式正确解决这个问题实际上很棘手。
它实质上可以归结为两个基本问题:
我将分别解决这些问题。
我最好参考here中的Raymond Hettingers答案:
O(n):最好使用 Counter() 方法(如果您的对象是可哈希的):
from collections import Counter def compare(s, t): return Counter(s) == Counter(t)
O(n log n):其次是 sorted() 方法(如果您的对象是可订购的):
def compare(s, t): return sorted(s) == sorted(t)
O(n * n):如果对象既不可散列也不可排序,则可以使用相等性:
def compare(s, t): t = list(t) # make a mutable copy try: for elem in s: t.remove(elem) except ValueError: return False return not t
在您的情况下,您不需要任何导入,因此可以将collections.Counter
替换为:
def count(it):
d = {}
for item in it:
try:
d[item] += 1
except KeyError:
d[item] = 1
return d
只要这些项目是可哈希的并且您不关心项目的数量(例如[1,1,2]
应该解释为等于[1,2,2]
),否则它们将始终是唯一的,那么您也可以使用set
:
def compare(s, t):
return set(s) == set(t)
这样,您可以检查两个子列表是否包含相同的元素。如果您可能有不同长度的列表,则可以进行一些优化,然后添加:
if len(s) != len(t):
return False
在每个功能的开头。
这还取决于对结果(非重复项是否应保持其相对顺序)和内容(同样,可以对内容进行散列还是可以对其进行排序)的假设。
如果项目是可哈希的(或可以转换为可哈希的内容),则可以使用set
调用来删除重复项。如果您关心订单,您仍然可以使用集合,但只能用于查找,例如itertools文档unique_everseen
中的食谱:
from itertools import filterfalse
def unique_everseen(iterable, key=None):
"List unique elements, preserving order. Remember all elements ever seen."
# unique_everseen('AAAABBBCCDAABBB') --> A B C D
# unique_everseen('ABBCcAD', str.lower) --> A B C D
seen = set()
seen_add = seen.add
if key is None:
for element in filterfalse(seen.__contains__, iterable):
seen_add(element)
yield element
else:
for element in iterable:
k = key(element)
if k not in seen:
seen_add(k)
yield element
您没有提到任何导入,但是幸运的是我们仍然不需要key is None
部分(请参见下文),因此您可以简单地使用它:
def unique_everseen(iterable, key):
seen = set()
seen_add = seen.add
for element in iterable:
k = key(element)
if k not in seen:
seen_add(k)
yield element
请注意,比较内部列表的方法使用了不可散列的集合,字典和列表。但是所有这些都可以转换为可哈希化的集合,例如Frozensets或tuples:
# for sets
frozenset(s)
# for dictionaries
frozenset(d.items())
# for lists
tuple(l)
但是最后一种方法(如果物品不能散列并且不能订购)不能与这种方法一起使用,所以现在让我们忽略它。
基本上,您可以这样使用unique_everseen
:
list(unique_everseen(your_list, key=lambda sublist: frozenset(count(sublist).items())))
# Or with collections.Counter instead of count
或者如果您不在乎子列表中的重复项(或者将不会有重复项):
list(unique_everseen(your_list, key=frozenset))
或者它们不可散列但可以订购:
list(unique_everseen(your_list, key=lambda sublist: tuple(sorted(sublist))))
如果不能使用这种快速unique_everseen
方法来完成子列表中的项目不可散列和不可排序的情况,则只能采用这种方法。您必须使用较慢的变体:
def compare(s, t):
t = list(t) # make a mutable copy
try:
for elem in s:
t.remove(elem)
except ValueError:
return False
return not t
def unique_everseen_slow(iterable):
seen = []
for element in iterable:
for already_seen_item in seen:
if compare(element, already_seen_item):
break # We found a match, so stop looking
else:
seen.append(element)
yield element
list(unique_everseen_slow(your_list))
else
子句属于for
循环,仅在没有break
时输入。您也可以检查any
来避免出现for
-else
:
def unique_everseen_slow(iterable):
seen = []
for element in iterable:
if not any(compare(element, seen_element) for seen_element in seen):
seen.append(element)
yield element
在您的情况下,这实际上非常容易,因为子列表中的整数是可哈希的和可排序的。但这对于更一般的情况可能会变得非常复杂。
但是,在您的情况下,您甚至可以通过简单地检查因素是否已排序(甚至停止)来避免创建重复因素:
def factors(number):
for candidate in range(1, number + 1):
if number % candidate == 0:
other_factor = number // candidate
if candidate > other_factor:
return
yield [candidate, other_factor]
例如:
>>> list(factors(200))
[[1, 200], [2, 100], [4, 50], [5, 40], [8, 25], [10, 20]]
答案 9 :(得分:0)
lst = [[1, 200], [2, 100], [4, 50], [5, 40], [8, 25], [10, 20], [20, 10], [25, 8], [40, 5], [50, 4], [100, 2], [200, 1]]
[list(i) for i in set([tuple(sorted(i)) for i in l]))]
答案:
[(8, 25), (4, 50), (1, 200), (10, 20), (2, 100), (5, 40)]
说明:
首先,我们需要对每个列表进行排序,以便使重复的列表看起来相似。然后,我们需要将每个列表转换为元组,以便可以使用set()消除重复项。
我们可以直接使用use List,因为list的元素必须是可哈希的才能使用set()。
set([tuple(sorted(i)) for i in l])
这给了我们所有元素的集合,没有重复。但是它是一个集合,每个元素都是一个元组,但它们应该是列表。
我们可以使用列表推导将元组元素转换为列表。