使用Java lambda表达式从Map获取特定条目及其索引

时间:2017-02-15 09:13:31

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

我有一个node-kmeans,其中包含以下条目:

Map<String, Boolean>

我需要找到第一个条目及其索引值为true。 在这里我应该得到汤姆和3(比如,索引从1开始)。

我可以迭代地图并获取这些值:

{‘John’:false,
 'Mike':false,
 'Tom':true,
 'Harry':false,
 'Bob': false}

但是,我正在研究一个lambda表达式。

2 个答案:

答案 0 :(得分:3)

如果你可以保证Map实际上是一个LinkedHashMap(这样它可以保留插入顺序),你可以这样做:

List<Map.Entry<String, Boolean>> l = map.entrySet().stream().collect(Collectors.toList());
    IntStream.range(0, l.size())
            .mapToObj(i -> new AbstractMap.SimpleEntry<>(i, l.get(i)))
            .filter(e -> e.getValue().getValue())
            .map(e -> new AbstractMap.SimpleEntry<>(e.getValue().getKey(), e.getKey()))
            .findFirst();

答案 1 :(得分:3)

我认为不可能满足以下所有条件:

  1. 解决方案应该是懒惰的(一旦找到答案就停止迭代地图)
  2. 解决方案不应使用显式的iterator()或spliterator()
  3. 解决方案应符合Stream API规范(特别是中间lambdas不应有副作用)
  4. 解决方案不应使用第三方Stream扩展。
  5. 如果您违反了#1,请查看@ Eugene的答案。如果您违反了#2,那么问题中的代码就很好了。如果你违反了#3,你可以这样做:

    AtomicInteger idx = new AtomicInteger();
    
    String name = map.entrySet().stream()
       .peek(e -> idx.incrementAndGet())
       .filter(Map.Entry::getValue)
       .map(Map.Entry::getKey)
       .findFirst().orElse(null);
    int itr = idx.get();
    

    如果你可以违反#4,你可以考虑使用我的免费StreamEx库:

    Map.Entry<String, Integer> entry = StreamEx.of(map.entrySet()) // (name, bool)
           .zipWith(IntStreamEx.ints().boxed()) // ((name, bool), index)
           .filterKeys(Map.Entry::getValue) // filter by bool
           .mapKeys(Map.Entry::getKey) // (name, index)
           .findFirst()
           .orElse(null);
    if(entry != null) {
        String name = entry.getKey();
        int itr = entry.getValue();
    }