随机列表除了某些序列

时间:2018-02-14 07:44:37

标签: java arraylist

我想根据一些自定义条件对ArrayList进行随机播放: 如果我的数组列表类似于[1, 4, 5, 6, 9, 45, 67], 我想要洗牌,但要确保5, 6, 9始终一起出现。

Collections课程中是否有可用的方法来执行此操作?

我尝试过这样做,但它会抛出ConcurrentModificationException

 List<Integer> y= new ArrayList<>();
 y.add(1);
 y.add(4);
 y.add(5);
 y.add(6);
 y.add(9);
 y.add(45);
 y.add(67);
 List<Integer> z = y.subList(2, 5);
 y.removeAll(z);
 Collections.shuffle(y);
 int index = ThreadLocalRandom.current()
                              .nextInt(0, y.size() + 1);
 y.addAll(index,z);

3 个答案:

答案 0 :(得分:1)

执行此操作的一种简单方法是将目标元素存储在单独的 List中:

List<Integer> target = new ArrayList<>();
target.add(5);
target.add(6);
target.add(9);

然后随机播放主列表:

Collections.shuffle(y);

然后从0获取随机数 - > y.size()

Random ran = new Random();
int pos = ran.nextInt(y.size());

将目标列表插入原始列表:

y.addAll(pos, target);

注意:这假设您的原始列表已删除目标3号码。

答案 1 :(得分:1)

听起来你的数据确实应该是一个列表列表,特别是因为你可能会有超过1个需要保持在一起的组。 您可以随时在需要时展平它。

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;

public class Example {
    public static void main(String[] args) {
        List<List<Integer>> y = new ArrayList<List<Integer>>();
        y.add(new ArrayList<Integer>(Arrays.asList(1)));
        y.add(new ArrayList<Integer>(Arrays.asList(4)));
        y.add(new ArrayList<Integer>(Arrays.asList(5, 6, 9)));
        y.add(new ArrayList<Integer>(Arrays.asList(45)));
        y.add(new ArrayList<Integer>(Arrays.asList(67)));
        Collections.shuffle(y);
        List<Integer> flatList = new ArrayList<>();
        y.forEach(flatList::addAll);

    }

}

答案 2 :(得分:0)

在没有看到您的代码的情况下,我认为ConcurrentModificationException被抛出是因为您尝试从列表中删除组元素或者在迭代时将它们添加回来。在迭代时更改集合会导致这些例外:Iterating through a Collection, avoiding ConcurrentModificationException when removing in loop

如果您不将组视为例外,那将会变得更容易,但作为常态。我的意思是你应该将List<?>转换为List<List<?>>,其中每个子列表包含一个元素或一个组。然后,您可以使用Collections.shuffle()轻松地对该列表进行随机播放,然后再将其展平。

看看这个粗略的实现:

List<Integer> ints = new ArrayList<>(asList(2, 3, 5, 4, 8, 7, 11, 55));
List<List<Integer>> groups = asList(asList(5, 4), asList(7, 11));

// remove all the grouped elements from the list
groups.forEach(ints::removeAll);

// wrap the single elements into list and join them with the groups
List<List<Integer>> wrapped = Stream.concat(ints.stream().map(Arrays::asList),
                                            groups.stream())
                                    .collect(Collectors.toList());

Collections.shuffle(wrapped);

// flatten the list into single elements again
List<Integer> shuffled = wrapped.stream()
                                .flatMap(Collection::stream)
                                .collect(Collectors.toList());

System.out.println(shuffled); // e.g. [55, 3, 7, 11, 2, 8, 5, 4]
                              //              -----        ----

请注意,虽然这是非常易读的,但它可能不是最有效或防错的解决方案。但它应该让你知道如何解决这个问题。

Gonen I评论后编辑。这是一个帮助方法,只删除整个列表中的确切序列而不是随机部分:

private static <T> void removeSequence(List<T> list, List<T> sequence)
{
    int indexOfSubList = Collections.lastIndexOfSubList(list, sequence);
    while (indexOfSubList != -1)
    {
        for (int j = 0; j < sequence.size(); j++)
        {
            list.remove(indexOfSubList);
        }
        indexOfSubList = Collections.lastIndexOfSubList(list, sequence);
    }
}

groups.forEach(ints::removeAll);替换为groups.forEach(group -> removeSequence(ints, group));

来使用它