一個Spliterator能實現Stream中元素排序
如果我們有一個List <Stream <T >>,每個流都具有排序元素,那麼如何生成一個排序後的Stream <T>,一次從每個流中獲取一個?javaspecialists的文章將展示如何使用Stream API並編寫我們自己的MergingSortedSpliterator。
import java.util.*; import java.util.function.*; import java.util.stream.*; public class MergingSortedSpliterator<T> implements Spliterator<T> { private final List<Spliterator<T>> spliterators; private final List<Iterator<T>> iterators; private final int characteristics; private final Object[] nextItem; private final static Object START_OF_STREAM = new Object(); private final static Object END_OF_STREAM = new Object(); private final Comparator<? super T> comparator; private final boolean distinct; public MergingSortedSpliterator(Collection<Stream<T>> streams) { this.spliterators = streams.stream() .map(Stream::spliterator) .collect(Collectors.toList()); if (!spliterators.stream().allMatch( spliterator -> spliterator.hasCharacteristics(SORTED))) throw new IllegalArgumentException("Streams must be sorted"); Comparator<? super T> comparator = spliterators.stream() .map(Spliterator::getComparator) .reduce(null, (a, b) -> { if (Objects.equals(a, b)) return a; else throw new IllegalArgumentException( "Mismatching comparators " + a + " and " + b); }); this.comparator = Objects.requireNonNullElse(comparator, (Comparator<? super T>) Comparator.naturalOrder()); this.characteristics = spliterators.stream() .mapToInt(Spliterator::characteristics) .reduce((ch1, ch2) -> ch1 & ch2) .orElse(0); this.distinct = hasCharacteristics(DISTINCT); // setting up iterators this.iterators = spliterators.stream() .map(Spliterators::iterator) .collect(Collectors.toList()); nextItem = new Object[streams.size()]; Arrays.fill(nextItem, START_OF_STREAM); } private Object fetchNext(Iterator<T> iterator) { return iterator.hasNext() ? iterator.next() : END_OF_STREAM; } public boolean tryAdvance(Consumer<? super T> action) { Objects.requireNonNull(action, "action==null"); if (nextItem.length == 0) return false; T smallest = null; int smallestIndex = -1; for (int i = 0; i < nextItem.length; i++) { Object o = nextItem[i]; if (o == START_OF_STREAM) nextItem[i] = o = fetchNext(iterators.get(i)); if (o != END_OF_STREAM) { T t = (T) o; if (smallest == null || comparator.compare(t, smallest) < 0) { smallest = t; smallestIndex = i; } } } // smallest might be null if the stream contains nulls if (smallestIndex == -1) return false; if (distinct) { for (int i = 0; i < nextItem.length; i++) { Iterator<T> iterator = iterators.get(i); while (nextItem[i] != END_OF_STREAM && comparator.compare(smallest, (T) nextItem[i]) == 0) { nextItem[i] = fetchNext(iterator); } } } else { nextItem[smallestIndex] = fetchNext(iterators.get(smallestIndex)); } action.accept(smallest); return true; } public Spliterator<T> trySplit() { // never split - parallel not supported return null; } public long estimateSize() { return spliterators.stream() .mapToLong(Spliterator::estimateSize) .reduce((ch1, ch2) -> { long result; if ((result = ch1 + ch2) < 0) result = Long.MAX_VALUE; return result; }) .orElse(0); } public int characteristics() { return characteristics; } public Comparator<? super T> getComparator() { return comparator; } } |
下面是呼叫測試客戶端程式碼:
import java.util.*; import java.util.concurrent.*; import java.util.stream.*; public class SortedStreamOfSortedStreams { private static final int SIZE = 5; public static void main(String... args) { List<Stream<Integer>> streams = List.of( generateSortedRandom(SIZE), generateSortedRandom(SIZE), generateSortedRandom(SIZE), generateSortedRandom(SIZE) ); Stream<Integer> numbers = StreamSupport.stream( new MergingSortedSpliterator<>(streams), false ); numbers.forEach(System.out::println); } private static Stream<Integer> generateSortedRandom(int size) { return ThreadLocalRandom.current().ints(size, 0, size * 4) .parallel() .sorted() .boxed(); } } |
輸出結果:
0 0 2 4 4 5 6 6 7 10 10 11 12 15 16 17 18 18 19 19 |
它比並行排序的flatMap甚至更快。
相關文章
- Collection如何轉成stream以及Spliterator對其操作的實現
- 在排序陣列中查詢元素的第一個和最後一個位置排序陣列
- 歸併排序與快速排序的一個實現與理解排序
- 34. 在排序陣列中查詢元素的第一個和最後一個位置(中)排序陣列
- Java stream判斷列表是否包含某幾個元素/重複元素Java
- C#實現一個萬物皆可排序的佇列C#排序佇列
- 統計陣列元素中每個元素出現的次數陣列
- 用Java實現Stream流處理中的滑窗Java
- <qsort實現一個通用的氣泡排序,排序各種型別的資料詳解>排序型別
- 給定一個非空整數陣列,除了某個元素只出現一次以外,其餘每個元素均出現兩次。找出那個只出現了一次的元素。陣列
- Three.js中實現一個OBBHelperJS
- 13萬字詳細分析JDK中Stream的實現原理JDK
- list集合按元素的某一屬性排序排序
- Selenium實現元素定位
- c語言 - 模仿qsort的功能實現一個通用的氣泡排序C語言排序
- php實現 歸併排序,快速排序PHP排序
- java原始碼學習-SpliteratorJava原始碼
- 如何實現一個簡易版的 Spring - 如何實現 AOP(中)Spring
- 探討把一個元素從它所在的div 拖動到另一個div內的實現方法
- 347前 K 個高頻元素(雜湊表、堆排序)排序
- 把 14 億中國人都拉到一個微信群在技術上能實現嗎?
- Java排行榜中多級排序的一種正確實現方式Java排序
- 一篇夯實一個知識點系列--python實現十大排序演算法Python排序演算法
- java實現快速排序Java排序
- Swift實現快速排序Swift排序
- js 實現堆排序JS排序
- GO 實現快速排序Go排序
- 快速排序(java實現)排序Java
- 快速排序 java實現排序Java
- Go實現氣泡排序和快速排序Go排序
- HTML 中塊級元素設定 height:100% 的實現HTML
- php實現 氣泡排序,插入排序,選擇排序PHP排序
- 實現一個promisePromise
- Java 列表元素自定義排序Java排序
- 在 Flutter 中實現一個無限輪播Flutter
- 如何實現一個能精確同步滾動的Markdown編輯器
- 在一個元素上:hover,改變另一個元素的css屬性CSS
- 一個 key 能儲存多個 value 的 map --- 自定義的 MultiValueMap,實現 Map 介面