Я столкнулся с вопросом Python - Удаление дубликатов в list только с помощью фильтра и лямбда, где OP спрашивает, как удалить повторяющиеся элементы из списка Python, используя исключительно функции filter и lambda.

Это заставило меня задуматься, возможно ли с теоретической точки зрения удалить дубликаты из списка Python, используя только функции lambda?

Если да, то как мы можем это сделать?

В этом случае «удаление дубликатов» означает «сохранение ровно одного вхождения каждого элемента, присутствующего в исходном списке», поэтому [1,2,1,3,1,4] должен стать [1,2,3,4].

Кроме того, цель состоит в том, чтобы написать только один lambda, поэтому код будет однострочным, например:

lambda l: """do something that returns l without duplicates"""

Использование внешних переменных запрещено.

Кроме того, что касается вышеуказанного вопроса, ничего "необычного" не допускается, особенно функция set, а также reduce, map ...

По сути, никакие другие функции, даже встроенные, вызывать не следует.

1
Right leg 7 Янв 2017 в 20:08
Только лямбда-функции и никаких временных заполнителей / контейнеров?
 – 
wwii
7 Янв 2017 в 20:16
Отредактировал мой вопрос; да, код должен состоять исключительно из одной лямбда-функции, поэтому дополнительный контейнер не допускается.
 – 
Right leg
7 Янв 2017 в 20:20
Иногда это немного сложно, но обычно вы можете найти способ написать лямбда -версию функции, независимо от того, насколько она запутана или нечитабельна.
 – 
wwii
7 Янв 2017 в 20:21
Проверьте мой ответ, чтобы увидеть, насколько он грязный :)
 – 
Right leg
7 Янв 2017 в 20:22
lambda a: list(set(a)) ??
 – 
wwii
7 Янв 2017 в 20:31

1 ответ

Лучший ответ

С теоретической точки зрения, если вычислительная проблема требует ввода и вывода без побочных эффектов, лямбда-исчисление, вероятно, может решить ее (в более общем плане лямбда-исчисление является полным по Тьюрингу, cf wikipedia).

Теперь для реализации следующая функция lambda принимает аргумент списка и возвращает список, в котором все дубликаты были удалены:

lambda l: (lambda u, a: u(u, a)) ((lambda f, x: x if len(x) <= 0 else (f(f, x[1:]) if x[0] in x[1:] else ([x[0]] + f(f, x[1:])))), l)

Вот развернутая версия:

lambda l:
    (lambda u, a: u(u, a))
    (
        (lambda f, x: x if len(x) <= 0
                        else
                        (
                            f(f, x[1:]) if x[0] in x[1:]
                                        else ([x[0]] + f(f, x[1:]))
                        )
         ),
         l
    )

Функция состоит из lambda версии следующей рекурсивной функции:

def f(l):
    if len(l) <= 0:
        return l
    elif l[0] in l[1:]:
        return f(l[1:])
    else:
        return ([l[0]] + f(l[1:]))

Чтобы имитировать рекурсивный вызов, эквивалент lambda принимает дополнительную функцию в качестве аргумента, которая будет самой собой:

lambda f, x: x if len(x) <= 0
               else
               (
                   f(f, x[1:]) if x[0] in x[1:]
                               else ([x[0]] + f(f, x[1:]))
               )

Затем другой lambda вызывает эту предыдущую функцию, передавая себя в качестве аргумента (помимо списка):

lambda u, a: u(u, a)

Наконец, внешний lambda завершает все, что принимает только список в качестве аргумента.

4
Right leg 7 Янв 2017 в 20:41
1
Аккуратный. Почему-то на ум приходит десятое правило Гринспана ;-)
 – 
snakecharmerb
7 Янв 2017 в 20:47
1
Действительно, за исключением того, что в этом случае C / Fortran - это Python, а Common Lisp - это Python :)
 – 
Right leg
7 Янв 2017 в 20:53