2017-02-15 82 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)'。 –