如何在 java 中随机化 Hashmap 中的相同值
How to randomize the same values in Hashmap in java
Map<Integer, BigDecimal> vendorRating = new HashMap<>();
List<Integer> sortedList = new LinkedList<>();
vendorRating 有值 (11=>4,12=>3.5,13=>3,14=>3.5,15=>4,16=>5)
我想根据值对键进行排序,并将相同的值打乱。
输出应该像 [16,11,15,12,14,13], [16,15,11,14,12,13],[16,15,11,12,14,13] , [16,11,15,14,12,13]
我试过如下,这对排序有效,但我不知道我要洗牌相同的值。
vendorRating.entrySet().stream().sorted(Map.Entry.comparingByValue(Comparator.reverseOrder()))
.forEachOrdered(
x -> sortedList.addAll(Collections.singleton(x.getKey()))
);
假设您的地图如下:
Map<Integer, BigDecimal> vendorRating = Map.of( 11, BigDecimal.valueOf(4),
12, BigDecimal.valueOf(3.5),
13, BigDecimal.valueOf(3),
14, BigDecimal.valueOf(3.5),
15, BigDecimal.valueOf(4),
16, BigDecimal.valueOf(5));
您首先需要一个比较器来按需要按降序排序:
Comparator<Map.Entry<Integer, BigDecimal>> comp = Map.Entry.comparingByValue();
在流中使用上述比较器,然后您可以使用 Collectors.groupingBy
对具有相同值的条目进行分组以生成 Map<BigDecimal,List<Integer>>
Map<BigDecimal,List<Integer>> grouped =
vendorRating.entrySet()
.stream()
.sorted(comp.reversed())
.collect(Collectors.groupingBy(Map.Entry::getValue, LinkedHashMap::new,
Collectors.mapping(Map.Entry::getKey, Collectors.toList())));
System.out.println(grouped);
//output: {5=[16], 4=[11, 15], 3.5=[12, 14], 3=[13]}
由于您似乎只对原始地图的键感兴趣,而不是 BigDecimal 值,因此我将在下面仅使用上述地图 grouped.values()
的值,即 [[16], [11, 15], [12, 14], [13]]
有趣的部分来了。现在你需要生成每个列表的所有排列,这不是一项微不足道的任务,但可以自己编写一个算法来做到这一点。但是像 Guava、Apache commons 这样的库已经有这样的功能了。我建议使用库而不是实现排列生成算法。我将使用 combinatoricslib3,我发现它在处理流时非常方便。
Maven 依赖:
<dependency>
<groupId>com.github.dpaukov</groupId>
<artifactId>combinatoricslib3</artifactId>
<version>3.3.2</version>
</dependency>
正如您在上面链接页面中使用 combinatoricslib3 看到的示例,您可以非常轻松地生成排列,语法也很简单,生成一些字符串排列的示例
Generator.permutation("apple", "orange", "cherry")
.simple()
.stream()
.forEach(System.out::println);
//会输出
[apple, orange, cherry]
[apple, cherry, orange]
[cherry, apple, orange]
[cherry, orange, apple]
[orange, cherry, apple]
[orange, apple, cherry]
应用于您的用例,生成每个子列表的排列可能看起来像
grouped.values().stream()
.map(list -> Generator.permutation(list).simple().stream().collect(Collectors.toList()))
.collect(Collectors.toList()).forEach(System.out::println);
会给你:
[[16]]
[[15, 11], [11, 15]]
[[12, 14], [14, 12]]
[[13]]
接近您想要的最终结果,但还差得远。您现在需要一次从每个子列表中选择一个元素以获得最终结果,这与生成列表的笛卡尔积相同。幸运的是,combinatoricslib3 也可以做到这一点。但我确信像 Guava 这样的其他库也有相同的实现。语法就像上面一样非常简单。如果您需要更多信息,请查看他们的示例。
首先将中间结果存储在列表列表中:
List<List<List<Integer>>> perms = grouped.values().stream()
.map(list -> Generator.permutation(list)
.simple().stream()
.collect(Collectors.toList()))
.collect(Collectors.toList());
//and generating the cartasian product
Generator.cartesianProduct(perms)
.stream()
.forEach(System.out::println);
//should produce something like:
[[16], [15, 11], [14, 12], [13]]
[[16], [15, 11], [12, 14], [13]]
[[16], [11, 15], [14, 12], [13]]
[[16], [11, 15], [12, 14], [13]]
这几乎就是您的最终结果。您只需流式传输内部列表和平面图即可将它们收集到一个列表中:
Generator.cartesianProduct(perms)
.stream()
.map(lili -> lili.stream().flatMap(List::stream).collect(Collectors.toList()))
.collect(Collectors.toList())
.forEach(System.out::println);
最终将带您到达目的地:
[16, 15, 11, 14, 12, 13]
[16, 15, 11, 12, 14, 13]
[16, 11, 15, 14, 12, 13]
[16, 11, 15, 12, 14, 13]
我将整个任务分解成更小的步骤,以便于解释。如果您对存储中间结果不感兴趣,而只对最终输出感兴趣,您可以内联这些步骤并一次性完成。工作演示:
import java.math.BigDecimal;
import java.util.Comparator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import org.paukov.combinatorics3.Generator;
public class Example {
public static void main(String[] args) {
Map<Integer, BigDecimal> vendorRating = Map.of( 11, BigDecimal.valueOf(4),
12, BigDecimal.valueOf(3.5),
13, BigDecimal.valueOf(3),
14, BigDecimal.valueOf(3.5),
15, BigDecimal.valueOf(4),
16, BigDecimal.valueOf(5));
Comparator<Map.Entry<Integer, BigDecimal>> comp = Map.Entry.comparingByValue();
List<List<Integer>> result =
Generator.cartesianProduct(
vendorRating.entrySet()
.stream()
.sorted(comp.reversed())
.collect(Collectors.groupingBy(Map.Entry::getValue, LinkedHashMap::new,
Collectors.mapping(Map.Entry::getKey, Collectors.toList())))
.values().stream()
.map(list -> Generator.permutation(list).simple().stream().collect(Collectors.toList()))
.collect(Collectors.toList())
).stream()
.map(lili -> lili.stream().flatMap(List::stream).collect(Collectors.toList()))
.collect(Collectors.toList());
result.forEach(System.out::println);
}
}
输出
[16, 15, 11, 14, 12, 13]
[16, 15, 11, 12, 14, 13]
[16, 11, 15, 14, 12, 13]
[16, 11, 15, 12, 14, 13]
答案变得比原先想象的要长得多。这是长的土豆post
System.out.println("Potato");
Map<Integer, BigDecimal> vendorRating = new HashMap<>();
List<Integer> sortedList = new LinkedList<>();
vendorRating 有值 (11=>4,12=>3.5,13=>3,14=>3.5,15=>4,16=>5)
我想根据值对键进行排序,并将相同的值打乱。
输出应该像 [16,11,15,12,14,13], [16,15,11,14,12,13],[16,15,11,12,14,13] , [16,11,15,14,12,13]
我试过如下,这对排序有效,但我不知道我要洗牌相同的值。
vendorRating.entrySet().stream().sorted(Map.Entry.comparingByValue(Comparator.reverseOrder()))
.forEachOrdered(
x -> sortedList.addAll(Collections.singleton(x.getKey()))
);
假设您的地图如下:
Map<Integer, BigDecimal> vendorRating = Map.of( 11, BigDecimal.valueOf(4),
12, BigDecimal.valueOf(3.5),
13, BigDecimal.valueOf(3),
14, BigDecimal.valueOf(3.5),
15, BigDecimal.valueOf(4),
16, BigDecimal.valueOf(5));
您首先需要一个比较器来按需要按降序排序:
Comparator<Map.Entry<Integer, BigDecimal>> comp = Map.Entry.comparingByValue();
在流中使用上述比较器,然后您可以使用 Collectors.groupingBy
对具有相同值的条目进行分组以生成 Map<BigDecimal,List<Integer>>
Map<BigDecimal,List<Integer>> grouped =
vendorRating.entrySet()
.stream()
.sorted(comp.reversed())
.collect(Collectors.groupingBy(Map.Entry::getValue, LinkedHashMap::new,
Collectors.mapping(Map.Entry::getKey, Collectors.toList())));
System.out.println(grouped);
//output: {5=[16], 4=[11, 15], 3.5=[12, 14], 3=[13]}
由于您似乎只对原始地图的键感兴趣,而不是 BigDecimal 值,因此我将在下面仅使用上述地图 grouped.values()
的值,即 [[16], [11, 15], [12, 14], [13]]
有趣的部分来了。现在你需要生成每个列表的所有排列,这不是一项微不足道的任务,但可以自己编写一个算法来做到这一点。但是像 Guava、Apache commons 这样的库已经有这样的功能了。我建议使用库而不是实现排列生成算法。我将使用 combinatoricslib3,我发现它在处理流时非常方便。
Maven 依赖:
<dependency>
<groupId>com.github.dpaukov</groupId>
<artifactId>combinatoricslib3</artifactId>
<version>3.3.2</version>
</dependency>
正如您在上面链接页面中使用 combinatoricslib3 看到的示例,您可以非常轻松地生成排列,语法也很简单,生成一些字符串排列的示例
Generator.permutation("apple", "orange", "cherry")
.simple()
.stream()
.forEach(System.out::println);
//会输出
[apple, orange, cherry]
[apple, cherry, orange]
[cherry, apple, orange]
[cherry, orange, apple]
[orange, cherry, apple]
[orange, apple, cherry]
应用于您的用例,生成每个子列表的排列可能看起来像
grouped.values().stream()
.map(list -> Generator.permutation(list).simple().stream().collect(Collectors.toList()))
.collect(Collectors.toList()).forEach(System.out::println);
会给你:
[[16]]
[[15, 11], [11, 15]]
[[12, 14], [14, 12]]
[[13]]
接近您想要的最终结果,但还差得远。您现在需要一次从每个子列表中选择一个元素以获得最终结果,这与生成列表的笛卡尔积相同。幸运的是,combinatoricslib3 也可以做到这一点。但我确信像 Guava 这样的其他库也有相同的实现。语法就像上面一样非常简单。如果您需要更多信息,请查看他们的示例。
首先将中间结果存储在列表列表中:
List<List<List<Integer>>> perms = grouped.values().stream()
.map(list -> Generator.permutation(list)
.simple().stream()
.collect(Collectors.toList()))
.collect(Collectors.toList());
//and generating the cartasian product
Generator.cartesianProduct(perms)
.stream()
.forEach(System.out::println);
//should produce something like:
[[16], [15, 11], [14, 12], [13]]
[[16], [15, 11], [12, 14], [13]]
[[16], [11, 15], [14, 12], [13]]
[[16], [11, 15], [12, 14], [13]]
这几乎就是您的最终结果。您只需流式传输内部列表和平面图即可将它们收集到一个列表中:
Generator.cartesianProduct(perms)
.stream()
.map(lili -> lili.stream().flatMap(List::stream).collect(Collectors.toList()))
.collect(Collectors.toList())
.forEach(System.out::println);
最终将带您到达目的地:
[16, 15, 11, 14, 12, 13]
[16, 15, 11, 12, 14, 13]
[16, 11, 15, 14, 12, 13]
[16, 11, 15, 12, 14, 13]
我将整个任务分解成更小的步骤,以便于解释。如果您对存储中间结果不感兴趣,而只对最终输出感兴趣,您可以内联这些步骤并一次性完成。工作演示:
import java.math.BigDecimal;
import java.util.Comparator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import org.paukov.combinatorics3.Generator;
public class Example {
public static void main(String[] args) {
Map<Integer, BigDecimal> vendorRating = Map.of( 11, BigDecimal.valueOf(4),
12, BigDecimal.valueOf(3.5),
13, BigDecimal.valueOf(3),
14, BigDecimal.valueOf(3.5),
15, BigDecimal.valueOf(4),
16, BigDecimal.valueOf(5));
Comparator<Map.Entry<Integer, BigDecimal>> comp = Map.Entry.comparingByValue();
List<List<Integer>> result =
Generator.cartesianProduct(
vendorRating.entrySet()
.stream()
.sorted(comp.reversed())
.collect(Collectors.groupingBy(Map.Entry::getValue, LinkedHashMap::new,
Collectors.mapping(Map.Entry::getKey, Collectors.toList())))
.values().stream()
.map(list -> Generator.permutation(list).simple().stream().collect(Collectors.toList()))
.collect(Collectors.toList())
).stream()
.map(lili -> lili.stream().flatMap(List::stream).collect(Collectors.toList()))
.collect(Collectors.toList());
result.forEach(System.out::println);
}
}
输出
[16, 15, 11, 14, 12, 13]
[16, 15, 11, 12, 14, 13]
[16, 11, 15, 14, 12, 13]
[16, 11, 15, 12, 14, 13]
答案变得比原先想象的要长得多。这是长的土豆post
System.out.println("Potato");