【问题标题】:How to get element index when using a stream to traverse a list?使用流遍历列表时如何获取元素索引?
【发布时间】:2017-09-30 17:42:05
【问题描述】:

我想在遍历列表使用 lambda 时获取索引。

例如:

List<CheckBox> checkBoxes = null;

checkBoxes.forEach(checkBox -> {
      if (checkBox.isSelected()) {
          sb.append("index"); //I want to get checkbox index here
          sb.append(",");
      }
});

编辑checkBoxes = null; 只是一个占位符,但一旦我开始编写一些代码就会正确使用。

【问题讨论】:

  • 该代码完全会抛出Null pointer Exception
  • lambda 不适用于所有情况,但使用传统的 for 循环最适合您的情况。
  • 我知道。这只是一个例子。我不会在我的代码中这样写。
  • 我需要为每周重复的警报生成玉米表情。

标签: java android lambda java-8 java-stream


【解决方案1】:

试试

List<CheckBox> checkBoxes = null;
checkBoxes.forEach(checkBox -> {
    if(checkBox.isSelected()){
        index = checkBoxes.indexOf(checkBox);
        sb.append(index); //I want to get checkbox index here
        sb.append(",");
    }
});

【讨论】:

    【解决方案2】:

    试试这个,使用IntStream:

    List<CheckBox> checkBoxes = //data
    
    IntStream.range(0, checkBoxes.size())
    .forEach(i -> {
       CheckBox checkbox = checkBoxes.get(i); 
        if(checkbox.isSelected()){
            sb.append(i);
            sb.append(",");
        }
    });
    

    【讨论】:

    • 请保持您的 lambda 简短,并且可能像一个班轮一样
    【解决方案3】:

    lambda 并非适用于所有情况,我建议使用传统的 for 循环。

    for(int i = 0; i < checkBoxes.size(); i++){
        if(checkBoxes.get(i).isSelected()){
             // simply use "i" in this case for the index
             sb.append(i); //I want to get checkbox index here
             sb.append(",");
         }
    }
    

    但是,如果您坚持使用流,则需要使用List 提供的indexOf 方法来获取该特定元素的相应索引。

    checkBoxes.forEach(checkBox ->{
        if(checkBox.isSelected()){
              int indexValue = checkBoxes.indexOf(checkBox);
              sb.append(indexValue); //I want to get checkbox index here
              sb.append(",");
        }
    });
    

    【讨论】:

      【解决方案4】:

      我会这样做。

      在列表的索引上运行IntStream。然后根据是否选中相应的复选框过滤索引。然后将索引值(int映射 到索引值的String 表示中。最后,将字符串收集成一个结果字符串,用逗号分隔。

      代码:

          String result = IntStream.range(0, checkBoxes.size())
                                   .filter(i -> checkBoxes.get(i).isSelected())
                                   .mapToObj(String::valueOf)
                                   .collect(Collectors.joining(","));
      

      输出将类似于

          0,1,3,6
      

      取决于实际选中的复选框。

      我会避免使用forEach,因为您可以通过转换值而不是执行副作用来实现目标。我也会避免使用List.indexOf,因为它会线性地搜索列表以查找所需的项目。如果你只有几个复选框,这没什么大不了的,但如果你有很多,O(N^2) 的增长会导致性能受到影响。

      【讨论】:

      • 你的回答对我来说很有价值,但让我头疼的是它需要 API 24。
      【解决方案5】:

      几个未提出的选项:

      1.. 使用包装流和一对:

      public static <T> Stream<Pair<Integer, T>> createIndexedStream(Stream<T> stream) {
          AtomicInteger count = new AtomicInteger();
          return stream.map(t -> Pair.of(count.getAndIncrement(), t));
      }
      

      使用示例:

          List<String> list = List.of("a", "b", "c");
          createIndexedStream(list.stream())
                  .forEach(pair -> System.out.println("Index: " + pair.getLeft() + ". Value: " + pair.getRight()));
      

      2.. 外部计数器:

      AtomicInteger count = new AtomicInteger();
      list.stream().map(s -> Pair.of(count.getAndIncrement(), s))
              .forEach(pair -> System.out.println("Index: " + pair.getLeft() + ". Value: " + pair.getRight()));
      

      AtomicInteger count = new AtomicInteger();
      list.stream().forEach(s -> System.out.println("Index: " + count.getAndIncrement() + ". Value: " + s));
      

      * 最好使用 BiFunction/BiConsumer/等。但我不知道怎么做。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2018-03-06
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-08-05
        • 2011-01-11
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多