Java 8 Stream,如何获得前N个计数?
内容导读
互联网集市收集整理的这篇技术教程文章主要介绍了Java 8 Stream,如何获得前N个计数?,小编现在分享给大家,供广大互联网技能从业者学习和参考。文章包含3912字,纯文字阅读大概需要6分钟。
内容图文
![Java 8 Stream,如何获得前N个计数?](/upload/InfoBanner/zyjiaocheng/812/599360197c1649f182ce3daebb9d5f0b.jpg)
我需要你的建议来简化下面的代码.我有一个玩家列表,其中包含赢得的游戏ID.我想从这个列表中提取2个最佳玩家(2个拥有更多匹配ID的玩家)
提取后,我必须返回初始列表以执行其他操作.
我认为可以在优化或阅读方面改进此代码.如果你能帮助我.
public class PlayerStatistics {
int id
String name;
int idMatchWon; // key from Match
// getter , setter
}
public static void main(String[] args) throws Exception {
List<PlayerStatistics> _players = new ArrayList<PlayerStatistics>();
_players.add(initialize(1,'John',4));
_players.add(initialize(2,'Teddy',2));
_players.add(initialize(3,'Kevin',3));
// How to get Top 2
List<PlayerStatistics> _top2Players = extractTop2Players(_players);
}
private List<PlayerStatistics> extractTop2Players (List<PlayerStatistics> _list) {
List<PlayerStatistics> _topPlayers = new ArrayList<PlayerStatistics>();
// 1. Group and count
Map<String, Long> _players = _list
.stream()
.filter(x -> (!"".equals(x.getName()) && x.getName()!= null) )
.collect(
Collectors.groupingBy(
PlayerStatistics::getName, Collectors.counting()
)
);
;
// 2 Best Palyers
Set<String> _sortedPlayers = _players.entrySet().stream()
.sorted(Map.Entry.comparingByValue(Collections.reverseOrder()))
.limit(2)
.map(Entry::getKey)
.collect(Collectors.toSet())
;
// 3. Rebuild list
_topPlayers = _list
.stream()
.filter(x -> _sortedPlayers.contains(x.getName()))
.collect(Collectors.toList())
;
return _topPlayers;
}
private PlayerStatistics initialize (int id, String name, int year, int month, int won, int lost) {
return
new PlayerStatistics()
.withId(id)
.withName(name)
.withIdMatchWon(won)
);
}
解决方法:
首先,让我们说明你的代码绝对正确.它做了需要做的事情,甚至通过使用集合进行优化.不过,它可以通过两种方式进一步改进:
>时间复杂度:您正在对整个数据集进行排序,其时间复杂度为O(mlogm),m是您最初的玩家列表的大小.您将立即获取列表中的前N个元素,其中N<<米
下面我展示了一种将算法的时间复杂度提高到O(mlogN)的方法,这意味着在你的特定情况下它会变成O(m)(这是因为N = 2,所以logN = log2 = 1).
>您正在遍历数据集3次:首先,您正在迭代玩家列表以创建计数地图,然后您正在迭代此地图以获得前N个玩家的集合,最后您正在迭代列表玩家再次检查每个玩家是否属于前N名玩家的集合.
这可以改进,只对数据集执行2次传递:第一次创建计数图(类似于您已经完成的),另一次创建一个只保留前N个元素的结构,排序按递减计数,结果准备好在遍历完成后返回.
重要提示:下面的解决方案要求您的PlayerStatistics类一致地实现hashCode和equals方法.
首先,我们有一个通用方法topN(毫不奇怪)从任何给定的地图中提取前N个元素.它通过按值比较它的条目,降序来实现这一点(在这个版本中,值V必须是可比较的< V>,但是通过提供自定义比较器< V>,可以容易地扩展该算法以支持不实现Comparable< V>的值. V>):
public static
<K, V extends Comparable<? super V>, T extends Comparable<? super T>>
Collection<K>
topN(
Map<K, V> map,
int N,
Function<? super K, ? extends T> tieBreaker) {
TreeMap<Map.Entry<K, V>, K> topN = new TreeMap<>(
Map.Entry.<K, V>comparingByValue() // by value descending, then by key
.reversed() // to allow entries with duplicate values
.thenComparing(e -> tieBreaker.apply(e.getKey())));
map.entrySet().forEach(e -> {
topN.put(e, e.getKey());
if (topN.size() > N) topN.pollLastEntry();
});
return topN.values();
}
topN TreeMap在这里表现为大小为N的priority queue(尽管我们加起来为N 1个元素).首先我们将条目放入topN映射,然后,如果映射有超过N个条目,我们立即调用它上面的pollLastEntry方法,这将删除具有最低优先级的条目(根据TreeMap的键的顺序) .这保证了在遍历时,topN映射将仅包含已经排序的前N个条目.
请注意,我正在使用比较器,首先对TreeMap< Map.Entry< K,V>,K>进行排序.通过值V按降序排列,然后按键K.这是在函数<?的帮助下实现的.超级K,?延伸T> tieBreaker函数,它将每个密钥K转换为必须是Comparable< T>的值T.所有这些允许地图包含具有重复值V的条目,而不需要键K也是可比较的< K>.
最后,您将使用以上方法:
Map<PlayerStatistics, Long> counts = yourInitialListOfPlayers.stream()
.filter(x -> !"".equals(x.getName()) && x.getName() != null)
.collect(Collectors.groupingBy(x -> x, Collectors.counting()));
Collection<PlayerStatistics> top2 = topN(counts, 2, PlayerStatistics::getName);
内容总结
以上是互联网集市为您收集整理的Java 8 Stream,如何获得前N个计数?全部内容,希望文章能够帮你解决Java 8 Stream,如何获得前N个计数?所遇到的程序开发问题。 如果觉得互联网集市技术教程内容还不错,欢迎将互联网集市网站推荐给程序员好友。
内容备注
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 gblab@vip.qq.com 举报,一经查实,本站将立刻删除。
内容手机端
扫描二维码推送至手机访问。