从列表列表中删除重复的内容,而不保留任何顺序

时间:2018-07-21 14:04:46

标签: python

我正在用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)

10 个答案:

答案 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]) 

这给了我们所有元素的集合,没有重复。但是它是一个集合,每个元素都是一个元组,但它们应该是列表。

我们可以使用列表推导将元组元素转换为列表。