Избавиться от некрасивых высказываний - PullRequest
60 голосов
/ 24 сентября 2010

У меня есть этот уродливый код:

if ( v > 10 ) size = 6;
if ( v > 22 ) size = 5;
if ( v > 51 ) size = 4;
if ( v > 68 ) size = 3;
if ( v > 117 ) size = 2;
if ( v > 145 ) size = 1;
return size;

Как мне избавиться от нескольких операторов if?

Ответы [ 25 ]

7 голосов
/ 11 октября 2010
7 - (x>10 + x>22 + x>51 + x>68 + x>117 + x>145)

где 7 - значение по умолчанию (x <= 10).

Edit: Первоначально я не понимал, что этот вопрос о Java. Это выражение недопустимо в Java, но допустимо в C / C ++. Я оставлю ответ, так как некоторые пользователи сочли его полезным.

5 голосов
/ 24 сентября 2010

Моя возможность комментирования еще не включена, надеюсь, никто не скажет "по праву" на основании моего ответа ...

Довольно ужасный код может / должен быть определен как попытка достичь:

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

ИМО ответ org.life.java был самым красивым и чрезвычайно легко читаемым. Мне также понравился порядок, в котором были написаны условия, по причинам чтения и исполнения.

Просматривая все комментарии на эту тему, на момент моего написания выясняется, что только org.life.java поднял вопрос производительности (и, возможно, mfloryan также заявил, что что-то будет «длиннее»). Конечно, в большинстве ситуаций, и, учитывая этот пример, он не должен иметь заметного замедления, как бы вы его ни написали.

Однако, вложив ваши условия и оптимально упорядочив условия, можно улучшить производительность [особенно, если это было зациклено].

С учетом всего сказанного условия вложения и упорядочения (более сложные, чем ваш пример), вызванные решимостью добиться максимально быстрого выполнения, часто приводят к менее читаемому коду и коду, который сложнее изменить. Я снова ссылаюсь на № 3, прагматизм ... балансирование потребностей.

5 голосов
/ 24 сентября 2010

Вот объектно-ориентированное решение, класс с именем Mapper<S,T>, который отображает значения любого типа, который реализуется сопоставимо с любым целевым типом.

Синтаксис:

Mapper<String, Integer> mapper = Mapper.from("a","b","c").to(1,2,3);

// Map a single value
System.out.println(mapper.map("beef")); // 2

// Map a Collection of values
System.out.println(mapper.mapAll(
    Arrays.asList("apples","beef","lobster"))); // [1, 2, 3]

Код:

public class Mapper<S extends Comparable<S>, T> {

    private final S[] source;
    private final T[] target;

    // Builder to enable from... to... syntax and
    // to make Mapper immutable
    public static class Builder<S2 extends Comparable<S2>> {
        private final S2[] data;
        private Builder(final S2[] data){
            this.data = data;
        }
        public <T2> Mapper<S2, T2> to(final T2... target){
            return new Mapper<S2, T2>(this.data, target);
        }
    }


    private Mapper(final S[] source, final T[] target){
        final S[] copy = Arrays.copyOf(source, source.length);
        Arrays.sort(copy);
        this.source = copy;
        this.target = Arrays.copyOf(target, target.length);
    }

    // Factory method to get builder
    public static <U extends Comparable<U>, V> Builder<U> from(final U... items){
        return new Builder<U>(items);
    }

    // Map a collection of items
    public Collection<T> mapAll(final Collection<? extends S> input){
        final Collection<T> output = new ArrayList<T>(input.size());
        for(final S s : input){
            output.add(this.map(s));
        }
        return output;
    }

    // map a single item
    public T map(final S input){
        final int sourceOffset = Arrays.binarySearch(this.source, input);
        return this.target[
            Math.min(
                this.target.length-1,
                sourceOffset < 0 ? Math.abs(sourceOffset)-2:sourceOffset
            )
        ];
    }
}

Редактировать: окончательно заменил метод map () на более эффективную (и более короткую) версию.Я знаю: версия, которая ищет разделы, все еще будет быстрее для больших массивов, но извините: я слишком ленив.

Если вы думаете, что это слишком раздутый, подумайте:

  1. Содержит компоновщик, который позволяет создавать Mapper с использованием синтаксиса varargs.Я бы сказал, что это необходимо для удобства использования
  2. Он содержит как один элемент, так и метод отображения коллекции
  3. Он неизменен и, следовательно, безопасен для потоков

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

4 голосов
/ 25 сентября 2010

Есть ли в этом математическое правило? Если это так, вы должны использовать это: но только если это происходит из проблемной области, а не просто какая-то формула, которая подходит для случаев.

3 голосов
/ 24 сентября 2010
int[] arr = new int[] {145, 117, 68, 51, 22, 10};
for(int index = 0; index < arr.length; index++)
{
  if(v > arr[index]) return 1 + index; 
}

return defaultValue;
3 голосов
/ 24 ноября 2017

Вы можете переписать его в код ARM. Это всего 7 циклов в худшем случае и тонкий 164 байта. Надеюсь, это поможет. (примечание: это не проверено)

; On entry
;   r0 - undefined
;   r1 - value to test
;   lr - return address
; On exit
;   r0 - new value or preserved
;   r1 - corrupted
;
wtf
        SUBS    r1, r1, #10
        MOVLE   pc, lr
        CMP     r1, #135
        MOVGT   r0, #1
        ADRLE   r0, lut
        LDRLEB  r0, [r0, r1]
        MOV     pc, lr
;
; Look-up-table
lut
        DCB     0   ; padding
        DCB     6   ; r1 = 11 on entry
        DCB     6
        DCB     6
        DCB     6
        DCB     6
        DCB     6
        DCB     6
        DCB     6
        DCB     6
        DCB     6
        DCB     6
        DCB     6
        DCB     5   ; r1 = 23 on entry
        DCB     5
        ...
        ALIGN
2 голосов
/ 29 сентября 2010

На самом деле, если размеры могут измениться, сделать это в базе данных может быть хорошей альтернативной стратегией:

CREATE TABLE VSize (
   LowerBound int NOT NULL CONSTRAINT PK_VSize PRIMARY KEY CLUSTERED,
   Size int NOT NULL
)
INSERT VSize VALUES (10, 6)
INSERT VSize VALUES (22, 5)
INSERT VSize VALUES (51, 4)
INSERT VSize VALUES (68, 3)
INSERT VSize VALUES (117, 2)
INSERT VSize VALUES (145, 1)

И хранимая процедура или функция:

CREATE PROCEDURE VSizeLookup
   @V int,
   @Size int OUT
AS
SELECT TOP 1 @Size = Size
FROM VSize
WHERE @V > LowerBound
ORDER BY LowerBound
1 голос
/ 06 января 2014

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

public int getSize(int input)
    {
        int size = 0;
        switch(input)
        {
        case 10:
            size = 6;
            break;

        case 22:
            size = 5;
            break;


        case 51:
            size = 4;
            break;

        case 68:
            size = 3;
            break;

        case 117:
            size = 2;
            break;

        case 145:
            size = 1;
            break;
        }

        return size;
    }
1 голос
/ 27 сентября 2010

Просто для полноты позвольте мне предложить, чтобы вы могли настроить массив SIZES с 145 элементами, чтобы ответ мог быть возвращен непосредственно как SIZES [v]. Прошу прощения за то, что не выписал все это. Конечно, вы должны убедиться, что v был в пределах досягаемости.

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

1 голос
/ 06 октября 2010

Очевидный ответ - использовать Groovy:

def size = { v -> [145,117,68,51,22,10].inject(1) { s, t -> v > t ? s : s + 1 } }

Один лайнер всегда лучше. Возвращает 7 для неопределенного случая, когда v <= 10. </p>

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