Удаление дублирующегося содержимого из списка списков, не сохраняя при этом никакого заказа
Я писал код в 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)
Ответы
Ответ 1
>>> 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]]
>>>
Ответ 2
Использование 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]]
Ответ 3
Если вход большой, существует значительное преимущество в производительности за счет использования наборов вместо списков.
>>> 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]]
Ответ 4
Вы можете сохранить набор, чтобы следить за тем, что было видно, и использовать frozenset()
для хэширования списков в 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]]
Ответ 5
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]]
Ответ 6
Вы можете использовать toolz.unique
для поддержания порядка на внешнем уровне. Если у вас нет доступа к 3 - ю участник 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))
Ответ 7
Я ожидаю downvote, потому что мой ответ кажется неприемлемым.
Во-первых, вам нужно проверить значение до 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]]
Ответ 8
Я думаю, что в этом случае вы можете использовать некоторые знания домена. В частности, вы получите пары [x, y]
(я рекомендую вам сделать этот кортеж (в частности, 2-кортеж, иначе известный как пара), а не массив) и [y,x]
за исключением случаев, когда x=y
где вы получаете его только один раз. Таким образом, вы можете написать простую функцию:
def unique_factors(all_factors):
[ [a,b] for [a,b] in all_factors if a <= b ]
Ответ 9
На самом деле довольно сложно получить это право в общем виде.
Это, по сути, сводится к двум основным проблемам:
- Проверка того, содержат ли два списка одни и те же элементы
- Удалите все списки, содержащие одни и те же элементы
Я займусь этим отдельно.
Проверьте, содержат ли два списка одни и те же элементы
Я лучше обратиться к 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
s:
def compare(s, t):
return set(s) == set(t)
Таким образом, вы можете проверить, содержат ли два подсписчика одни и те же элементы. Возможны оптимизации, если у вас могут быть списки разной длины, тогда было бы целесообразно добавить:
if len(s) != len(t):
return False
В начале каждой из этих функций.
Удаление дубликатов из списка
Это также зависит от предположений о результате (если не дубликаты сохраняют свой относительный порядок или нет) и содержимого (опять же, вы можете хешировать содержимое или их можно заказать).
Если элементы хешируются (или могут быть преобразованы в нечто хешируемое), вы можете использовать set
вызов для удаления дубликатов. Если вы заботитесь о заказе, вы все равно можете использовать набор, но только для поиска, например, рецепт из документации 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
Обратите внимание, что в подходах к сопоставлению внутренних списков используются наборы, словари и списки, которые не сотрясаются. Но все они могут быть преобразованы в хешируемые коллекции, такие как фризонсет или кортежи:
# 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]]
Ответ 10
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 как есть, поскольку элементы списка должны быть хешируемыми для использования set().
set([tuple(sorted(i)) for i in l])
это дает нам набор всех элементов без дубликатов. Но его набор и каждый элемент являются кортежем, но они должны быть списками.
мы можем использовать представление списка, чтобы преобразовать элементы кортежа в списки.