2017-02-15 87 views
1

地图的特定条目和它的索引我有以下条目Map<String, Boolean>从获得使用Java lambda表达式

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

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

我可以遍历地图和获取这些值:

int itr=0; 
for(Iterator<Map.Entry<String, Boolean>> entries = map.entrySet().iterator; entries.hasNext();) { 
    itr++; 
    Map.Entry<String, Boolean> entry = entries.next(); 
    if(entry.getValue()) { 
     name = entry.getKey(); 
     index = itr; 
    } 
} 

不过,我在看一个相同的lambda表达式。

+5

'HashMap'不维护其元素的顺序! – user1803551

+2

@ user1639485通过索引您可能意味着您有多少条目*在获得价值之前已*见过*如果是这样,这是不可靠的,因为当地图的某个重新大小发生时,该条目可以移动。除非你的地图保留了顺序,比如'LinkedHashMap'。 – Eugene

+0

@Eugene我认为你ping了一个错误的用户,你基本上说了我说的话。 – user1803551

回答

3

那么,如果你能保证地图实际上是一个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(); 
3

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

  1. 解决方案应该是懒惰(一旦发现回答为停止迭代地图)
  2. 解决方案不应该使用迭代器明确()或spliterator()
  3. 所以lution应符合Stream API规范(特别是中间lambda不应有副作用)
  4. 解决方案不应使用第三方Stream扩展。

如果您违反#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(); 
} 
+1

这两个选项都非常好。一加。 – Eugene

+1

StreamEx是否有'takeWhile'? 'int index = StreamEx.of(map.values())。takeWhile(b - >!b).count(); String name = map.keySet()。stream().skip(index).findFirst()。orElse(null);'... – Holger

+1

@Holger,是的,这样的解决方案也是可能的,尽管它是两遍的。顺便说一下,这是一个很好的版本,因为它可以在Java 9中使用。也可以使用StreamEx'long idx = StreamEx.ofValues(map).indexOf(b-> b).orElse(-1)'。其他单通StreamEx解决方案也可能像'EntryStream.of(map).takeWhileInclusive(e - >!e.getValue())keys()。zipWith(IntStreamEx.ints()。boxed())。reduce( a,b)→b)'。 –