函数应返回最常用姓氏的可选项(如果遇到至少两次)或者如果姓氏数相同或者用户列表为空则返回可选空
这是我提出的,但它不会返回Optional.empty
@Override
public Optional<String> getMostFrequentLastName(final List<User> users) {
return users.stream()
.map(User::getLastName)
.distinct()
.collect
(Collectors.groupingBy(
Function.identity(),
Collectors.summingInt(w -> 1)
))
.entrySet()
.stream()
.filter(stringIntegerEntry -> stringIntegerEntry.getValue() >= 2)
.sorted(Map.Entry.comparingByValue(Comparator.reverseOrder()))
.map(Map.Entry::getKey)
.findFirst();
}
这是我的测试课
public static void main(String[] args) {
Optional<String> optionalS = Stream.of(new User("name1"),
new User("name1"), new User("name2"), new User("name2"))
.map(User::getLastName)
.collect
(Collectors.groupingBy(
Function.identity(),
Collectors.counting()
))
.entrySet()
.stream()
.filter(stringIntegerEntry -> stringIntegerEntry.getValue() >= 2)
.sorted(Map.Entry.comparingByValue(Comparator.reverseOrder()))
.map(Map.Entry::getKey)
.findFirst();
System.out.println(optionalS.toString());
}
这是答案
Optional[name2]
但应该是
Optional[empty]
你可以用
Optional<String> optionalS =
Stream.of(new User("name1"), new User("name1"), new User("name2"), new User("name2"))
.collect(Collectors.groupingBy(User::getLastName, Collectors.counting()))
.entrySet()
.stream()
.filter(entry -> entry.getValue() >= 2)
.reduce((e1, e2) -> e1.getValue() < e2.getValue()? e2:
e1.getValue() > e2.getValue()? e1:
new AbstractMap.SimpleImmutableEntry<>(null, e1.getValue()))
.map(Map.Entry::getKey);
System.out.println(optionalS.toString());
获得最大价值是减少的一种形式。因为你想在一个平局的情况下得到一个空的可选项,最简单的解决方案是明确地编写简化函数,如果有的话,使用值更大的Map.Entry
,否则使用Map.Entry
密钥构造一个新的null
。
减少的结果已经是一个Optional
,如果没有元素(计数>=2
)将是空的。所以最后的map
步骤应用于Optional
。如果已经为空,则不会评估map
函数,并且生成的Optional
保持为空。如果optional不是空的,但是Map.Entry::getKey
计算为null
,则生成的可选项将为空。
在我看来,如果你有一些不同的lastNames的最大数量,你想要返回一个Optional::empty
,如下:
Map<String, Long> map =
Stream.of(new User("name1"),
new User("name1"),
new User("name2"),
new User("name2"))
.collect(Collectors.groupingBy(User::getLastName, Collectors.counting()));
map.entrySet()
.stream()
.max(Entry.comparingByValue())
.flatMap(en -> {
boolean b = map.entrySet()
.stream()
.filter(x -> !x.getKey().equals(en.getKey()))
.mapToLong(Entry::getValue)
.noneMatch(x -> x == en.getValue());
return b ? Optional.of(en.getKey()) : Optional.empty();
})
.ifPresent(System.out::println);
}
这里是我的怪物:
Optional<String> optionalS = Stream.of(
new User("name1"),
new User("name1"),
new User("name2"),
new User("name2"))
.map(User::getLastName)
.collect(
Collectors.groupingBy(
Function.identity(),
Collectors.counting()
))
.entrySet()
.stream()
.filter(stringIntegerEntry -> stringIntegerEntry.getValue() >= 2)
.collect(
Collectors.groupingBy(
Map.Entry::getValue,
Collectors.toList()
))
.entrySet()
.stream()
.sorted(Comparator.comparing(
Map.Entry::getKey,
Comparator.reverseOrder()))
.map(Map.Entry::getValue)
.findFirst()
.filter(x -> x.size() == 1)
.map(x -> x.get(0).getKey());
System.out.println(optionalS);
据我所知,你的代码创建的流解决方案
Map<String(lastname),Integer(number of occurence)>
然后过滤那个出现次数> = 2的地图,在你的测试用例中你有一个带有条目的地图:
<"name1",2>
<"name2",2>
因此按值排序仍将返回两个值。
你应该尝试创造
Map<Integer,List<String>>
这将存储出现次数 - >名称,然后过滤地图键,对它们进行降序排序,并且(在地图值中)您将获得最常见的姓氏(如果输入中有多次,则为姓氏)。
//编辑
以下简短代码片段与我的解决方案:
Map<Integer, List<String>> map = new HashMap<>();
map.put(2,Arrays.asList("name1","name2"));
Optional<String> optionalS = map
.entrySet()
.stream()
.sorted(Map.Entry.comparingByKey(Comparator.reverseOrder()))
.findFirst() //get max{map's keys}
.filter(x->x.getValue().size() == 1) //get lastname that occured only once
.map(x->x.getValue().get(0)); //get that lastname (above filter check that list has only one element) or Optional.empty if stream didn't find any
System.out.println(optionalS.toString());
我跳过了创建地图的部分。
附:您可以使用自定义比较器替换带有TreeMap的HashMap,以避免在流中进行排序。