2015-06-06 3 views
1

В качестве примера, я хочу, чтобы создать бесконечный поток групп десятков так:Как уменьшить поток в другой поток в Java8?

0=[0, 1, 2, 3, 4, 5, 6, 7, 8, 9] 
1=[10, 11, 12, 13, 14, 15, 16, 17, 18, 19] 
2=[20, 21, 22, 23, 24, 25, 26, 27, 28, 29] 
... 

Я хочу использовать inifinte поток Интс как вход, который затем должен быть сгруппированы. Если первый поток итерации 10 раз, результирующий поток должен быть повторен только один раз.

Мой рабочий, но не очень элегантный код выглядит следующим образом:

// create a stream from 0 (inclusive) to 100 (exclusive) 
IntStream.iterate(0, i -> i+1).boxed().limit(100) 

// slow down 
.peek((i) -> {try {Thread.sleep(50);} catch (InterruptedException e) {}}) 

// group by tens 
/* ugly: */.collect(Collectors.groupingBy(i -> i/10)).entrySet() 
/* not working: */ //.makeSequentialGroups(i -> i/10) 

// print to console 
.forEach(System.out::println); 

Как сделать группы с Int потока, без необходимости собирать и повторно поток? (Если возможно, даже без использования бокса)

+0

Вам не нужно создавать другой поток, вы можете использовать метод 'forEach' в' Set'. – Bubletan

+0

@Bubletan Спасибо за ваш намек, я обновил свой вопрос, чтобы не содержать устаревшего 'forEach' больше – slartidan

ответ

1

Такая функция доступна в моей StreamEx библиотеке и называется groupRuns: вы можете собрать соседние элементы в промежуточный список, основанный на предикат. Пример:

IntStreamEx.iterate(0, i -> i+1).boxed().limit(100) 
    .peek((i) -> {try {Thread.sleep(50);} catch (InterruptedException e) {}}) 
    .groupRuns((a, b) -> a/10 == b/10) 
    .forEach(System.out::println); 
+0

Спасибо за ваш ответ. Ваша библиотека выглядит весьма полезной! – slartidan

2

Я сомневаюсь, что есть способ, так как вы не можете нанести на карту sequence to a Map in java 8, не собирая и не можете группировать без сбора. Вы можете создать свой собственный поток, но я сомневаюсь, что вы действительно хотите пойти по этому маршруту.

Таким образом, хотя это не ответ, я бы что-то вроде этого, если вы хотите сэкономить на некоторых тактах:

IntStream.range(0, 10) 
      .boxed() 
      .collect(Collectors.toMap(
       Function.identity(), 
       (x) -> IntStream.range(x * 10, x * 10 + 10) 
     )) 
1

Похоже, если один поток основан на другом потоке, чем это всегда должно иметь то же самое количество записей.

Однако я нашел паталогическое решение моей проблемы: я завернул потребителя в «GroupingConsumer». Это прекратит исходный поток, но все равно сможет быть выполнен бесконечно.

Полученный код отрезала:

// create a stream from 0 (inclusive) to infinity! 
IntStream.iterate(0, i -> i+1).boxed() 

// slow down 
.peek((i) -> {try {Thread.sleep(50);} catch (InterruptedException e) {}}) 

// terminate the stream of single items (ungrouped) 
.forEach(

    // create a wrap-around 
    GroupingConsumer.create(

     // define the grouping rule 
     i -> i/10, 

     // the wrapped consumer 
     System.out::println 
)); 

GroupingConsumer класс:

import java.util.AbstractMap.SimpleEntry; 
import java.util.ArrayList; 
import java.util.List; 
import java.util.Map.Entry; 
import java.util.function.Consumer; 
import java.util.function.Function; 

/** 
* Forwards a group of items, whenever the grouping-key changes 
* 
* @param <K> the type of the grouping key 
* @param <T> the type of the single entries 
*/ 
class GroupingConsumer<K, T> implements Consumer<K> { 

    private Function<K, T> keyCalculator; 
    private Consumer<Entry<T, List<K>>> consumer; 

    Entry<T, List<K>> currentGroup; 

    /** 
    * Wraps your consumer, so that it will get groups of items instead of single items. 
    * 
    * @param keyCalculator the "grouping by" 
    * @param consumer your consumer, that will be called less frequently 
    * @return the wrapped consumer 
    */ 
    public static <K, T> GroupingConsumer<K,T> create(Function<K, T> keyCalculator, Consumer<Entry<T, List<K>>> consumer) { 
     GroupingConsumer<K, T> groupingConsumer = new GroupingConsumer<K, T>(); 
     groupingConsumer.consumer = consumer; 
     groupingConsumer.keyCalculator = keyCalculator; 
     return groupingConsumer; 
    } 

    @Override 
    public void accept(K nextValue) { 
     T key = keyCalculator.apply(nextValue); 

     boolean newGroupRequired = false; 

     if (currentGroup == null) 
      newGroupRequired = true; 
     else if (!currentGroup.getKey().equals(key)) { 
      newGroupRequired = true; 
      consumer.accept(currentGroup); 
     } 

     if (newGroupRequired) 
      currentGroup = new SimpleEntry<T, List<K>>(key, new ArrayList<K>()); 
     currentGroup.getValue().add(nextValue); 
    } 
} 
0

Вы можете думать массив как карты с ключом типа примитивного int, с той лишь разницей, что вместо того, чтобы искать значение с помощью map.get(i) вы посмотрите значение через myArray[i]. Используя массив для группировки массивов, вы также можете избежать бокса, как вы просили. Вот решение, которое дает похожие результаты без бокса.

int[][] results = IntStream.iterate(0, i -> i + 10) 
      .limit(10) 
      .mapToObj(i -> (int[]) IntStream.range(i, i + 10).toArray()) 
      .toArray(int[][]::new); 

    System.out.println(Arrays.deepToString(results)); 
Смежные вопросы