一個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
- 原生js實現的獲取當前元素的上一個元素節點JS
- Single Number 陣列中除了某個元素出現一次,其他都出現兩次,找出這個元素陣列
- 巧妙利用快速排序法的原理求一個陣列中的第10大元素排序陣列
- javascript如何實現複製克隆一個dom元素節點JavaScript
- 如何在mysql中實現自然排序MySql排序
- js實現的在li元素列表的任意位置插入一個新的li元素JS
- jquery實現的獲取當前元素的上一個元素程式碼例項jQuery
- C#實現一個萬物皆可排序的佇列C#排序佇列
- javascript實現的對陣列每一個元素都執行一個函式JavaScript陣列函式
- 用Java實現Stream流處理中的滑窗Java
- 統計陣列元素中每個元素出現的次數陣列
- 一個排序的有界的併發Buffer佇列Java實現排序佇列Java
- Three.js中實現一個OBBHelperJS
- 判斷一個元素是否是另一個元素的子元素或者父元素
- javascript實現的獲取下一個li元素程式碼例項JavaScript
- 點選按鈕實現隱藏一個元素程式碼例項
- 13萬字詳細分析JDK中Stream的實現原理JDK
- <qsort實現一個通用的氣泡排序,排序各種型別的資料詳解>排序型別
- 如何統計一列數中每個元素出現的次數
- 求Matlab矩陣中各個不同元素或者某個元素出現的次數Matlab矩陣
- js實現未知寬高的元素在指定元素中垂直水平居中JS
- 給定一個非空整數陣列,除了某個元素只出現一次以外,其餘每個元素均出現兩次。找出那個只出現了一次的元素。陣列
- easyui tree 預設選中第一個元素UI
- 實現堆排序排序
- java原始碼學習-SpliteratorJava原始碼
- 把 14 億中國人都拉到一個微信群在技術上能實現嗎?
- jquery使用一個按鈕實現控制元素的顯示與隱藏jQuery
- 如何將一個陣列中的元素插入另一個陣列陣列
- asp.net 實現獲取一個集合陣列中出現次數最多的元素ASP.NET陣列
- css3實現多個元素依次顯示CSSS3
- js動態在一個元素中新增另一個元素JS
- c語言 - 模仿qsort的功能實現一個通用的氣泡排序C語言排序