2017-07-13 29 views
3

我的程序中有一些SQL語句含有給定ID的IN條款。問題是在某些情況下,可能會有超過1000個Ids導致Oracle與ORA-01795崩潰。過多的物品。將LongStream劃分爲最大長度的子流

所以我想把這個列表分成多個子列表。

例如:我有2403個IDS

結果將是三個列表:

  1. 0 - 999
  2. 1000 - 1999
  3. 2000至2402年

我已經寫一段可行的代碼,但看起來很糟糕。有沒有更好的解決方案來解決這個問題?也許收集器&分組或類似的東西?

我的代碼:

Map<Integer, List<Long>> result = new HashMap<>(); 
    ArrayList<Long> asList = new ArrayList<Long>(listOfIds); 
    IntStream.range(0, (listOfIds.size()/1000) + 1) 
      .forEach(partGroup -> result.put(partGroup, asList.subList(partGroup * 1000, (partGroup * 1000) + Math.min(1000, 
      asList.size() - partGroup * 1000)))); 

回答

5

短期使用第三方庫,我不認爲你可以做得更好的。我個人使用這個工具的功能,這是接近你做了什麼:

public static <T> Stream<List<T>> splitListStream(List<T> input, int batchSize) { 
    if (batchSize <= 0) 
    throw new IllegalArgumentException("batchSize must be positive (" + batchSize + ")"); 
    if (input.size() <= batchSize) return Stream.of(input); 
    return IntStream.range(0, (input.size() + batchSize - 1)/batchSize) 
      .mapToObj(i -> { 
      int from = i * batchSize; 
      int to = Math.min((i + 1) * batchSize, input.size()); 
      return input.subList(from, to); 
      }); 
} 
+0

你會闡述關於'.mapToObj'部分發生了什麼事情。再加上一個。 – Yahya

+1

@Yahya它計算下一個批次的界限 - 從我看來不言自明,並且有一個額外的步驟來避免超出列表的大小。 – assylias

1

作爲替代滾動你自己的,你可以考慮jOOL或番石榴(Iterators.partition(stream.iterator(), batchSize))。

3

你可以編寫你自己的收集器 - 這將有效地並行化。你也可以把它變成一個實用的方法。

private static <T> Collector<T, ?, List<List<T>>> partitioning(int size) { 
    class Acc { 
     int count = 0; 

     List<List<T>> list = new ArrayList<>(); 

     void add(T elem) { 
      int index = count++/size; 
      if (index == list.size()) { 
       list.add(new ArrayList<>()); 
      } 
      list.get(index).add(elem); 
     } 

     Acc merge(Acc right) { 

      List<T> lastLeftList = list.get(list.size() - 1); 
      List<T> firstRightList = right.list.get(0); 
      int lastLeftSize = lastLeftList.size(); 
      int firstRightSize = firstRightList.size(); 

      // they are both size, simply addAll will work 
      if (lastLeftSize + firstRightSize == 2 * size) { 
       list.addAll(right.list); 
       return this; 
      } 

      // last and first from each chunk are merged "perfectly" 
      if (lastLeftSize + firstRightSize == size) { 
       int x = 0; 
       while (x < firstRightSize) { 
        lastLeftList.add(firstRightList.remove(x)); 
        --firstRightSize; 
       } 
       right.list.remove(0); 
       list.addAll(right.list); 
       return this; 
      } 

      right.list.stream().flatMap(List::stream).forEach(this::add); 
      return this; 
     } 

     public List<List<T>> finisher() { 
      return list; 
     } 

    } 
    return Collector.of(Acc::new, Acc::add, Acc::merge, Acc::finisher); 
} 

而且用法是:

List<List<Integer>> list = Arrays.asList(1, 3, 4, 5, 9, 8, 7) 
      .stream() 
      .parallel() 
      .collect(partitioning(3));