Java流过滤特定索引的项目

时间:2016-03-29 20:01:23

标签: java java-8 java-stream

我正在寻找一种简洁的方法来过滤掉特定索引中List中的项目。我的示例输入如下所示:

List<Double> originalList = Arrays.asList(0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0);
List<Integer> filterIndexes = Arrays.asList(2, 4, 6, 8);

我想过滤索引2468的项目。我有一个跳过跳过与索引匹配的项目的for循环,但我希望有一种简单的方法可以使用流来完成它。最终结果如下:

List<Double> filteredList = Arrays.asList(0.0, 1.0, 3.0, 5.0, 7.0, 9.0, 10.0);

3 个答案:

答案 0 :(得分:18)

您可以生成IntStream来模仿原始列表的索引,然后删除filteredIndexes列表中的索引,然后将这些索引映射到列表中的相应元素(更好方法是为索引设置HashSet<Integer>,因为它们根据定义是唯一的,因此contains是一个恒定时间操作。)

List<Double> filteredList = 
    IntStream.range(0, originalList.size())
             .filter(i -> !filterIndexes.contains(i))
             .mapToObj(originalList::get)
             .collect(Collectors.toList());

答案 1 :(得分:5)

如果您的filteredIndexes列表已预先排序,则可以避免以这种方式检查每个元素:

List<Double> filteredList = IntStream.rangeClosed(0, filterIndexes.size())
    .mapToObj(idxPos -> idxPos == 0 
           ? originalList.subList(0, filterIndexes.get(idxPos)) 
           : idxPos == filterIndexes.size() 
           ? originalList.subList(filterIndexes.get(idxPos-1)+1, originalList.size()) 
           : originalList.subList(filterIndexes.get(idxPos-1)+1, filterIndexes.get(idxPos)))
    .flatMap(List::stream)
    .collect(Collectors.toList());

这里我们创建了许多子列表,其中包含过滤索引之间的所有元素,然后将它们展平为单个最终列表。对于大输入(例如一百万个数字),这个解决方案可能比@AlexisC提出的解决方案更快。

答案 2 :(得分:2)

如果您对索引降序进行排序,则可以使用java.util.List.remove(int)删除项目。

List<Double> originalList = new ArrayList<>(Arrays.asList(0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0));
List<Integer> filterIndexes = Arrays.asList(2, 4, 6, 8);

filterIndexes.stream()

    // remove higher indixes first, because each remove affects all indexes to the right
    .sorted(Comparator.reverseOrder())

    // make sure to use remove(int) not remove(Object) in java.util.List to use indexes
    .mapToInt(Integer::intValue)

    // remove each index
    .forEach(originalList::remove);

// print results
originalList.forEach(System.out::println);