Я пытаюсь найти функциональный метод, доступный в Python, который можно использовать для проверки равенства всех элементов в списке. Инстинктивно я чувствую, что это возможно.
Моя цель — создать функциональное решение для решения проблемы проверки равенства всех значений в списке.
Если вы ищете похожие вопросы на этом сайте, вы найдете как вопросы, так и ответы, написанные для Python, но ни один из них не использует функциональный подход.
Что вы подразумеваете под «функциональным методом»? То есть, что бы вы считали/не считали функциональным, чем это отличается от этого вопроса ведь он же "все равны?" задача?
На самом деле совершенно бесполезно, что комментарии были перенесены в чат, где я не могу на них отвечать. Тем, у кого раньше не было опыта работы с функциональным программированием, прочтите эту статью в Википедии, чтобы получить базовое понимание. en.wikipedia.org/wiki/Functional_programming






Спасибо другим за помощь в этом. Ответ 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)
pairwise производит [(1,1), (1,2), (2,2)], а не [(1,1), (2,2)].
@Christoph На самом деле здесь есть еще одна проблема. Это работает только для длины 3.
Используйте itertools.starmap вместо map. *pairwise(...)распаковывает последовательность кортежей, а не отдельные кортежи. all(starmap(operator.eq, pairwise(l))).
То есть 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)]).
Используя map, вам понадобится что-то вроде map(eq, l, islice(l, 1, None)) (по сути, «разархивирование» итерируемого pairwise на отдельные потоки для map для повторения. map больше похоже на zipWith в Haskell, чем просто на простую функцию отображения.)
@chepner, спасибо, я подумал, что распаковка должна происходить не так, как я ожидал - есть ли способ «перевернуть» распаковку? Может быть, что-то связанное с производной zip? (На самом деле здесь просто предполагаю...)
Вы могли бы сделать map(eq, *zip(*pairwise(l))), но это устраняет короткое замыкание, поскольку весь экземпляр pairwise (и экземпляр zip) должен быть полностью итерирован, прежде чем map сможет начать применять eq. На самом деле вы просто хотите использовать starmap, который эффективно очищает eq, чтобы вы могли извлечь из pairwise только столько кортежей, сколько all необходимо для возврата True или False.
Отметим, что это также будет работать для пустых и одноэлементных списков, поскольку pairwise([]) и pairwise([x]) оба создают пустые последовательности, но all([]) в целом верно.
«Наконец, all эффективно применяет лямбда-функцию для проверки истинности всех элементов». нет?
@juanpa.arrivillaga Я не понял ваш комментарий, но удалил слово lambda, потому что оно, возможно, вводит в заблуждение.
Мне это нравится
def all_elements_equal(lst):
return all(x == lst[0] for x in lst)
Я думаю, что ОП ищет что-то, использующее только функции, а не специальный синтаксис Python. (Хотя это было бы более идиоматичное решение: Python не является строго функциональным языком.)
@ Кристоф, я как раз собирался написать def all_equal( L ): return len( L ) == 0 or L.count( L[0] ) == len( L ), который, вероятно, постигла бы та же удручающая участь, что и твой совершенно хороший ответ. Итак, я снова поставил вам галочку!
@lastchance, спасибо :) приятно знать, что здесь еще есть гибкие ребята. Иногда люди относятся к этому серьезно ;)
Это решение совершенно чисто функционально. Тот факт, что он использует, казалось бы, «императивный» синтаксический сахар, не означает, что он не функционален. for здесь работает так же, как map, возвращая итератор, который лениво вычисляется. Вы могли бы написать это как all(map(lambda x: x == lst[0], lst)), и это фактически сделало бы то же самое. +1 от меня.
@chepner, хотя это глупо. понимание списков и связанные конструкции взяты прямо из таких языков, как Haskell.
@Luatic, верно, только теперь это чисто функционально, сама конструкция вырвана прямо из Haskell, и никто не будет спорить, что это не функциональный язык
@juanpa.arrivillaga Juanpa.arrivillaga Я никогда не говорил, что это не так, но исходный вопрос указывает на то, что ОП искал решение с использованием функций более высокого порядка.
Итак, я попытался реализовать это, используя только вызовы функций и разбивая 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]).
Меня вообще не заботила производительность, я просто имитировал строго функциональный стиль.
@KellyBundy Ты прав. Это должно быть во внешней функции. Спасибо.
Если у вас есть утверждения и задания, это не строго функциональный стиль.
Это не функционально
@chepner Удалены задания. if операторы существуют в Haskell, Erlang.
В Haskell нет операторов if. Он использует ключевое слово if для определения условного выражения, для которого требуется часть else, чтобы все выражение определялось независимо от того, истинно условие или нет.
Комментарии перенесены в чат ; пожалуйста, не продолжайте обсуждение здесь. Прежде чем оставлять комментарий под этим, пожалуйста, ознакомьтесь с целями комментариев . Комментарии, которые не требуют разъяснений или предложений по улучшению, обычно размещаются в виде ответа , в Meta Stack Overflow или в Stack Overflow Chat. Комментарии продолжения обсуждения могут быть удалены.