从ArrayList中随机选取元素

Chr*_*ris 0 java shuffle arraylist

我需要从 中选取 N 个随机元素List<MyObject> objectsMyObject是一个复杂的类对象。我可以很容易地Collections.shuffle(objects)得到一个大小为 N 的子列表。

但后来我想到了一个想法。如果我创建 a List<Integer> indexes= [0, N-1],改洗此索引数组,获取一个子列表,并使用它从原始列表中获取元素,它会提高性能吗?

我的问题归结为:在 Java 中重排与轻量级对象列表之间是否存在有意义的性能差异?


ps:如果重要的话,我需要在新列表中返回随机选择,同时还将它们从原始列表中删除。

Bas*_*que 9

与混洗无关的对象类型

没有不同。

A是引用(本质上是指针List)的集合,而不是对象。列表中的每个元素都是一个引用,可以将其视为对象所在的内存中的地址。该引用隐式地将您带到该对象的内容。因此,我们很方便地将列表视为包含对象,尽管这并不完全准确。

因此,洗牌 aList<MyObject>和洗牌 aList<Integer>做同样的工作。两者都会打乱对象引用的集合,而不是对象。这些对象从未移动过,它们始终位于相同的内存地址中。对对象的引用MyObject和对Integer对象的引用是相同的,都是引用。

对对象的引用与MyObject对对象的引用的类型和大小完全相同Integer它们的确切本质是特定JVM的实现细节,但您可以将引用视为都是包含对象所在内存地址的长整数。

打乱重物体与轻物体的列表

MyObject类和类的大小和复杂性Integer与洗牌无关List

下面的图表描述了改组之前和之后的对象引用列表。右侧对象(3 维框)的大小/复杂性与左侧列表中包含的引用的移动无关。

洗牌前后的参考文献列表图

生成新列表

你说:

我需要在新列表中返回随机选择,同时还将它们从原始列表中删除。

首先,生成一个新的打乱列表。

List < String > names = new ArrayList <> ( List.of ( "Alice" , "Bob" , "Carol" , "Davis" , "Edith" , "Frank" , "Georgette" ) );
Collections.shuffle ( names );

List < String > fewNames = List.copyOf ( names.subList ( 0 , 3 ) );
Run Code Online (Sandbox Code Playgroud)

姓名 = [鲍勃、伊迪丝、乔治特、戴维斯、卡罗尔、爱丽丝、弗兰克]

FewNames = [鲍勃、伊迪丝、乔其纱]

其次,仅通过替换引用即可有效删除原始列表中排除的名称。

names = fewNames ;  // Effectively removes the excluded elements.
Run Code Online (Sandbox Code Playgroud)

如果第一个较长的列表未被任何其他引用保存,则该列表对象将成为垃圾收集的候选者,并最终将从内存中删除。

如果您确实想从第一个较长的列表本身中删除元素,请保留元素的子集。

boolean listChanged = names.retainAll( fewNames ) ;
Run Code Online (Sandbox Code Playgroud)

另请参阅许多现有的问题和解答

  • 您需要了解 Java 中的所有内容无一例外都是按值传递引用。这不是通过引用传递。 (2认同)