Chr*_*ris 0 java shuffle arraylist
我需要从 中选取 N 个随机元素List<MyObject> objects。MyObject是一个复杂的类对象。我可以很容易地Collections.shuffle(objects)得到一个大小为 N 的子列表。
但后来我想到了一个想法。如果我创建 a List<Integer> indexes= [0, N-1],改洗此索引数组,获取一个子列表,并使用它从原始列表中获取元素,它会提高性能吗?
我的问题归结为:在 Java 中重排与轻量级对象列表之间是否存在有意义的性能差异?
ps:如果重要的话,我需要在新列表中返回随机选择,同时还将它们从原始列表中删除。
没有不同。
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)
另请参阅许多现有的问题和解答。