Как исправить проблему с функцией, которая должна перемещать только 0 в конец списка, но также перемещает значения False?

Я пишу функцию для перемещения 0 в конец списка, но когда значение False находится в списке, оно преобразует его в 0 и также перемещает в конец.

Я пробовал много вариантов операторов if, включая:

  1. если я == 0

  2. если type(i) != bool и i == 0

  3. если ул(я) == '0'

def move_zeros(array):
    for i in array:
        if str(i) == '0' and str(i) != 'False':
            array.remove(i)
            array.append(0)
    return array

В случае [0,1,None,2,False,1,0] я ожидал, что функция вернет [1,None,2,False,1,0,0], но вместо этого она вернула [1,None,2,1,0,0,0].

Почему в 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 может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
2
0
48
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

У вас есть две проблемы здесь. Во-первых, в Python bool является подклассом int и False == 0, поэтому, чтобы отличить 0 от False, вам нужно проверить тип вашего объекта. Кроме того, изменение списка на месте во время его повторения является верным рецептом для ошибок «выключения».

Вот простая глупая простая реализация, которая работает:

def move_zeros(seq):
    head, tail = [], []
    for v in seq:
        if isinstance(v, int) and not isinstance(v, bool) and v == 0:
            tail.append(v)
        else:
            head.append(v)
    return head + tail

Спасибо, я также добавил или isinstance(v,float) для возможных значений 0.0

hubvoy 27.05.2019 14:45

рад, что смог помочь - и тогда не стесняйтесь голосовать за мой ответ. Вы также можете проголосовать и принять ответ Лепорелло, который точнее моего.

bruno desthuilliers 27.05.2019 14:48

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

hubvoy 27.05.2019 14:51

@hubvoy спасибо за нас обоих 8-) - и, пожалуйста, не забудьте ответ принимать leporello, который заслуживает того, чтобы быть отмеченным здесь как единственный правильный ответ (помните, что SO предназначен для создания базы технических знаний, поэтому принятие лучшего решения важно для будущие читатели).

bruno desthuilliers 27.05.2019 15:48

хорошо, принять ответ - это просто поставить галочку под счетчиком голосов, верно?

hubvoy 27.05.2019 16:08
Ответ принят как подходящий

Здесь есть пара подводных камней. Один из них, который вы уже поняли, заключается в том, что не существует тривиального способа различать 0 и False. Однако есть еще два момента:

  1. Изменение итерируемого объекта (списка, словаря и т. д.), который вы повторяете, опасно. Вам следует избегать этого (если только вы не можете поступить иначе, например, с очень большими объемами данных, которые вы не можете себе позволить копировать в память).
  2. array.remove() делает не то, что вы думаете. Это удаляет из array первый элемент, который является == своим аргументом, который может быть или не быть в той же позиции, что и элемент в итерационном цикле. Это отвечает за превращение вашего False в 0.

Имея это в виду, вот рабочая версия:

def is_integer_zero(x):
    # The cleanest way I found, but you could argue for other options
    return x == 0 and not isinstance(x, bool)

def move_zeros(array):
    left_part = []
    right_part = []

    for i in array:
        if is_integer_zero(i):
            right_part.append(i)
        else:
            left_part.append(i)

    return left_part + right_part


l = [0, 1, None, 2, False, 1, 0]

print(move_zeros(l))  # [1, None, 2, False, 1, 0, 0]

right_part полностью состоит из нулей, так что вы могли бы немного упростить код/улучшить производительность, но у этой версии есть то преимущество, что вы можете использовать другие условия, чтобы выбрать, что сдвигать вправо.

если вы хотите сделать его более общим, рассмотрите возможность передачи функции предиката (здесь is_integer_zero) в качестве обратного вызова. Совершенно очевидно, что для проблемы ОП, но поскольку вы упомянули «использование других условий»... ;-)

bruno desthuilliers 27.05.2019 15:50

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