使用排序来改组分组列表,使得相同组的元素在java中不会一个接一个地出现

时间:2017-04-19 09:19:11

标签: java arraylist random java-8

我有一个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列表进行排序,以使MediaEventEntity对象不会一个接一个地出现。

例如,我想要的结果是:

[
{
"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

在这种情况下,随机顺序将会完成,但可能不遵循规则,但应该接近它。

1 个答案:

答案 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,其余的元素将全部转移。