Есть ли лучший способ написания этого цикла? - PullRequest
0 голосов
/ 05 июля 2019

Мне нужно проверить, имеет ли хотя бы 1 элемент в списке X, Y и Z (не все одновременно). например у элемента 1 есть x, а у элемента 2 есть y и z.

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

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

Спасибо

        boolean hasX = false;
        boolean hasY = false;
        boolean hasZ = false;

        for (ItemType item : Items) {
            if (!hasX) { hasX = DoesHaveX(item); }
            if (!hasY) { hasY = DoesHaveY(item); }
            if (!hasZ) { hasZ = DoesHaveZ(item); }
    }

Ответы [ 4 ]

1 голос
/ 05 июля 2019

Если вы собираетесь придерживаться JVM ниже 1,8, тогда ваш код в порядке!

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

    for (ItemType item : items) {

        hasX = hasX || doesHaveX(item);
        hasY = hasY || doesHaveY(item);
        hasZ = hasZ || doesHaveZ(item);

        if (hasX && hasY && hasZ) {

            break;
        }
    }

Если вам просто хорошо использовать потоки, возможно, лучше инициализировать каждую переменную при ее создании следующим образом:

    boolean hasX = items.stream().anyMatch(this::doesHaveX); // goes trough the elements until a match is found.
    boolean hasY = items.stream().anyMatch(this::doesHaveY); // goes trough the elements until a match is found.
    boolean hasZ = items.stream().anyMatch(this::doesHaveZ); // goes trough the elements until a match is found.
0 голосов
/ 06 июля 2019

Просто добавьте также вариант BitSet, и при условии, что проверка has... является полудорожой операцией:

private static final int xBit = 0;
private static final int yBit = 1;
private static final int zBit = 2;

public static boolean hasAll(final Collection<ItemType> items) {
    if (items.isEmpty()) return false;

    final BitSet bits = new BitSet(3);

    for (final ItemType item : items) {

        // Check if bit is already set to avoid
        // needless `has*` evaluation
        if (!bits.get(xBit) && hasX(item)) bits.set(xBit);

        if (!bits.get(yBit) && hasY(item)) bits.set(yBit);

        if (!bits.get(zBit) && hasZ(item)) bits.set(zBit);

        // You could repeat this INSIDE all of the 'if's
        // above to potentially avoid computing bits.get
        // but I'd sacrifice that for the slightly improved
        // readability.
        if (bits.cardinality() == 3) return true;
    }

    return false;
}

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

0 голосов
/ 05 июля 2019

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

import java.util.EnumMap;
import java.util.List;
import java.util.Map;
import java.util.function.Predicate;

class StackOverflowQuestion56902308Scratch {
    class ItemType {
        boolean x;
        boolean y;
        boolean z;
    }

    enum ItemTypeCheck implements Predicate<ItemType> {
        HASX() {
            @Override
            public boolean test(ItemType itemType) {
                //TODO: implement me
                return itemType.x;
            }
        },
        HASY() {
            @Override
            public boolean test(ItemType itemType) {
                //TODO: implement me
                return itemType.y;
            }
        },
        HASZ() {
            @Override
            public boolean test(ItemType itemType) {
                //TODO: implement me
                return itemType.z;
            }
        }
    }

    public static boolean hasOneOfAll(List<ItemType> itemTypes) {
        Map<ItemTypeCheck, Boolean> result = new EnumMap<>(ItemTypeCheck.class);
        for (ItemType itemType : itemTypes) {
            for (ItemTypeCheck check : ItemTypeCheck.values()) {
                result.merge(check, check.test(itemType), Boolean::logicalOr);
            }
        }

        return result.values().stream().allMatch(hadOne -> hadOne);
    }

}

Лично я не уверен, слишком ли это чрезмерно, но это облегчает боль ручной настройки функции, если в будущем будет добавлена ​​еще одна проверка.

0 голосов
/ 05 июля 2019

Потоковая карта / уменьшенная версия цикла для развлечения.Не уверен, что лучше быть честным.Но, по крайней мере, мы избавляемся от всех переменных

  • отображаем каждый элемент в список из 3 логических значений (по одному для каждого атрибута x, y, z)
  • сокращаем весь список досписок из 3 логических значений (по одному для каждого атрибута x, y, z), проверяющий, имеет ли какой-либо из элементов каждое значение
  • , проверяет, являются ли все элементы результирующего списка истинными.
boolean allGood = items.stream()
    .map(i -> Arrays.asList(doesHaveX(i), doesHaveY(i), doesHaveZ(i)))
    .reduce(Arrays.asList(false, false, false),
            (acc, elem) -> Arrays.asList(acc.get(0) || elem.get(0), 
                                         acc.get(1) || elem.get(1), 
                                         acc.get(2) || elem.get(2)))
    .stream()
    .allMatch(Boolean::booleanValue);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...