我有一个Media对象列表。
Class structure of Media is :
Integer id;
String url;
(@ManyToOne)EventEntity event,..etc
Class structure of EventEntity is :
Integer id;
String name;....etc
可能有多个Media
个对象EventEntity
。我们如何随机对Media
列表进行排序,以使Media
个EventEntity
对象不会一个接一个地出现。
例如,我想要的结果是:
[
{
"abc",event1
},
{
"sdf",event2
},
{
"sdf34",event1
},
{
"sdsdafsdf",event3
},
{
"sdf345f34",event2
}
]
我也可以创建另一个类 - > Demo.class
:
Integer id;
String url;
Integer eventId;
填充List<Demo>
并随机化。
输出应为:
[
{
5,"abc",1
},
{
8,"sdf",2
},
{
1,"sdf34",1
},
{
2,"sdsdafsdf",3
},
{
9,"sdf345f34",2
}
]
请提供一些说明。优先选择Java 8,以及更高效的旧版本。
更新:
List<Media>
可以为不同的EventEntity
提供不等数量的元素。
例如:List<Media>
有8个元素,其中5个元素具有相同的EventEntity
。
在这种情况下,随机顺序将会完成,但可能不遵循规则,但应该接近它。
答案 0 :(得分:2)
一种方法是
List<Media> result = new ArrayList<>(mediaCollection.size());
ArrayList<Media> flatList = new ArrayList<>(mediaCollection);
Map<Integer,Integer> countMap = new HashMap<>();
for(Media m: flatList)
countMap.merge(m.getEventEntity().getId(), 1, Integer::sum);
Random r = ThreadLocalRandom.current();
Collections.shuffle(flatList, r);
Integer previousID = null;
while(!flatList.isEmpty()) {
for(int index = flatList.size()-1; index >= 0; index--) {
final Media m = flatList.get(index);
Integer id = m.getEventEntity().getId();
if(previousID!=null && previousID.equals(id) && countMap.size()>1) continue;
previousID = id;
result.add(m);
flatList.remove(index);
countMap.merge(id, -1, (a,b) -> a==1? null: a+b);
}
if(countMap.size() == 1) {
result.addAll(flatList);
flatList.clear();
}
}
这会将所有元素复制到flatList
中,然后在将它们复制到最终result
列表时,将与之前ID相同的元素推迟到下一次复制迭代(通常,在第一步之后只剩下几个元素)。关键部分是当只剩下具有相同ID的元素时停止,因为,推迟没有任何意义并导致无限循环。这就是维持countMap
的原因。它会跟踪每个ID的剩余数量,而当条目变为零时,条目将被删除。当地图的大小为1时,只剩下一个ID,其余的元素将全部转移。