Что лучше - для цикла с разрывом или условного цикла? - PullRequest
23 голосов
/ 27 февраля 2009

Мне просто любопытно, что думают люди по этой теме. Допустим, у меня есть массив объектов, и я хочу просмотреть их, чтобы увидеть, содержат ли объекты определенные значения, и если да, я хочу остановить цикл. Что является лучшей практикой - цикл for с разрывом или условный цикл?

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

для цикла с разрывом:

var i:int;

var isBaxterInMilwaukee:Boolean;    

for (i = 0; i < arrayLen; i++)
{
    if (myArray[i]["name"] == "baxter"
         && myArray[i]["location"] == "milwaukee")
    {
        isBaxterInMilwaukee = true;

        barkTwice();

        break;
    }
}

условный цикл:

var i:int;

var isBaxterInMilwaukee:Boolean;    

while (!isBaxterInMilwaukee && i < arrayLen)
{
    if (myArray[i]["name"] == "baxter"
         && myArray[i]["location"] == "milwaukee")
    {
        isBaxterInMilwaukee = true;

        barkTwice();
    }

    i++;
}

Ответы [ 19 ]

2 голосов
/ 27 февраля 2009

Есть два аспекта проблемы:

  • Что сделать (например: найти, если один из предметов содержит указанного человека в локации)
  • Как сделать это (например: использовать индекс, повторять и т. Д.)

Оба примера смешивают два, и трудно понять что из как . Лучше всего было бы, если бы мы могли выразить в коде только часть what . Вот пример (c # 3.5), который делает это, используя спецификацию pattern

// what we are looking for?
IsPersonInLocation condition = new IsPersonInLocation("baxter", "milwaukee");

// does the array contain what we are looking for?
bool found = myArray.Find(item => condition.IsSatifiedBy(item));

// do something if the condition is satisfied
if (found) {
    barkTwice();
}

Для полноты вот определение класса для условия:

class IsPersonInLocation {
    public string Person { get; set; }
    public string Location { get; set; }
    public IsPersonInLocation(string person, string location) {
        this.Person = person;
        this.Location = location;
    }
    bool IsSatifiedBy(item) {
        return item["name"] == this.Person
            && item["location"] == this.Location;
    }
}
1 голос
/ 27 февраля 2009

Моя теория заключается в том, что существует полезная программная абстракция, похожая на «отношение сигнал / шум», то есть «отношение проблемы к инструменту» - добротность можно измерить в одном измерении по тому, сколько времени я трачу на размышления проблема и ее решение по сравнению с тем временем, которое я трачу на размышления о том, как использовать инструмент (в данном случае синтаксис языка).

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

И хорошо, что все, что вам нужно знать (ошеломленно) о правилах циклов, находится в одной строке в верхней части цикла for. Я также склонен ставить переключатель «по умолчанию» первым в тестах по той же причине.

Но непротиворечивость и ясность - это непротиворечивость. YMMV, конечно.

1 голос
/ 27 февраля 2009

Многое зависит от конкретных обстоятельств. Но в вашем примере вы хотите обойти массив ограниченной длины, а использование цикла for позволяет легко это сделать и избежать выхода за пределы. В вашем примере цикла while вы должны сделать свое собственное приращение - что может быть проблематично, если вы хотите использовать оператор continue для перехода к следующему циклу - и создать более сложное условное выражение (которое, кстати, есть ошибка, я думаю, вы имели в виду && i != arrayLen). Вам просто нужно сделать дополнительный код для достижения эффекта, который обеспечивает цикл for.

Конечно, некоторые пуристы будут утверждать, что break и continue не должны использоваться и что вы должны использовать переменные if-else и булевы переменные, если это необходимо, а не продолжать или прерывать цикл. Но я думаю, что это может сделать цикл более уродливым, особенно если он относительно короткий и его легко понять, как в этом примере. Для цикла с гораздо более длинным кодом, в котором разрыв или продолжение можно легко скрыть от внимания, пуристический подход может быть более понятным, поскольку цикл уже сложен для понимания в этом случае. Но вы всегда можете сделать это как часть цикла for, просто добавьте его как часть условия.

Лучше также проверять массив, связанный с i < arrayLen, а не на точное равенство, в случае, если что-то заставило i пропустить точное значение (я действительно видел, что это произошло в ошибке Y2K, которая могла иметь избегал лучшей практики).

1 голос
/ 27 февраля 2009

У меня есть опыт работы с C ++, поэтому у меня все еще есть моменты, когда я пытаюсь "мыслить как компилятор". В то время как циклы имеют тенденцию приводить к более трудному коду, и поэтому циклы for рассматривались только в том случае, если вы знали, что собираетесь выполнять итерацию по каждому элементу в массиве, каждый раз.

РЕДАКТИРОВАТЬ: Теперь я считаю, что это излишне, если вы используете .Net или что-то еще, что вы не собираетесь компенсировать накладные расходы виртуальной машины с парой узких циклов. Я думаю, что хорошо помнить «почему» определенных практик.

1 голос
/ 03 марта 2009

Инкапсулируйте цикл в своем собственном методе и используйте возврат к концу обработки, когда ваше условие соответствия выполнено.

Пример кода C #:

class Program
{
   static bool IsBaxterInMilwaukee(IList<WhoAndWhere> peopleAndPlaces)
   {
      foreach (WhoAndWhere personAndPlace in peopleAndPlaces)
      {
         if (personAndPlace.Name == "Baxter" 
            && personAndPlace.Location == "Milwaukee")
         {
            return true;
         }
      }
      return false;
   }

   static void Main(string[] args)
   {
      List<WhoAndWhere> somePeopleAndPlaces = new List<WhoAndWhere>();
      somePeopleAndPlaces.Add(new WhoAndWhere("Fred", "Vancouver"));
      somePeopleAndPlaces.Add(new WhoAndWhere("Baxter", "Milwaukee"));
      somePeopleAndPlaces.Add(new WhoAndWhere("George", "London"));

      if (IsBaxterInMilwaukee(somePeopleAndPlaces))
      {
         // BarkTwice()
         Console.WriteLine("Bark twice");
      }
   }

   public class WhoAndWhere
   {
      public WhoAndWhere(string name, string location)
      {
         this.Name = name;
         this.Location = location;
      }

      public string Name { get; private set; }
      public string Location { get; private set; }
   }

}
1 голос
/ 28 февраля 2009

Полагаю, ни то, ни другое на самом деле не интересно. Вы должны искать конструкции более высокого уровня, если вам нужна читабельность.

В JS:

if(myArray.some(function(o) { o.name == "baxter" && o.location == "milwaukee" }))
  barkTwice();

или с некоторыми собственными утилитами

if(myArray.containsMatch({name:"baxter",location:"milwaukee"})
  barkTwice();
0 голосов
/ 24 апреля 2019

В ES6 это было сделано очень просто, нет необходимости использовать ключевое слово break, мы можем использовать функцию find, когда условие удовлетворяется, мы можем вернуть true.

let barkTwice = () => {
    console.log('bark twice');
}

let arr = [{
        location: "waukee",
        name: "ter"
    }, {
        location: "milwaukee",
        name: "baxter"
    },
    {
        location: "sample",
        name: "sampename"
    }
];

Здесь мы сопоставляем условие и, когда условие совпадает, мы вызываем функцию в соответствии с вопросом, а затем возвращаем true. Так что это не выходит за рамки.

arr.find(item => {
    if (item.location == "milwaukee" && item.name == "baxter") {
        barkTwice();
        return true
    }
});
0 голосов
/ 28 февраля 2009

Я голосую while, потому что перерывы уменьшают способность к покупкам.

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

Но я подписываюсь на не заставляй меня думать модель кодирования.

0 голосов
/ 28 февраля 2009

Моя общая позиция:

Если у него есть счетчик цикла, используйте для () (например, пока цикл имеет).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...