Функциональный метод Python для проверки равенства всех элементов в списке

Я пытаюсь найти функциональный метод, доступный в Python, который можно использовать для проверки равенства всех элементов в списке. Инстинктивно я чувствую, что это возможно.

Моя цель — создать функциональное решение для решения проблемы проверки равенства всех значений в списке.

Если вы ищете похожие вопросы на этом сайте, вы найдете как вопросы, так и ответы, написанные для Python, но ни один из них не использует функциональный подход.

Что вы подразумеваете под «функциональным методом»? То есть, что бы вы считали/не считали функциональным, чем это отличается от этого вопроса ведь он же "все равны?" задача?

Kelly Bundy 18.02.2024 17:16

На самом деле совершенно бесполезно, что комментарии были перенесены в чат, где я не могу на них отвечать. Тем, у кого раньше не было опыта работы с функциональным программированием, прочтите эту статью в Википедии, чтобы получить базовое понимание. en.wikipedia.org/wiki/Functional_programming

FreelanceConsultant 20.02.2024 10:25
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
0
3
236
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Ответ принят как подходящий

Спасибо другим за помощь в этом. Ответ TL;DR: используйте starmap.

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

  • Первый шаг — проверить, что соседние пары элементов равны, создавая новый список (фактически: итератор с возвращающим поведением), содержащий логические значения.
  • Второй шаг — проверить, верны ли все логические значения.

Кажется, это единственное очевидное функциональное решение, которое приводит к чистому коду.

input_list [1, 1, 1, 1, 1, 1, 1]

import operator
from itertools import pairwise
from itertools import starmap

def all_items_in_list_are_equal(l: list) -> bool:

    all_items_are_equal = \
        all(
            starmap(
                operator.eq,
                pairwise(l)
            )
        )

    return all_items_are_equal

Это решение:

  • ленивый оценивающий
  • требуется только operator.eq для типов, содержащихся в l
  • не требует __hash__

Он работает путем создания парного итератора pairwise(l), который возвращает пары соседних элементов в списке l в виде кортежа.

Кортеж разбивается на пары аргументов с помощью starmap. operator.eq ожидает два аргумента, поэтому один аргумент типа pair не подойдет. Мы используем starmap, чтобы применить operator.eq к каждой паре значений, возвращаемых итератором.

  • starmap значит map что func(*args) значит func(a, b, c, ...)

Наконец, all проверяет, что все элементы итерируемого объекта являются True.

Посмотреть изменения для истории

Я думаю, что это вернет True для списка типа [1, 1, 2, 2], потому что попарно (l)

Christoph 17.02.2024 22:01
pairwise производит [(1,1), (1,2), (2,2)], а не [(1,1), (2,2)].
chepner 17.02.2024 22:02

@Christoph На самом деле здесь есть еще одна проблема. Это работает только для длины 3.

FreelanceConsultant 17.02.2024 22:04

Используйте itertools.starmap вместо map. *pairwise(...)распаковывает последовательность кортежей, а не отдельные кортежи. all(starmap(operator.eq, pairwise(l))).

chepner 17.02.2024 22:05

То есть map(eq, *pairwise([1,2,3])) эквивалентно map(eq, (1,2), (2,3), (3,4)). starmap(eq, pairwise([1,2,3])) эквивалентно (игнорируя разницу между списками и произвольными итерациями) starmap(eq, [(1,2), (2,3), (3,4)]).

chepner 17.02.2024 22:10

Используя map, вам понадобится что-то вроде map(eq, l, islice(l, 1, None)) (по сути, «разархивирование» итерируемого pairwise на отдельные потоки для map для повторения. map больше похоже на zipWith в Haskell, чем просто на простую функцию отображения.)

chepner 17.02.2024 22:16

@chepner, спасибо, я подумал, что распаковка должна происходить не так, как я ожидал - есть ли способ «перевернуть» распаковку? Может быть, что-то связанное с производной zip? (На самом деле здесь просто предполагаю...)

FreelanceConsultant 17.02.2024 22:18

Вы могли бы сделать map(eq, *zip(*pairwise(l))), но это устраняет короткое замыкание, поскольку весь экземпляр pairwise (и экземпляр zip) должен быть полностью итерирован, прежде чем map сможет начать применять eq. На самом деле вы просто хотите использовать starmap, который эффективно очищает eq, чтобы вы могли извлечь из pairwise только столько кортежей, сколько all необходимо для возврата True или False.

chepner 17.02.2024 22:24

Отметим, что это также будет работать для пустых и одноэлементных списков, поскольку pairwise([]) и pairwise([x]) оба создают пустые последовательности, но all([]) в целом верно.

chepner 17.02.2024 22:29

«Наконец, all эффективно применяет лямбда-функцию для проверки истинности всех элементов». нет?

juanpa.arrivillaga 18.02.2024 02:57

@juanpa.arrivillaga Я не понял ваш комментарий, но удалил слово lambda, потому что оно, возможно, вводит в заблуждение.

FreelanceConsultant 20.02.2024 10:27

Мне это нравится

def all_elements_equal(lst):
    return all(x == lst[0] for x in lst)

Я думаю, что ОП ищет что-то, использующее только функции, а не специальный синтаксис Python. (Хотя это было бы более идиоматичное решение: Python не является строго функциональным языком.)

chepner 17.02.2024 22:08

@ Кристоф, я как раз собирался написать def all_equal( L ): return len( L ) == 0 or L.count( L[0] ) == len( L ), который, вероятно, постигла бы та же удручающая участь, что и твой совершенно хороший ответ. Итак, я снова поставил вам галочку!

lastchance 17.02.2024 22:19

@lastchance, спасибо :) приятно знать, что здесь еще есть гибкие ребята. Иногда люди относятся к этому серьезно ;)

Christoph 17.02.2024 22:25

Это решение совершенно чисто функционально. Тот факт, что он использует, казалось бы, «императивный» синтаксический сахар, не означает, что он не функционален. for здесь работает так же, как map, возвращая итератор, который лениво вычисляется. Вы могли бы написать это как all(map(lambda x: x == lst[0], lst)), и это фактически сделало бы то же самое. +1 от меня.

Luatic 18.02.2024 00:45

@chepner, хотя это глупо. понимание списков и связанные конструкции взяты прямо из таких языков, как Haskell.

juanpa.arrivillaga 18.02.2024 02:55

@Luatic, верно, только теперь это чисто функционально, сама конструкция вырвана прямо из Haskell, и никто не будет спорить, что это не функциональный язык

juanpa.arrivillaga 18.02.2024 02:57

@juanpa.arrivillaga Juanpa.arrivillaga Я никогда не говорил, что это не так, но исходный вопрос указывает на то, что ОП искал решение с использованием функций более высокого порядка.

chepner 18.02.2024 15:49

Итак, я попытался реализовать это, используя только вызовы функций и разбивая list на head|tail. Никаких библиотечных функций, никаких циклов.

def all_equal(lst):
    def ale(l, r):
        if l[1:] == []:
            return l[0] == r
        if l[0] != l[1:][0]:
            return False
        return ale(l1, l[0])

    if lst == []:
        return True
    return ale(lst, lst[0])

print(all_equal([1, 1, 1]))
print(all_equal([1, 2, 3]))

Выход:

True
False
l[1:] — это операция копирования O(n), поскольку списки Python не являются рекурсивно определяемыми структурами данных. Однако необходим только один: def ale(l, r): if not l: return True; if l[0] != r: return False; return ale(l[1:], l[0]).
chepner 18.02.2024 00:48

Меня вообще не заботила производительность, я просто имитировал строго функциональный стиль.

Yuri Ginsburg 18.02.2024 00:53

@KellyBundy Ты прав. Это должно быть во внешней функции. Спасибо.

Yuri Ginsburg 18.02.2024 05:11

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

chepner 18.02.2024 15:46

Это не функционально

FreelanceConsultant 18.02.2024 18:06

@chepner Удалены задания. if операторы существуют в Haskell, Erlang.

Yuri Ginsburg 18.02.2024 19:45

В Haskell нет операторов if. Он использует ключевое слово if для определения условного выражения, для которого требуется часть else, чтобы все выражение определялось независимо от того, истинно условие или нет.

chepner 18.02.2024 20:11

Другие вопросы по теме