Уникальные списки в списке списков, если в этих списках есть список в качестве одного из элементов.

Если у меня есть:

l = [['98765', ['Einstein, A', 'SFEN'], 'SSW 540', 3], ['98765', ['Einstein, A', 'SFEN'], 'SSW 540', 3],
     ['98764', ['Feynman, R', 'SFEN'], 'SSW 564', 3], ['98764', ['Feynman, R', 'SFEN'], 'SSW 564', 3]]

Как лучше всего получить:

k = [['98765', 'Einstein, A', 'SFEN', 'SSW 540', 3], ['98764', 'Feynman, R', 'SFEN', 'SSW 564', 3]]

Если я попытаюсь:

uniqinstruct = set(map(tuple, l))

Я получаю TypeError: unhashable type: 'list'. Я не хочу удалять все слои вложенности, потому что это просто объединит все в один список:

output = []

def reemovNestings(l):
    for i in l:
        if type(i) == list:
            reemovNestings(i)
        else:
            output.append(i)

reemovNestings(l)
print(sorted(set(output), key=output.index))

Выход:

['98765', 'Einstein, A', 'SFEN', 'SSW 540', 3, '98764', 'Feynman, R', 'SSW 564']

Если у двух инструкторов одинаковое количество (в данном случае 3), то остается только одна 3, потому что это set, и я не могу сгруппировать элементы списка через каждые x интервалов. Что было бы хорошим способом сохранить это последнее значение?


person Jim T    schedule 20.11.2020    source источник
comment
Можем ли мы объединить эти списки с одинаковыми номерами, например "98765" или "98764"?   -  person jizhihaoSAMA    schedule 20.11.2020
comment
stackoverflow.com/questions/952914/ помочь?   -  person Karl Knechtel    schedule 20.11.2020
comment
@jizhihaoSAMA Этот номер является уникальным идентификатором, но может повторяться, если инструктор преподает несколько курсов (с разными названиями курсов и количеством), поэтому было бы нецелесообразно объединять   -  person Jim T    schedule 20.11.2020
comment
@KarlKnechtel Похоже, flatten из django, а затем сбор по каждым 5 элементам тоже может работать   -  person Jim T    schedule 20.11.2020


Ответы (4)


Учитывая, что вы знаете, какой слой вы хотите развернуть, вы можете просто выполнить итерацию по этому слою. В вашем конкретном примере это второй слой:

res = []
for inner_list in l:
    inner = []
    for el in inner_list:
        if type(el) == list:
            inner.extend(el)
        else:
            inner.append(el)
    if not (inner in res):
        res.append(inner)

Обратите внимание, что list.extend добавляет в список несколько значений.

if not (inner in res): res.append(inner) дает вам уникальные предметы в верхнем слое. Спасибо @dmitryro за подсказку.

person Muslimbek Abduganiev    schedule 20.11.2020
comment
вы, вероятно, захотите проверить if not (inner in res): res.append(inner), так как его интересуют только неповторяющиеся элементы. - person dmitryro; 20.11.2020
comment
Да, вы правы. Там я ослеп и осознал необходимость неповторяющихся элементов после того, как закончил код. Обновил ответ. - person Muslimbek Abduganiev; 20.11.2020

используйте itertools.groupby, чтобы разделить их, и сгладьте их с помощью понимания списка. Чтобы обеспечить порядок в списке, вы можете использовать dict.fromkeys().

Если вы не возражаете против этого слишком длинного понимания списка:

from itertools import groupby

l = [['98765', ['Einstein, A', 'SFEN'], 'SSW 540', 3], ['98765', ['Einstein, A', 'SFEN'], 'SSW 540', 3],
     ['98764', ['Feynman, R', 'SFEN'], 'SSW 564', 3], ['98764', ['Feynman, R', 'SFEN'], 'SSW 564', 3]]

s = [list(dict.fromkeys(e for i in item for j in i for e in (j if type(j) is list else [j])).keys()) for _, item in groupby(l)]
print(s)

Результат:

[['98765', 'Einstein, A', 'SFEN', 'SSW 540', 3], ['98764', 'Feynman, R', 'SFEN', 'SSW 564', 3]]
person jizhihaoSAMA    schedule 20.11.2020
comment
Словарь Python 3.6 + сохранит порядок вставки. - person jizhihaoSAMA; 20.11.2020

Используйте Numpy.unique с плоским списком.

np.unique(flattened, axis=0)

person Canasta    schedule 20.11.2020
comment
Изменить print(sorted(set(output), key=output.index)) на print(np.unique(output, axis=0)) - person Canasta; 20.11.2020

Вот еще одно возможное решение.

Во-первых, сгладьте исходный список:

def flatten(s):
    if s == []:
        return s
    if isinstance(s[0], list):
        return flatten(s[0]) + flatten(s[1:])
    return s[:1] + flatten(s[1:])

Ваш исходный ввод:

l = [['98765', ['Einstein, A', 'SFEN'], 'SSW 540', 3], 
     ['98765', ['Einstein, A', 'SFEN'], 'SSW 540', 3],
     ['98764', ['Feynman, R', 'SFEN'], 'SSW 564', 3], 
     ['98764', ['Feynman, R', 'SFEN'], 'SSW 564', 3]]

Теперь давайте сгладим и повторим его.

final = [] # the resulting list

items = flatten(l) # first flatten the input

# take every 5 elements and add them to the final list, if not there yet.
for i in range(0, len(items), 5):
    if not (items[i:i+5] in final):
        final.append(items[i:i+5])

#let's print [['98765', 'Einstein, A', 'SFEN', 'SSW 540', 3], 
              ['98764', 'Feynman, R', 'SFEN', 'SSW 564', 3]]
print(final) 
person dmitryro    schedule 20.11.2020