使用 Java Stream API 从给定用户列表中计算最频繁姓氏的方法
Method to calculate the most frequent last name from list of given users with Java Stream API
函数应该return可选最频繁的姓氏(如果至少遇到两次)或者如果姓氏数量相同或用户列表为空则可选为空
这是我想出来的,但不是 return 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();
}
这是我的测试class
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());
}
Here is the awnser
Optional[name2]
但应该是
Optional[empty]
据我了解您在流中的解决方案是您的代码创建的
Map<String(lastname),Integer(number of occurence)>
然后过滤出现次数 >=2 的地图,在您的测试用例中,您有带有条目的地图:
<"name1",2>
<"name2",2>
因此按值排序仍将 return 两个值。
你应该尝试创建
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());
我跳过了创建地图的部分。
P.S。您可以使用自定义比较器将 HashMap 替换为 TreeMap 以避免在流中排序。
这是我的怪物:
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);
在我看来,如果你有相同数量的最大的一些不同的姓氏,你想要return一个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"))
.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
保持为空。如果可选值不为空,但 Map.Entry::getKey
的计算结果为 null
,结果可选值将为空。
函数应该return可选最频繁的姓氏(如果至少遇到两次)或者如果姓氏数量相同或用户列表为空则可选为空
这是我想出来的,但不是 return 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();
}
这是我的测试class
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());
}
Here is the awnser
Optional[name2]
但应该是
Optional[empty]
据我了解您在流中的解决方案是您的代码创建的
Map<String(lastname),Integer(number of occurence)>
然后过滤出现次数 >=2 的地图,在您的测试用例中,您有带有条目的地图:
<"name1",2>
<"name2",2>
因此按值排序仍将 return 两个值。
你应该尝试创建
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());
我跳过了创建地图的部分。
P.S。您可以使用自定义比较器将 HashMap 替换为 TreeMap 以避免在流中排序。
这是我的怪物:
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);
在我看来,如果你有相同数量的最大的一些不同的姓氏,你想要return一个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"))
.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
保持为空。如果可选值不为空,但 Map.Entry::getKey
的计算结果为 null
,结果可选值将为空。