当前位置: 首页 > 知识库问答 >
问题:

随机/随机比较器

公良文彬
2023-03-14

是否有任何方法可以模拟Collections.shuffle的行为,而比较器不容易受到排序算法实现的影响,以确保结果安全?

我的意思是不违反类似的合同等..

共有3个答案

穆城
2023-03-14

这是我的解决方案:

List<String> st = Arrays.asList("aaaa","bbbb","cccc");
System.err.println(st.stream().sorted((o1, o2) -> RandomUtils.nextInt(0, 2)-1).findFirst().get());
劳华灿
2023-03-14

当元素的类型未知时,与前面的答案相比,更加一般化:

public static <T> Comparator<T> shuffle() {
    final Map<Object, UUID> uniqueIds = new IdentityHashMap<>();
    return Comparator.comparing(e -> uniqueIds.computeIfAbsent(e, k -> UUID.randomUUID()));
}

也可以在流中使用:

list.stream().sorted(Streams.shuffle()).collect(Collectors.toList())

可能会以某种方式发生冲突,因此可以使用 UUIDHashSet 进行扩展以检查这种情况

亢正德
2023-03-14

在不破坏合同的情况下实现真正的“洗牌比较器”是不可能的。比较器合约的一个基本方面是结果是可重现的,因此必须固定特定比较器实例的顺序。

当然,您可以使用混洗操作预先初始化该固定顺序,并创建一个比较器来准确建立该顺序。例如

List<ElementType> ordering=new ArrayList<>(list);
Collections.shuffle(ordering);

list.sort(Comparator.comparingInt(ordering::indexOf));

尽管这有点没有意义。很明显,这个比较器不能用于包含不在排序列表中的元素的集合。

或者,您可以使用首先没有排序的值的稳定属性作为排序标准,例如哈希代码。这可以通过稳定但可随机化的转换来增强,例如

public static Comparator<String> randomOrder() {
    ThreadLocalRandom r = ThreadLocalRandom.current();
    int x = r.nextInt(), y = r.nextInt(), z = r.nextInt();
    boolean b = r.nextBoolean();
    return Comparator.comparingInt((String s) -> Integer.reverse((s.hashCode()&x)^y))
      .thenComparingInt(s -> s.length()^z)
      .thenComparing(b? Comparator.naturalOrder(): Comparator.reverseOrder());
}
List<String> list=Arrays.asList("hello", "now", "shuffle", "this", "!");
list.sort(randomOrder());
System.out.println(list);
list.sort(randomOrder());
System.out.println(list);

关键点是,每个Comparator实例代表一个随机选择但固定的排序,我们创建一个新的Comparator实例来请求不同的排序。因此,没有Comparator违反合同。

请注意,这个<code>比较器</code>看起来有点复杂,因为它必须考虑可能的哈希冲突。它将使用<code>length</code>属性(也是随机化的),然后对于具有相同哈希码和长度的<code>String</code>,它将简单地返回到自然或反向顺序,这不太可能被注意到,因为它只影响这些不常见对的关系。

如果为没有冲突的值(例如整数实例)或覆盖定义相等的值的所有属性(例如,点的 xy)创建这样的比较器,则比较器看起来会简单得多。

 类似资料:
  • 问题内容: 有没有什么方法可以模拟Collections.shuffle的行为,而比较器不容易受到排序算法实现的影响,从而确保结果安全? 我的意思是不违反可比合同等。 问题答案: 不打破合同就不可能实现真正的“改组比较器”。合同的一个基本方面是,结果是可 重现的, 因此必须确定特定实例的顺序。 当然,您可以使用混洗操作预先初始化该固定顺序,并创建一个比较器来精确地建立此顺序。例如 虽然没有意义。显

  • 配置 UserAgent 列表 @app.beans: [ 'UserAgentManager' => [ 'list' => [ // 这里可以放想要用的 UserAgent 列表 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36

  • 每次产生一个随机数。 用法 Your browser does not support the video tag. 案例:掷骰子 功能:设置随机数范围1-6,每按一下按钮,产生一个随机数 工作原理 当输入由no变为yes时,一个随机数将会被传送到输出。你可以通过配置改变随机数的范围 例如:一个随机变色的灯

  • 问题内容: 当他每次运行程序时都不断获得相同的数字时,我试图向Java解释随机数生成器。我为同一件事创建了自己的简单版本,每次运行该程序时,我也得到了与他得到的确切数字相同的数字。 我究竟做错了什么? 100个数字中的最后五个数字是: 问题答案: 您已经为随机数生成器提供了恒定的值。它是确定性的,因此每次运行都会生成相同的值。 我不确定您为什么选择使用作为种子,但是种子值与生成的值范围无关(这是由

  • 一个简单的新手问题,奇怪的是我一直没能找到解决方法。

  • 给定一个随机数生成器random(7),它可以以相等的概率生成数字1,2,3,4,5,6,7(即每个数字出现的概率为1/7)。现在我们要设计一个随机数(5),它能以相等的概率(1/5)生成1,2,3,4,5。 有一种方法:每次我们随机运行(7),只有当它生成1-5时才返回。如果是6或7,再运行一次,直到它是1-5。 我有点困惑。第一个问题是: 如何用数学方法证明每个数字发生的概率是1/5?例如,假