2015-10-08 4 views
1

MATLAB documentation описывает break ключевое слово, таким образом:Идиоматический способ выхода из нескольких вложенных циклов?

  • break завершает выполнение для или во время цикла. Выражения в цикле после оператора break не выполняются.
  • Во вложенных циклах разрывайте выходы только из цикла, в котором оно происходит. Контроль переходит к утверждению, которое следует за концом этого цикла.

(курсив мой)

Что делать, если вы хотите, чтобы выйти из нескольких вложенных циклов? Другие языки, такие как Java, предлагают labelled breaks, которые позволяют указать, куда следует передавать поток управления, но MATLAB не имеет такого механизма.

Рассмотрим следующий пример:

% assume A to be a 2D array 

% nested 'for' loops 
for j = 1 : n 
    for i = 1 : m 
    if f(A(i, j)) % where f is a predicate 
     break; % if want to break from both loops, not just the inner one 
    else 
     % do something interesting with A 
    end 
    end 
    % <--- the break transfers control to here... 
end 
% <--- ... but I want to transfer control to here 

Что такое идиоматических способ (в MATLAB) из выхода из обеих петель?

+2

Возможный дубликат [как выйти из двух вложенных циклов в Matlab] (http://stackoverflow.com/questions/20302746/how-to-exit-from-two-nested-for-loop-in-matlab) – michaelsnowden

+0

Я бы просто извлек функцию и вернусь из нее – michaelsnowden

+0

Вам нужно использовать другой механизм для выхода из всех вложенных циклов. Например. добавьте больше if или передайте весь цикл-strucutre в функцию, а затем используйте 'return' вместо' break' – rst

ответ

2

Я бы сказал, для оригинальногоконкретных например, лучше использовать линейную индексацию и один цикл:

%// sample-data generation 
m = 4; 
n = 5; 
A = rand(m, n); 
temp = 0; 

for k = 1:numel(A) 
    if A(k) > 0.8 %// note that if you had switched your inner and outer loops you would have had to transpose A first as Matlab uses column-major indexing 
     break; 
    else 
     temp = temp + A(k); 
    end 
end 

Или практически идентичную (но с меньшим разветвлением):

for k = 1:numel(A) 
    if A(k) <= 0.8 %// note that if you had switched your inner and outer loops you would have had to transpose A first as Matlab uses column-major indexing 
     temp = temp + A(k); 
    end 
end 

Я бы подумал, что этот ответ будет отличаться от случая к случаю, и нет единого одного размера подходит всем идиоматически правильно решение, но я хотел бы подойти к нему следующим образом в зависимости от вашей проблемы (заметьте, это все предполагает, что векторизация решение не практично, как это очевидно, первый выбор)

  1. уменьшить размеры вложенности и использовать либо нет break s или только один break (т.е. как показано выше).
  2. Don't use break at all потому что, если расчет вашего предиката не является дорогостоящим, и ваша петля имеет очень много итераций, эти дополнительные итерации в конце должны быть практически бесплатными.
  3. Неисправность этого set a flag and break at each level.
  4. Или, наконец, заверните свою петлю в функцию и вызовите return вместо break.
+0

Спасибо, но не зацикливаюсь на моем примере (который я с тех пор обобщил). Я просто ищу общий способ выхода из нескольких вложенных циклов, который хорошо масштабируется с уровнем вложенности. – Jubobs

+0

@Jubobs нет единого правильного пути. Я добавил 4 метода к моему ответу в порядке предпочтения. – Dan

1

Насколько я знаю, таких встроенных функций не существует. Однако в большинстве случаев Matlab не нуждается в вложенных циклах из-за поддержки векторизации. В тех случаях, когда векторизация не работает, петли в большинстве случаев являются длинными и сложными, и, следовательно, множественные разрывы не будут существенно мешать читаемости. Как отмечено в комментарии, вам действительно не нужен вложенный цикл.Векторизация будет делать трюк,

m = 5; 
n=4; 
x = rand(m,n); 
tmp = find(x>0.8, 1, 'first'); 
if (isempty(tmp)) 
    tmp = m*n+1; 
end 
tmp = tmp-1; 
tot = sum(x(1:tmp)); 

Там может быть, конечно, люди, утверждающие, что для петель не обязательно замедлится больше, но факт остается фактом, что Matlab является колонна тяжелой и с использованием более одного цикла в большинстве случаев включают цикл по не оптимальным размерам. Векторизованные решения не требуют этого, поскольку они могут использовать интеллектуальные методы, избегая таких циклов (которые, конечно, не выполняются, если вход представляет собой вектор строки, поэтому избегать этого также хорошо).

0

Лучший идиоматический способ использования Python (или яд вашего выбора) и забыть обо всем этом, но это еще одна история. Кроме того, я больше не согласен с требованиями к векторизации других ответов. Недавние версии Matlab довольно быстро обрабатывают петли. Вы можете быть удивлены.

Мои личные предпочтения направлены на то, чтобы сделать исключение преднамеренно и использовать его в блоке try and catch.

% assume A to be a 2D array 
A = rand(10) - 0.5; 
A(3,2) = 0; 

wreaker = MException('Loop:breaker','Breaking the law'); 

try 
    for j = 1 : size(A,1) 
     % forloop number 1 
     for i = 1 : size(A,2) 
      % forloop number 2 
      for k = 1:10 
       % forloop number 3 
       if k == 5 && j == 3 && i == 6 
        mycurrentval = 5; 
        throw(wreaker) 
       end 
      end 
     end 
    end 
catch 
    return % I don't remember the do nothing keyword for matlab apparently 
end 

Вы можете изменить местоположение вашего оттиска улочка try, чтобы вернуться в цикл по вашему выбору. Кроме того, убивая котят, вы можете написать свои собственные исключения, чтобы они маркировали исключение в зависимости от количества гнезд, а затем вы можете их слушать. Нет никакого конца уродству, хотя все еще красивее, чем наличие счетчиков или пользовательских переменных с предложениями, на мой взгляд.

Обратите внимание, что именно поэтому Matlab управляет многими людьми с ума. Он бесшумно выдает исключения довольно похожим образом, и вы получаете бессмысленную ошибку для последней случайно выбранной функции при прохождении, например, несоответствие размера в каком-то решателе дифференциальных уравнений и так далее. На самом деле я узнал все это после прочтения многих исходных кодов.

+0

Хороший ответ.Я удивлен, увидев ответ MATLAB от вас всех людей, учитывая вашу ненависть к MATLAB :) – Jubobs

+2

@ Jubobs Я был молодым, мне нужны были деньги, поэтому я использовал matlab – percusse

Смежные вопросы