Изменение последовательности внутри цикла for, мощность Си-шного for в python

Здравствуйте. Пишу калькулятор на python. Имеется список с операторами ['+', '*'], которые я перебираю:
for cur_op_num in range(len(opers)):
    cur_op = opers[cur_op_num]
Дело в том, что по алгоритму нужно удалить оператор после выполнения и продолжить с этого же индекса, но, насколько я знаю, в python нет мощности цикла for из Си... На Си это было бы примерно так:
for (int cur_op_num=0;cur_op_num<len(opers); cur_op_num++)
{
    if (some_condition) //Если нужно удалить оператор
        {
            //Удаляем и уменьшаем текущий индекс чтобы после итерации он сохранил своё значение
            opers.RemoveAt(cur_op_num);
            cur_op_num--;
        }
}
А как мне сделать такое же на python, если заранее неизвестно, какие индексы будут удаляться? Вынести range(len(opers)) в отдельную переменную и править эту последовательность? Использовать while и самому контролировать выход...? Как это лучше сделать? Заранее спасибо.
6 ответов

А так не подойдет?
>>> sequence = ['one', 'two', 'three', 'four']
>>> for item in sequence[:]:
...     if input('Delete item {} [Y/N]? '.format(item)) in 'yY':
...             sequence.remove(item)
... 
Delete item one [Y/N]? n
Delete item two [Y/N]? y
Delete item three [Y/N]? n
Delete item four [Y/N]? n
>>> sequence
['one', 'three', 'four']
>>>
Приведи минимальный работающий пример на С.


#include <iostream>
using namespace std;
 
int * DelInd (int * arr, int len, int ind)
{
    // Удаляем индекс путём создания нового массива (указателя на область с кучей int) длиной len - 1
    // И копированием туда всего, кроме ind-ого элемента.
    len--;
    int * new_arr = new int[len];
    for (int i = 0; i < ind; i++)
    {
        new_arr[i] = arr[i];
    }
    for (int i = ind; i < len; i++)
    {
        new_arr[i] = arr[i + 1];
    }
    //Удаляем старый массив.
    delete arr;
    return new_arr;
}
 
int GetMin(int * arr, int len)
{
    int min = arr[0];
    for (int i = 1; i < len; i++)
    {
        if (arr[i] < min)
            min = arr[i];
    }
    return min;
}
 
 
int GetMax(int * arr, int len)
{
    int max = arr[0];
    for (int i = 1; i < len; i++)
    {
        if (arr[i] > max)
            max = arr[i];
    }
    return max;
}
 
void main()
{
    //Массив операторов
    int op_pr_len = 3;
    int * opers = new int [op_pr_len];
    //Массив приортитетов
    //Приоритеты мало связаны с операторами, т.е. у одного '+' может быть приоритет 1, а у другого 0 (приоритеты меняются скобками).
    int *priors = new int [op_pr_len];
    //Массив чисел
    int digs_len = 4;
    int * digs = new int[digs_len];
 
    //Заполняем их
    opers[0] = '*'; //Приоритет по-умолчанию 0
    opers[1] = '+'; //Приоритет по-умолчанию 1
    opers[2] = '-'; //Приоритет по-умолчанию 1
 
    priors[0] = 0; //Приоритет у '*' по-умолчанию 0, значит скобок нет.
    priors[1] = 1; //Приоритет у '-' по-умолчанию 1, значит скобок нет.
    priors[2] = 0; //Приоритет у '+' по-умолчанию 1, а здесь 0, значит есть ОДНА пара скобок (1-0).
 
    digs[0] = 10;
    digs[1] = 5;
    digs[2] = 7;
    digs[3] = 3;
    //Т.е. исходное выражение: 10 * 5 + (7 - 3), ответ должен быть равен 54
 
    int pr_min = GetMin(priors, op_pr_len);
    int pr_max = GetMax(priors, op_pr_len);
 
    //Перебираем операторы
    for (int i_op = 0; i_op < op_pr_len; i_op++)
    {
        //Перебираем все приоритеты
        for (int i_pr = pr_min; i_pr <= pr_max; i_pr++)
        {
            // И вычисляем сначала все операторы с наименьшим приоритетом, постепенно повышая приоритет в i_pr.
            // Если приоритет текущего оператора равен тому приоритету, который мы сейчас обрабатываем, то вычисляем его.
            if (priors[i_op] == i_pr)
            {
                int res = 0;
                //Выполняем нужную операцию над i-ым и (i+1)-ым числом
                switch (opers[i_op])
                {
                    case '+':
                        res = digs[i_op] + digs[i_op+1];
                        break;
                    case '-':
                        res = digs[i_op] - digs[i_op+1];
                        break;
                    case '*':
                        res = digs[i_op] * digs[i_op+1];
                        break;
                }
                //Кладём ответ на место первого числа
                digs[i_op] = res;
                //Удаляем второе число
                int * new_arr = DelInd(digs, digs_len, i_op + 1);
                digs_len--;
                digs = new_arr;
 
                //Удаляем текущий i-ый оператор
                new_arr = DelInd(opers, op_pr_len, i_op);
                opers = new_arr;
 
                //Удаляем текущий i-ый приоритет
                new_arr = DelInd(priors, op_pr_len, i_op);
                priors = new_arr;
 
                op_pr_len--;
 
                //Раз что-то вычисляли - Возвращаем назад
                i_op--;
            }
        }
    }
 
           //Ответ остаётся в digs[0], остальные массивы должны быть пусты.
    cout << "Answer is " << digs[0] << endl;
 
    delete digs;
    delete opers;
 
    system("pause");
}
Извините за плохо-код... Подзабыл C++... Проверено на MS VC++ 2010. Видите, если было вычисление, то удаляем текущие оператор и приоритет, а также второе число И ОСТАЁМСЯ с этим же i_op, на этой же итерации.На Python у меня пока что-то типа этого, но не работает...
def CalculateParsed(parsed):
    """"Вычисление выражения в разобранном виде."""
    # Копируем из разобранного выражения необходимые списки.
    # Числа
    digs = parsed[0][:] # Это неглубокое копирование (срез).
    # Для глубокого копирования импортировать copy и выполнить copy.deepcopy(lst)
    # Операторы
    opers = parsed[1][:]
    # Приоритеты
    priors = parsed[2][:]
    ## Указатель на текущее число
    #cur_dig_num = 0
    # Находим максимальный и минимальный приоритеты.
    min_pr = GetMinPr(priors)
    max_pr = GetMaxPr(priors)
    
    #TODO: Может как-то иначе распознавать разноместность оператора?
    #TODO: Как сохранить предыдущий индекс? Использовать while? Менять последовательность?
    for cur_pr in range(min_pr, max_pr + 1):
        for cur_op_num in range(len(opers)):
            if (priors[cur_op_num] == cur_pr):
                cur_op = opers[cur_op_num]
                is_two_op = False
                cur_op_func = one_ops.get(cur_op)
                if (not cur_op_func):
                    cur_op_func = two_ops.get(cur_op)
                    is_two_op = True
                # Достаём функцию-обработчик данного оператора 
                cur_op_func = cur_op_func[0]
                cur_ans = 0
                if (is_two_op):
                    cur_ans = cur_op_func(digs[cur_op_num], digs[cur_op_num + 1])
                else:
                    cur_ans = cur_op_func(digs[cur_op_num])
                digs[cur_op_num] = cur_ans
                del opers[cur_op_num]
                del priors[cur_op_num]
                if (is_two_op):
                    del digs[cur_op_num + 1]
                # Шаг назад...
                #cur_op_num -= 1
    return digs[0]
С помощью while сделал так (работает):
def CalculateParsed(parsed):
    """"Вычисление выражения в разобранном виде."""
    # Копируем из разобранного выражения необходимые списки.
    # Числа
    digs = parsed[0][:] # Это неглубокое копирование (срез).
    # Для глубокого копирования импортировать copy и выполнить copy.deepcopy(lst)
    # Операторы
    opers = parsed[1][:]
    # Приоритеты
    priors = parsed[2][:]
    ## Указатель на текущее число
    #cur_dig_num = 0
    # Находим максимальный и минимальный приоритеты.
    min_pr = GetMinPr(priors)
    max_pr = GetMaxPr(priors)
    
    #TODO: Может как-то иначе распознавать разноместность оператора?
    #TODO: Как сохранить предыдущий индекс? Использовать while? Менять последовательность?
    # Перебираем приоритеты от минимального к максимальному.
    for cur_pr in range(min_pr, max_pr + 1):
        cur_op_num = 0
        # Перебираем операторы
        while (cur_op_num < len(opers)):
            # Если это оператор с приоритетом, который мы сейчас обрабатываем, то вычисляем этот оператор
            if (priors[cur_op_num] == cur_pr):
                cur_op = opers[cur_op_num]
                is_two_op = False
                # Ищем этот оператор в списке одноместных операторов.
                cur_op_func = one_ops.get(cur_op)
                # Если не нашли
                if (not cur_op_func):
                    # Ищем в списке двухместных
                    cur_op_func = two_ops.get(cur_op)
                    # Ставим флаг, что это двухместный оператор.
                    is_two_op = True
                # Сейчас в cur_op_func у нас параметры этого оператора: функция обработчик, приоритет, описание, пример. 
                # Достаём функцию-обработчик данного оператора
                cur_op_func = cur_op_func[0]
                cur_ans = 0
                # В зависимости от того, одноместный или двустный это оператор, вызываем функцию с одним или двумя параметрами
                if (is_two_op):
                    cur_ans = cur_op_func(digs[cur_op_num], digs[cur_op_num + 1])
                    # Удаляем второе число, оно больше нам не нужно.
                    del digs[cur_op_num + 1]
                else:
                    cur_ans = cur_op_func(digs[cur_op_num])
                # Ответ кладём в текущую ячейку
                digs[cur_op_num] = cur_ans
                # Оператор и приоритет удаляем.
                del opers[cur_op_num]
                del priors[cur_op_num]
            else:
                # Если расчётов не было - шаг вперёд, к следующему оператору.
                # Если были, то мы уже на следующем операторе за счёт удаления предыдущего оператора и приоритета
                cur_op_num += 1
    return digs[0]


Для удаления массивов в С++ используй не delete, а delete[], иначе кака получится.В твоем же случае, как мне кажется, использовать while будет вполне логично.Меня немного смущает, что у твоего уже разобранного выражения такое неудобное представление (следовательно, и сам алгоритм вычисления выглядит кривовато). Может, было бы удобней при разборе строки строить дерево или переводить его в постфиксную нотацию?


Вот хороший пример (вычисление — функция evaluateStack): http://pyparsing.wikispaces.com/file/view/fourFn.py


Ну, переделывать, наверно, уж не стану - времени нет. Если препод не заставит... А так... Действительно, немного нерационально, но... Я немного поправил этот алгоритм, он стал чуть лучше.
Вот хороший пример (вычисление — функция evaluateStack): http://pyparsing.wikispaces.com/file/view/fourFn.py
Неплохой пример, только рекурсия...


FutureCome, рекурсия там совсем необязательна, и все легко переписывается через цикл