Фильтрация двойного потока Java отсортированного списка [дубликат]

Вы хотите это:

class a:
    def __init__(self):
        self.list = []

Объявление переменных внутри объявления класса делает их членами класса, а не членами экземпляра. Объявление их внутри метода __init__ гарантирует, что новый экземпляр членов создается рядом с каждым новым экземпляром объекта, что является поведением, которое вы ищете.

153
задан assylias 12 June 2015 в 08:12
поделиться

16 ответов

Такая операция должна быть возможной с Java 8 Stream, но она не обязательно может быть выполнена эффективно - например, вы не можете распараллеливать такую ​​операцию, как вы должны смотреть на элементы по порядку.

API не обеспечивает простой способ сделать это, но, пожалуй, самый простой способ - взять Stream.iterator(), обернуть Iterator, чтобы иметь «take-while», а затем вернитесь к Spliterator, а затем к Stream. Или, может быть, оберните Spliterator, хотя в этой реализации он больше не может быть разделен.

Вот непроверенная реализация takeWhile на Spliterator:

static <T> Spliterator<T> takeWhile(
    Spliterator<T> splitr, Predicate<? super T> predicate) {
  return new Spliterators.AbstractSpliterator<T>(splitr.estimateSize(), 0) {
    boolean stillGoing = true;
    @Override public boolean tryAdvance(Consumer<? super T> consumer) {
      if (stillGoing) {
        boolean hadNext = splitr.tryAdvance(elem -> {
          if (predicate.test(elem)) {
            consumer.accept(elem);
          } else {
            stillGoing = false;
          }
        });
        return hadNext && stillGoing;
      }
      return false;
    }
  };
}

static <T> Stream<T> takeWhile(Stream<T> stream, Predicate<? super T> predicate) {
   return StreamSupport.stream(takeWhile(stream.spliterator(), predicate), false);
}
66
ответ дан Louis Wasserman 27 August 2018 в 06:24
поделиться

takeWhile является одной из функций, предоставляемых библиотекой protonpack .

Stream<Integer> infiniteInts = Stream.iterate(0, i -> i + 1);
Stream<Integer> finiteInts = StreamUtils.takeWhile(infiniteInts, i -> i < 10);

assertThat(finiteInts.collect(Collectors.toList()),
           hasSize(10));
46
ответ дан Andrew Tobilko 27 August 2018 в 06:24
поделиться

Обновление: Java 9 Stream теперь поставляется с методом takeWhile .

Нет необходимости в хаках или других решениях. Просто используйте это!


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

Stream<Integer> stream = Stream.iterate(0, n -> n + 1);

TakeWhile.stream(stream, n -> n < 10000)
         .forEach(n -> System.out.print((n == 0 ? "" + n : "," + n)));

Взломать наверняка .. Не элегантный - но он работает ~: D

class TakeWhile<T> implements Iterator<T> {

    private final Iterator<T> iterator;
    private final Predicate<T> predicate;
    private volatile T next;
    private volatile boolean keepGoing = true;

    public TakeWhile(Stream<T> s, Predicate<T> p) {
        this.iterator = s.iterator();
        this.predicate = p;
    }

    @Override
    public boolean hasNext() {
        if (!keepGoing) {
            return false;
        }
        if (next != null) {
            return true;
        }
        if (iterator.hasNext()) {
            next = iterator.next();
            keepGoing = predicate.test(next);
            if (!keepGoing) {
                next = null;
            }
        }
        return next != null;
    }

    @Override
    public T next() {
        if (next == null) {
            if (!hasNext()) {
                throw new NoSuchElementException("Sorry. Nothing for you.");
            }
        }
        T temp = next;
        next = null;
        return temp;
    }

    public static <T> Stream<T> stream(Stream<T> s, Predicate<T> p) {
        TakeWhile tw = new TakeWhile(s, p);
        Spliterator split = Spliterators.spliterator(tw, Integer.MAX_VALUE, Spliterator.ORDERED);
        return StreamSupport.stream(split, false);
    }

}
7
ответ дан Austin Powers 27 August 2018 в 06:24
поделиться

Даже у меня было подобное требование - вызовите веб-сервис, если он не работает, повторите попытку 3 раза. Если это не удается даже после этих многочисленных испытаний, отправьте уведомление по электронной почте. После многопользовательской игры, anyMatch() пришел как спаситель. Мой пример кода выглядит следующим образом. В следующем примере, если метод webServiceCall возвращает true в первой итерации, поток не выполняет итерацию по мере того, как мы вызвали anyMatch(). Я считаю, это то, что вы ищете.

import java.util.stream.IntStream;

import io.netty.util.internal.ThreadLocalRandom;

class TrialStreamMatch {

public static void main(String[] args) {        
    if(!IntStream.range(1,3).anyMatch(integ -> webServiceCall(integ))){
         //Code for sending email notifications
    }
}

public static boolean webServiceCall(int i){
    //For time being, I have written a code for generating boolean randomly
    //This whole piece needs to be replaced by actual web-service client code
    boolean bool = ThreadLocalRandom.current().nextBoolean();
    System.out.println("Iteration index :: "+i+" bool :: "+bool);

    //Return success status -- true or false
    return bool;
}
0
ответ дан cbaldan 27 August 2018 в 06:24
поделиться

Вот версия, сделанная в ints - как задано в вопросе.

Использование:

StreamUtil.takeWhile(IntStream.iterate(1, n -> n + 1), n -> n < 10);

Вот код для StreamUtil:

import java.util.PrimitiveIterator;
import java.util.Spliterators;
import java.util.function.IntConsumer;
import java.util.function.IntPredicate;
import java.util.stream.IntStream;
import java.util.stream.StreamSupport;

public class StreamUtil
{
    public static IntStream takeWhile(IntStream stream, IntPredicate predicate)
    {
        return StreamSupport.intStream(new PredicateIntSpliterator(stream, predicate), false);
    }

    private static class PredicateIntSpliterator extends Spliterators.AbstractIntSpliterator
    {
        private final PrimitiveIterator.OfInt iterator;
        private final IntPredicate predicate;

        public PredicateIntSpliterator(IntStream stream, IntPredicate predicate)
        {
            super(Long.MAX_VALUE, IMMUTABLE);
            this.iterator = stream.iterator();
            this.predicate = predicate;
        }

        @Override
        public boolean tryAdvance(IntConsumer action)
        {
            if (iterator.hasNext()) {
                int value = iterator.nextInt();
                if (predicate.test(value)) {
                    action.accept(value);
                    return true;
                }
            }

            return false;
        }
    }
}
2
ответ дан Chris Greenaway 27 August 2018 в 06:24
поделиться

Вот моя попытка использовать только библиотеку Java Stream.

        IntStream.iterate(0, i -> i + 1)
        .filter(n -> {
                if (n < 10) {
                    System.out.println(n);
                    return false;
                } else {
                    return true;
                }
            })
        .findAny();
-2
ответ дан climbing_bum 27 August 2018 в 06:24
поделиться

В качестве продолжения ответа @StuartMarks ответ . Моя библиотека StreamEx имеет операцию takeWhile , которая совместима с текущей реализацией JDK-9. При запуске под JDK-9 он просто делегирует реализацию JDK (через MethodHandle.invokeExact, которая очень быстро). При работе под JDK-8 будет использоваться реализация «polyfill». Поэтому, используя мою библиотеку, проблема может быть решена следующим образом:

IntStreamEx.iterate(1, n -> n + 1)
           .takeWhile(n -> n < 10)
           .forEach(System.out::println);
30
ответ дан Community 27 August 2018 в 06:24
поделиться

На самом деле есть два способа сделать это в Java 8 без каких-либо дополнительных библиотек или с использованием Java 9.

Если вы хотите печатать цифры от 2 до 20 на консоли, вы можете сделать это:

IntStream.iterate(2, (i) -> i + 2).peek(System.out::println).allMatch(i -> i < 20);

или

IntStream.iterate(2, (i) -> i + 2).peek(System.out::println).anyMatch(i -> i >= 20);

Выход в обоих случаях:

2
4
6
8
10
12
14
16
18
20

Пока никто не упомянул anyMatch . Вот почему этот пост.

0
ответ дан gil.fernandes 27 August 2018 в 06:24
поделиться

Вы можете использовать java8 + rxjava .

import java.util.stream.IntStream;
import rx.Observable;


// Example 1)
IntStream intStream  = IntStream.iterate(1, n -> n + 1);
Observable.from(() -> intStream.iterator())
    .takeWhile(n ->
          {
                System.out.println(n);
                return n < 10;
          }
    ).subscribe() ;


// Example 2
IntStream intStream  = IntStream.iterate(1, n -> n + 1);
Observable.from(() -> intStream.iterator())
    .takeWhile(n -> n < 10)
    .forEach( n -> System.out.println(n));
7
ответ дан Henrik 27 August 2018 в 06:24
поделиться

Если у вас другая проблема, вам может понадобиться другое решение, но для вашей текущей проблемы я просто зайду:

IntStream
    .iterate(1, n -> n + 1)
    .limit(10)
    .forEach(System.out::println);
-1
ответ дан krmanish007 27 August 2018 в 06:24
поделиться

Это источник, скопированный из JDK 9 java.util.stream.Stream.takeWhile (Predicate). Небольшая разница для работы с JDK 8.

static <T> Stream<T> takeWhile(Stream<T> stream, Predicate<? super T> p) {
    class Taking extends Spliterators.AbstractSpliterator<T> implements Consumer<T> {
        private static final int CANCEL_CHECK_COUNT = 63;
        private final Spliterator<T> s;
        private int count;
        private T t;
        private final AtomicBoolean cancel = new AtomicBoolean();
        private boolean takeOrDrop = true;

        Taking(Spliterator<T> s) {
            super(s.estimateSize(), s.characteristics() & ~(Spliterator.SIZED | Spliterator.SUBSIZED));
            this.s = s;
        }

        @Override
        public boolean tryAdvance(Consumer<? super T> action) {
            boolean test = true;
            if (takeOrDrop &&               // If can take
                    (count != 0 || !cancel.get()) && // and if not cancelled
                    s.tryAdvance(this) &&   // and if advanced one element
                    (test = p.test(t))) {   // and test on element passes
                action.accept(t);           // then accept element
                return true;
            } else {
                // Taking is finished
                takeOrDrop = false;
                // Cancel all further traversal and splitting operations
                // only if test of element failed (short-circuited)
                if (!test)
                    cancel.set(true);
                return false;
            }
        }

        @Override
        public Comparator<? super T> getComparator() {
            return s.getComparator();
        }

        @Override
        public void accept(T t) {
            count = (count + 1) & CANCEL_CHECK_COUNT;
            this.t = t;
        }

        @Override
        public Spliterator<T> trySplit() {
            return null;
        }
    }
    return StreamSupport.stream(new Taking(stream.spliterator()), stream.isParallel()).onClose(stream::close);
}
2
ответ дан martian 27 August 2018 в 06:24
поделиться

Вы не можете прервать поток, за исключением операции с коротким замыканием, которая оставила бы некоторые значения потока необработанными независимо от их значения. Но если вы просто хотите избежать операций над потоком, вы можете добавить преобразование и фильтр в поток:

import java.util.Objects;

class ThingProcessor
{
    static Thing returnNullOnCondition(Thing thing)
    {    return( (*** is condition met ***)? null : thing);    }

    void processThings(Collection<Thing> thingsCollection)
    {
        thingsCollection.stream()
        *** regular stream processing ***
        .map(ThingProcessor::returnNullOnCondition)
        .filter(Objects::nonNull)
        *** continue stream processing ***
    }
} // class ThingProcessor

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

0
ответ дан Matthew 27 August 2018 в 06:24
поделиться

Может быть немного не по теме, но это то, что у нас есть для List<T>, а не Stream<T>.

Сначала вам понадобится метод take util. Эти методы принимают первые n элементы:

static <T> List<T> take(List<T> l, int n) {
    if (n <= 0) {
        return newArrayList();
    } else {
        int takeTo = Math.min(Math.max(n, 0), l.size());
        return l.subList(0, takeTo);
    }
}

он работает только как scala.List.take

    assertEquals(newArrayList(1, 2, 3), take(newArrayList(1, 2, 3, 4, 5), 3));
    assertEquals(newArrayList(1, 2, 3), take(newArrayList(1, 2, 3), 5));

    assertEquals(newArrayList(), take(newArrayList(1, 2, 3), -1));
    assertEquals(newArrayList(), take(newArrayList(1, 2, 3), 0));

, теперь будет довольно просто написать метод takeWhile на основе на take

static <T> List<T> takeWhile(List<T> l, Predicate<T> p) {
    return l.stream().
            filter(p.negate()).findFirst(). // find first element when p is false
            map(l::indexOf).        // find the index of that element
            map(i -> take(l, i)).   // take up to the index
            orElse(l);  // return full list if p is true for all elements
}

он работает следующим образом:

    assertEquals(newArrayList(1, 2, 3), takeWhile(newArrayList(1, 2, 3, 4, 3, 2, 1), i -> i < 4));

эта реализация повторяет список частично в течение нескольких раз, но не добавляет add O(n^2) операций , Надеюсь, это приемлемо.

-1
ответ дан Max 27 August 2018 в 06:24
поделиться

Операции takeWhile и dropWhile добавлены в JDK 9. Ваш примерный код

IntStream
    .iterate(1, n -> n + 1)
    .takeWhile(n -> n < 10)
    .forEach(System.out::println);

будет вести себя точно так, как вы ожидаете, когда он скомпилирован и запущен под JDK 9.

Выпущен JDK 9. Его можно скачать здесь: http://jdk.java.net/9/

131
ответ дан Stuart Marks 27 August 2018 в 06:24
поделиться

У меня есть еще одно быстрое решение, реализуя это (что на самом деле является нечистым, но вы получаете идею):

public static void main(String[] args) {
    System.out.println(StreamUtil.iterate(1, o -> o + 1).terminateOn(15)
            .map(o -> o.toString()).collect(Collectors.joining(", ")));
}

static interface TerminatedStream<T> {
    Stream<T> terminateOn(T e);
}

static class StreamUtil {
    static <T> TerminatedStream<T> iterate(T seed, UnaryOperator<T> op) {
        return new TerminatedStream<T>() {
            public Stream<T> terminateOn(T e) {
                Builder<T> builder = Stream.<T> builder().add(seed);
                T current = seed;
                while (!current.equals(e)) {
                    current = op.apply(current);
                    builder.add(current);
                }
                return builder.build();
            }
        };
    }
}
-1
ответ дан user2504380 27 August 2018 в 06:24
поделиться

Перейти к библиотеке AbacusUtil . Он предоставляет точный API, который вы хотите, и многое другое:

IntStream.iterate(1, n -> n + 1).takeWhile(n -> n < 10).forEach(System.out::println);

Объявление: Я разработчик AbacusUtil.

0
ответ дан user_3380739 27 August 2018 в 06:24
поделиться
Другие вопросы по тегам:

Похожие вопросы: