Как обнаружить массив с единственным возможным значением [duplicate]

Если вы ищете решение для лицензирования, вы можете проверить API TrueLicense . Он основан на использовании асимметричных клавиш. Однако это не означает, что ваше приложение не может быть взломан. Каждое приложение может быть исправлено с достаточным усилием. Что действительно важно, поскольку Стю ответил , выяснив, насколько необходима сильная защита.

257
задан jfs 4 March 2016 в 16:59
поделиться

21 ответ

Общий метод:

def checkEqual1(iterator):
    iterator = iter(iterator)
    try:
        first = next(iterator)
    except StopIteration:
        return True
    return all(first == rest for rest in iterator)

Однострочный:

def checkEqual2(iterator):
   return len(set(iterator)) <= 1

Также однострочный:

def checkEqual3(lst):
   return lst[1:] == lst[:-1]

Разница между 3 версии:

  1. В checkEqual2 содержимое должно быть хешируемым.
  2. checkEqual1 и checkEqual2 могут использовать любые итераторы, но checkEqual3 должны принимать последовательный вход, обычно конкретные контейнеры, такие как список или кортеж.
  3. checkEqual1 останавливается, как только обнаруживается разница.
  4. Поскольку checkEqual1 содержит больше кода на Python, это меньше эффективен, когда многие из элементов равны в начале.
  5. Поскольку операции checkEqual2 и checkEqual3 всегда выполняют операции копирования O (N), они будут занимать больше времени, если большая часть вашего ввода вернет False.
  6. Для checkEqual2 и checkEqual3 сложнее адаптировать сравнение с a == b до a is b.

timeit результат для Python 2.7 и (только s1, s4, s7, s9 должны возвращать True)

s1 = [1] * 5000
s2 = [1] * 4999 + [2]
s3 = [2] + [1]*4999
s4 = [set([9])] * 5000
s5 = [set([9])] * 4999 + [set([10])]
s6 = [set([10])] + [set([9])] * 4999
s7 = [1,1]
s8 = [1,2]
s9 = []

получаем

      | checkEqual1 | checkEqual2 | checkEqual3  | checkEqualIvo | checkEqual6502 |
|-----|-------------|-------------|--------------|---------------|----------------|
| s1  | 1.19   msec | 348    usec | 183     usec | 51.6    usec  | 121     usec   |
| s2  | 1.17   msec | 376    usec | 185     usec | 50.9    usec  | 118     usec   |
| s3  | 4.17   usec | 348    usec | 120     usec | 264     usec  | 61.3    usec   |
|     |             |             |              |               |                |
| s4  | 1.73   msec |             | 182     usec | 50.5    usec  | 121     usec   |
| s5  | 1.71   msec |             | 181     usec | 50.6    usec  | 125     usec   |
| s6  | 4.29   usec |             | 122     usec | 423     usec  | 61.1    usec   |
|     |             |             |              |               |                |
| s7  | 3.1    usec | 1.4    usec | 1.24    usec | 0.932   usec  | 1.92    usec   |
| s8  | 4.07   usec | 1.54   usec | 1.28    usec | 0.997   usec  | 1.79    usec   |
| s9  | 5.91   usec | 1.25   usec | 0.749   usec | 0.407   usec  | 0.386   usec   |

Примечание:

# http://stackoverflow.com/q/3844948/
def checkEqualIvo(lst):
    return not lst or lst.count(lst[0]) == len(lst)

# http://stackoverflow.com/q/3844931/
def checkEqual6502(lst):
    return not lst or [lst[0]]*len(lst) == lst
296
ответ дан ankostis 16 August 2018 в 01:30
поделиться
  • 1
    @max: Да. Обратите внимание, что 1 мс = 1000 мкс. – kennytm 2 October 2010 в 09:28
  • 2
    Не забывайте анализировать использование памяти для очень больших массивов, собственное решение, которое оптимизирует запросы на obj.__eq__, когда lhs is rhs, и оптимизацию вне порядка, чтобы быстрее отсортировать отсортированные списки. – Glenn Maynard 2 October 2010 в 09:31
  • 3
    Ivo van der Wijk имеет лучшее решение для последовательностей, которое примерно в 5 раз быстрее, чем установлено, и O (1) в памяти. – aaronasterling 2 October 2010 в 09:32
  • 4
    @AaronMcSmooth: не критикуя этот ответ, это говорит о том, что этот ответ, вероятно, останется в четыре раза больше, чем оценка другого: не из-за сравнительной ценности, а из-за общего раннего ответа и опроса общественного голоса сайт. – Glenn Maynard 2 October 2010 в 09:57
  • 5
    @TurtlesAreCute: В чем проблема [2,3,3,3]? checkEqual3 правильно возвращает False. – kennytm 2 May 2016 в 11:25

Это еще один вариант, более быстрый, чем len(set(x))==1 для длинных списков (используется короткое замыкание)

def constantList(x):
    return x and [x[0]]*len(x) == x
9
ответ дан 6502 16 August 2018 в 01:30
поделиться
  • 1
    Это в 3 раза медленнее, чем установленное решение на моем компьютере, игнорируя короткое замыкание. Поэтому, если неравный элемент найден в среднем в первой трети списка, он быстрее в среднем. – max 2 October 2010 в 10:21

Сложная сравнительная работа:

len(set(the_list)) == 1

Использование set удаляет все повторяющиеся элементы.

26
ответ дан A-B-B 16 August 2018 в 01:30
поделиться
lambda lst: reduce(lambda a,b:(b,b==a[0] and a[1]), lst, (lst[0], True))[1]

Следующее короткое замыкание:

all(itertools.imap(lambda i:yourlist[i]==yourlist[i+1], xrange(len(yourlist)-1)))
0
ответ дан berdario 16 August 2018 в 01:30
поделиться
  • 1
    Ваш первый код, очевидно, был неправильным: reduce(lambda a,b:a==b, [2,2,2]) yields False ... Я отредактировал его, но таким образом это не совсем – berdario 27 March 2014 в 11:41
  • 2
    @berdario Затем вы должны написать свой собственный ответ, а не изменять то, что написал кто-то другой. Если вы считаете, что этот ответ был неправильным, вы можете прокомментировать его и / или уменьшить его. – Gorpik 27 March 2014 в 11:47
  • 3
    Лучше исправить что-то не так, чем оставить его там, чтобы все люди его читали, возможно, отсутствовали комментарии, объясняющие, почему это было неправильно – berdario 27 March 2014 в 14:04
  • 4
    «Когда мне следует редактировать сообщения?» «Каждый раз, когда вы чувствуете, что можете сделать сообщение лучше, и склонны это делать. Редактирование рекомендуется! & Quot; – berdario 27 March 2014 в 14:06

Вы можете преобразовать список в набор. У набора не может быть дубликатов. Поэтому, если все элементы в исходном списке идентичны, набор будет иметь только один элемент.

if len(sets.Set(input_list)) == 1
// input_list has all identical elements.
22
ответ дан codaddict 16 August 2018 в 01:30
поделиться
  • 1
    это хорошо, но это не короткое замыкание, и вам нужно рассчитать длину результирующего списка. – aaronasterling 2 October 2010 в 08:44
  • 2
    почему не просто len(set(input_list)) == 1? – Nick Dandoulakis 2 October 2010 в 08:50
  • 3
    @codaddict. Это означает, что даже если первые два элемента отличаются друг от друга, он все равно завершит весь поиск. он также использует O (k) дополнительное пространство, где k - количество отдельных элементов в списке. – aaronasterling 2 October 2010 в 08:58
  • 4
    @Максимум. потому что построение набора происходит на C, и у вас плохая реализация. Вы должны хотя бы сделать это в выражении генератора. См. Ответ KennyTM о том, как сделать это правильно, не используя набор. – aaronasterling 2 October 2010 в 09:20
  • 5
    sets.Set is "Устаревший со версии 2.6: встроенные типы set / frozenset заменяют этот модуль. & quot; (из docs.python.org/2/library/sets.html ) – Moberg 19 January 2017 в 23:23

Убедитесь, что все элементы равны первому.

np.allclose(array, array[0])

2
ответ дан Gusev Slava 16 August 2018 в 01:30
поделиться
def allTheSame(i):
    j = itertools.groupby(i)
    for k in j: break
    for k in j: return False
    return True

Работает в Python 2.4, который не имеет «все».

1
ответ дан itertool 16 August 2018 в 01:30
поделиться
  • 1
    for k in j: break эквивалентно next(j). Вы также могли бы сделать def allTheSame(x): return len(list(itertools.groupby(x))<2), если бы не заботились об эффективности. – ninjagecko 23 April 2012 в 18:06

Решение быстрее, чем использование set (), которое работает с последовательностями (а не итерами), состоит в простом подсчете первого элемента. Это предполагает, что список не пуст (но это тривиально проверить и решить, какой результат должен быть в пустом списке)

x.count(x[0]) == len(x)

несколько простых эталонных тестов:

>>> timeit.timeit('len(set(s1))<=1', 's1=[1]*5000', number=10000)
1.4383411407470703
>>> timeit.timeit('len(set(s1))<=1', 's1=[1]*4999+[2]', number=10000)
1.4765670299530029
>>> timeit.timeit('s1.count(s1[0])==len(s1)', 's1=[1]*5000', number=10000)
0.26274609565734863
>>> timeit.timeit('s1.count(s1[0])==len(s1)', 's1=[1]*4999+[2]', number=10000)
0.25654196739196777
225
ответ дан Ivo van der Wijk 16 August 2018 в 01:30
поделиться
  • 1
    OMG, это в 6 раз быстрее, чем установленное решение! (280 миллионов элементов / сек против 45 миллионов элементов в секунду на моем ноутбуке). Зачем??? И есть ли способ изменить его так, чтобы он замыкал цепи (я думаю, нет ...) – max 2 October 2010 в 10:18
  • 2
    Я думаю, что list.count имеет сильно оптимизированную реализацию C, а длина списка хранится внутри, поэтому len () также дешево. Не существует способа подсчета коротких замыканий (), поскольку вам нужно будет действительно проверить все элементы, чтобы получить правильный счет. – Ivo van der Wijk 2 October 2010 в 11:01
  • 3
    Могу ли я изменить его на: x.count(next(x)) == len(x), чтобы он работал для любого контейнера x? Ahh .. nm, просто увидел, что .count доступен только для последовательностей. Почему он не реализован для других встроенных контейнеров? Является ли подсчет внутри словаря менее значимым, чем внутри списка? – max 5 October 2010 в 06:09
  • 4
    Итератор может не иметь длины. Например. он может быть бесконечным или просто динамически генерироваться. Вы можете найти его длину, переведя его в список, который убирает большинство преимуществ итераторов – Ivo van der Wijk 5 October 2010 в 06:51
  • 5
    Извините, я имел в виду, почему count не реализован для iterables, а не почему len недоступен для итераторов. Ответ, вероятно, в том, что это просто недосмотр. Но для нас это непоправимо, потому что по умолчанию .count() для последовательностей очень медленный (чистый python). Причина, по которой ваше решение так быстро, заключается в том, что он полагается на C-реализованный count, предоставленный list. Поэтому я предполагаю, что какой-либо истребимый метод реализации count в C будет полезен вашему подходу. – max 12 March 2016 в 04:36

Это простой способ сделать это:

result = mylist and all(mylist[0] == elem for elem in mylist)

Это немного сложнее, оно навлекает служебные вызовы функций, но семантика более четко прописана:

def all_identical(seq):
    if not seq:
        # empty list is False.
        return False
    first = seq[0]
    return all(first == elem for elem in seq)
4
ответ дан Jerub 16 August 2018 в 01:30
поделиться
  • 1
    Вы можете избежать избыточного сравнения здесь, используя for elem in mylist[1:]. Сомнительно, что он значительно улучшает скорость, поскольку, как я полагаю, elem[0] is elem[0], переводчик, вероятно, может сделать это сравнение очень быстро. – Brendan 5 January 2017 в 16:58

Если вам интересно что-то более читаемое (но, конечно, не так эффективно), вы можете попробовать:

def compare_lists(list1, list2):
    if len(list1) != len(list2): # Weed out unequal length lists.
        return False
    for item in list1:
        if item not in list2:
            return False
    return True

a_list_1 = ['apple', 'orange', 'grape', 'pear']
a_list_2 = ['pear', 'orange', 'grape', 'apple']

b_list_1 = ['apple', 'orange', 'grape', 'pear']
b_list_2 = ['apple', 'orange', 'banana', 'pear']

c_list_1 = ['apple', 'orange', 'grape']
c_list_2 = ['grape', 'orange']

print compare_lists(a_list_1, a_list_2) # Returns True
print compare_lists(b_list_1, b_list_2) # Returns False
print compare_lists(c_list_1, c_list_2) # Returns False
2
ответ дан Joshua Burns 16 August 2018 в 01:30
поделиться
  • 1
    Я на самом деле пытаюсь проверить, идентичны ли все элементы в одном списке; если два отдельных списка идентичны. – max 5 June 2012 в 23:22

Преобразуйте список в набор, а затем найдите количество элементов в наборе. Если результат равен 1, он имеет одинаковые элементы, а если нет, то элементы в списке не идентичны.

list1 = [1,1,1]
len(set(list1)) 
>1

list1 = [1,2,3]
len(set(list1)
>3
2
ответ дан Kanmani 16 August 2018 в 01:30
поделиться

Измените список на набор. Тогда, если размер набора равен только 1, они должны быть одинаковыми.

if len(set(my_list)) == 1:
0
ответ дан Lumo5 16 August 2018 в 01:30
поделиться

Сомневаюсь, что это «самый Pythonic», но что-то вроде:

>>> falseList = [1,2,3,4]
>>> trueList = [1, 1, 1]
>>> 
>>> def testList(list):
...   for item in list[1:]:
...     if item != list[0]:
...       return False
...   return True
... 
>>> testList(falseList)
False
>>> testList(trueList)
True

выполнит трюк.

3
ответ дан machineghost 16 August 2018 в 01:30
поделиться
  • 1
    Ваш цикл for можно сделать более Pythonic в if any(item != list[0] for item in list[1:]): return False с точно такой же семантикой. – musiphil 18 August 2016 в 20:59

Относительно использования reduce() с lambda. Вот рабочий код, который, как мне кажется, лучше, чем некоторые другие ответы.

reduce(lambda x, y: (x[1]==y, y), [2, 2, 2], (True, 2))

Возвращает кортеж, где первое значение является логическим, если все элементы одинаковы или нет.

2
ответ дан Marcus Lind 16 August 2018 в 01:30
поделиться

Для чего это стоит, это появилось недавно в списке рассылки python-идей . Оказалось, что для этого уже существует рецепт itertools : 1

def all_equal(iterable):
    "Returns True if all the elements are equal to each other"
    g = groupby(iterable)
    return next(g, True) and not next(g, False)

Предположительно, он работает очень хорошо и имеет несколько приятных свойств.

  1. Короткие замыкания: он перестанет потреблять элементы из итерации, как только найдет первый неравный элемент.
  2. Не требует, чтобы элементы были хешируемыми.
  3. ] Он ленив и требует только O (1) дополнительной памяти для проверки.

1Иными словами, я не могу взять кредит на то, чтобы придумать решение - и не может Я признаю, что даже нашел это.

10
ответ дан mgilson 16 August 2018 в 01:30
поделиться
  • 1
    Гораздо быстрее, чем самый быстрый ответ, указанный здесь здесь в худшем случае. – ChaimG 29 April 2018 в 23:32

Самый простой и элегантный способ заключается в следующем:

all(x==myList[0] for x in myList)

(Да, это даже работает с нулевым списком! Это потому, что это один из немногих случаев, когда python имеет ленивую семантику. )

Что касается производительности, это произойдет как можно скорее, поэтому оно асимптотически оптимально.

98
ответ дан michaelsnowden 16 August 2018 в 01:30
поделиться
  • 1
    Это работает, но немного (1.5x) медленнее, чем @KennyTM checkEqual1. Я не знаю, почему. – max 24 April 2012 в 18:20
  • 2
    max: Вероятно, потому что я не потрудился выполнить оптимизацию first=myList[0] all(x==first for x in myList), возможно – ninjagecko 17 November 2015 в 13:48
  • 3
    Я думаю, что myList [0] оценивается с каждой итерацией. & GT; & GT; & GT; timeit.timeit ('all ([y == x [0] для y в x])', 'x = [1] * 4000', number = 10000) 2.707076672740641 & gt; & gt; & gt; timeit.timeit ('x0 = x [0]; all ([y == x0 для y в x])', 'x = [1] * 4000', number = 10000) 2.0908854261426484 – Matt Liberty 11 January 2016 в 22:35
  • 4
    Я должен, конечно, уточнить, что оптимизация first=myList[0] будет вызывать IndexError в пустом списке, поэтому комментаторы, которые говорили об этой оптимизации, о которой я упоминал, будут иметь дело с краем случайного списка. Однако оригинал прекрасен (x==myList[0] в пределах all, потому что он никогда не оценивается, если список пуст). – ninjagecko 13 January 2016 в 11:45
  • 5
    Это, безусловно, правильный путь. Если вы хотите скорость в каждом случае, используйте что-то вроде numpy. – Henry Gomersall 6 May 2016 в 16:14

Вы можете сделать:

reduce(and_, (x==yourList[0] for x in yourList), True)

Довольно раздражает, что python заставляет вас импортировать такие операторы, как operator.and_. Начиная с python3, вам также нужно будет импортировать functools.reduce.

(Вы не должны использовать этот метод, потому что он не сломается, если он найдет не равные значения, но продолжит изучение всего списка. просто включается здесь в качестве ответа для полноты.)

0
ответ дан ninjagecko 16 August 2018 в 01:30
поделиться
  • 1
    Это не будет короткое замыкание. Почему вы предпочитаете это по другому решению? – max 24 April 2012 в 18:18
  • 2
    @max: вы не хотели бы именно по этой причине; Я включил его для полноты. Я должен, вероятно, отредактировать его, чтобы упомянуть об этом, спасибо. – ninjagecko 24 April 2012 в 18:39
>>> a = [1, 2, 3, 4, 5, 6]
>>> z = [(a[x], a[x+1]) for x in range(0, len(a)-1)]
>>> z
[(1, 2), (2, 3), (3, 4), (4, 5), (5, 6)]
# Replacing it with the test
>>> z = [(a[x] == a[x+1]) for x in range(0, len(a)-1)]
>>> z
[False, False, False, False, False]
>>> if False in z : Print "All elements are not equal"
1
ответ дан pyfunc 16 August 2018 в 01:30
поделиться

Я бы сделал:

not any((x[i] != x[i+1] for i in range(0, len(x)-1)))

as any перестает искать итерацию, как только обнаруживает условие True.

2
ответ дан Robert Rossney 16 August 2018 в 01:30
поделиться
  • 1
    Вам не нужны дополнительные скобки вокруг выражения генератора, если это единственный аргумент. – ninjagecko 23 April 2012 в 18:02
  • 2
    также all(), почему бы не использовать all(x == seq[0] for x in seq)? выглядит более pythonic и должен выполнять то же самое – Chen A. 4 September 2017 в 07:36

Вот два простых способа сделать это

, используя set ()

. При преобразовании списка в набор удаляются повторяющиеся элементы. Поэтому, если длина преобразованного набора равна 1, это означает, что все элементы одинаковы.

len(set(input_list))==1

Вот пример

>>> a = ['not', 'the', 'same']
>>> b = ['same', 'same', 'same']
>>> len(set(a))==1  # == 3
False
>>> len(set(b))==1  # == 1
True

, используя all ()

Это будет сравнивать (эквивалентность) первый элемент списка ввода со всеми остальными элементами в списке. Если все эквиваленты True будут возвращены, в противном случае возвращается False.

all(element==input_list[0] for element in input_list)

Вот пример

>>> a = [1, 2, 3, 4, 5]
>>> b = [1, 1, 1, 1, 1]
>>> all(number==a[0] for number in a)
False
>>> all(number==b[0] for number in b)
True

PS Если вы проверяете, соответствует ли весь список определенному значение, вы можете suibstitue значение in для input_list [0].

1
ответ дан symphy 16 August 2018 в 01:30
поделиться

Можно использовать карту и лямбда

lst = [1,1,1,1,1,1,1,1,1]

print all(map(lambda x: x == lst[0], lst[1:]))
1
ответ дан Vikram S 16 August 2018 в 01:30
поделиться
Другие вопросы по тегам:

Похожие вопросы: