2010-11-03 3 views
1

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

Я попытался сделать это, чтобы использовать тот же код вперед или назад. Я закончил с:

for (int i = start; i != (finish + 1 * ((start < finish) ? 1 : -1)); i += 1 * ((start < finish) ? 1 : -1)) 

A) B) Я хотел поделиться этой концепцией со всеми.

B) Мне интересно об эффективности такой петли. Я знаю, что при вычислении целевого номера и фактора incriction, но я не знаю, как его проверить.

C) Пока я нахожусь, я нашел одну строку, которая меняет две переменные без использования временного. Это займет некоторое время, чтобы прочитать, но лучше ли это (код мудрый), чем использование темпа? (3-я строка в основном ниже)

Я протестировал его для работы, и он работает как ожидалось. Если второе число больше первого числа, оно подсчитывается. Если нет, оно подсчитывается. Мой тестовый код был:

// A generic loop that can go up or down 
import java.io.*; 

public class reversable 
{ 
    public static int start = 1; 
    public static int finish = 10; 

    public static void main(String[] args) 
    { 
    for (int i = start; i != (finish + 1 * ((start < finish) ? 1 : -1)); i += 1 * ((start < finish) ? 1 : -1)) 
    { 
     System.out.println("i = " + i); 
    } 
    finish = (start + finish) - (start = finish); 
System.out.println("Finish = " + finish); 
System.out.println("Start = " + start); 
    for (int i = start; i != (finish + 1 * ((start < finish) ? 1 : -1)); i += 1 * ((start < finish) ? 1 : -1)) 
    { 
     System.out.println("i = " + i); 
    } 
    finish = 10; 
    for (int i = start; i != (finish + 1 * ((start < finish) ? 1 : -1)); i += 1 * ((start < finish) ? 1 : -1)) 
    { 
     System.out.println("i = " + i); 
    } 
    } 
} 

На основе замечаний, это было бы приемлемо:

public static void reversable (int i, int j) 
{ 
    if (i > j) int inc = -1; // Count down 
    else  int inc = 1; // Count up 
    j += inc; 
    for (i; i != j; i += inc) 
    { 
    dostuff(); 
    morestuff(); 
    mostuff(); 
    } 
} 
+2

Результат 'finish = (start + finish) - (start = finish);' не определен, потому что разные компиляторы могут свободно оценивать два предложения в любом порядке. См. Аналогичный пример в нижней части этой страницы: http://www.cppreference.com/operator_precedence.html – AlcubierreDrive

+1

@Jon: Java! = C++. Java не соответствует тем же правилам, и большинство вещей, которые не определены в C/C++, имеют очень точные определения в Java. –

+0

@Mark Peters Ой, моя ошибка. Спасибо что подметил это. – AlcubierreDrive

ответ

15

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

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

+0

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

+4

этот код злой. – Ramp

+2

@muntoo: Я не против тройной, '? ..: ..', и я не считаю это злым. Но я определенно против вонючих кодов. –

10

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

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

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

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

+2

Я бы изменил «немного менее читаемый» на «гораздо менее читаемый». С 30-летним опытом программирования я все еще не убежден, что он работает по назначению, глядя на него в течение 10 минут. –

+1

@Software Monkey: Я разделил разницу и просто сделал ее «менее читаемой». :) –

6

Ум не пытается быть кирпич, но я думаю, что вы пытались написать:

public static void doAction(int i) { 
    System.out.println("i = " + i); 
} 

public static void loopValues(int i, int j) { 
    if (i > j) while (i >= j) doAction(i--); 
    else  while (i <= j) doAction(i++);; 
} 

public static void main(String[] args) { 
    int start = 1, finish = 10; 
    loopValues(start, finish); 
    loopValues(finish, start); 
} 

Причина, почему у вас есть 2 петли является эффективность и ваш случай читаемость. Сравнение - это дорогостоящая операция, и вы обычно не хотите добавлять дополнительные сравнения к циклу, чтобы изменить свой обычный курс.

+2

+1 для наглядности. –

0

Действительно, код трудно поддаться ... но достаточно с критиками. Когда кто-то просит методы повторного использования, где только цикл отличается, единственное, что приходит на ум, это Iterator. iterator pattern - это именно то, что вам нужно для этого многоразового использования.Если ваш оберните ваш итератор в интерфейсе Iterable, вы можете легко использовать его внутри блока for. Пример:

public class IntegerRange implements Iterable<Integer> { 
    private boolean reverse; 
    private int start; 
    private int end; 

    public IntegerRange(int start, int end) { 
     this.reverse = (start > end); 
     this.start = start; 
     this.end = end; 
    } 

    @Override 
    public Iterator<Integer> iterator() { 
     return new IntegerIterator(); 
    } 


    private class IntegerIterator implements Iterator<Integer> { 

     private int current; 

     private IntegerIterator() { 
     current = start; 
     } 

     @Override 
     public boolean hasNext() { 
     if (reverse) { 
      return (end <= current); 
     } else { 
      return (current <= end); 
     } 
     } 

     @Override 
     public Integer next() { 
     if (!hasNext()) { 
      throw new NoSuchElementException(); 
     } 
     if (reverse) { 
      return current--; 
     } else { 
      return current++; 
     } 
     } 

     @Override 
     public void remove() { 
     throw new UnsupportedOperationException("Cannot remove from this iterator"); 
     } 
    } 

} 

Затем использовать и повторно использовать итератор ...

static public void main(String...args) { 
    doStuff(new IntegerRange(1, 10)); 
    doStuff(new IntegerRange(10, 1)); 
} 

static private void doStuff(IntegerRange range) { 
    for (int i : range) { 
     System.out.println("i = " + i); 
    } 
} 

код более читаемым в настоящее время.

+0

Ummm ... У вас код не в моих силах. Я читаю его, думая ничего себе ... –