【发布时间】:2015-06-28 09:36:35
【问题描述】:
我有一个带有值元素的列表整数:0、7、2、1、6、5。
我知道我可以使用方法
Collections.shuffle(list);
洗牌我的名单。但我不想改变第二个位置的值。它应该始终是 7。
我该怎么做?
【问题讨论】:
我有一个带有值元素的列表整数:0、7、2、1、6、5。
我知道我可以使用方法
Collections.shuffle(list);
洗牌我的名单。但我不想改变第二个位置的值。它应该始终是 7。
我该怎么做?
【问题讨论】:
您可以将 Collection 洗牌,然后将 7 恢复到第 2 位:
Collections.shuffle(list);
list.set(list.indexOf(7),list.get(2));
list.set(2,7);
或更短:
Collections.shuffle(list);
Collections.swap(list, 2, list.indexOf(7));
正如其他人建议的那样,您还可以在洗牌之前删除您希望保留其位置的元素,然后将其添加到同一位置。
ArrayLists 的两种方法都需要相似的时间(在最坏的情况下是线性的),因为在我的回答中 indexOf 需要线性时间,但是在替代解决方案中删除和添加一个元素(特别是如果索引接近列表的开头)对于ArrayList 将花费线性时间,因为必须将删除/添加索引之后的所有元素推送到新索引。
【讨论】:
list.set(2,7) 并且不会更改任何内容,因为 set 不会向 List 添加值(它只会更改现有值)。
Collections.shuffle(...) 的分布属性。
简单地防止移动任意数量的元素
【讨论】:
有一个更长的替代解决方案,但对于长列表可能更快:
public static <T> void shuffleExcept(final List<T> list, final int position) {
List<T> view = new AbstractList<T>() {
@Override
public T get(int index) {
return list.get(index >= position ? index+1 : index);
}
@Override
public T set(int index, T element) {
return list.set(index >= position ? index+1 : index, element);
}
@Override
public int size() {
return list.size()-1;
}
};
Collections.shuffle(view);
}
这里我们创建一个原始列表的“视图”,它是除了我们想要保留的元素之外的整个列表(我们只是移动后续元素的索引)。接下来我们洗牌这个视图。这就是接口的美妙之处:您可以要求现有方法做一些不同的事情,只需传递新的接口实现即可。
使用示例:
List<Integer> input = Arrays.asList(0, 7, 2, 1, 6, 5);
shuffleExcept(input, 1);
System.out.println(input);
shuffleExcept(input, 1);
System.out.println(input);
shuffleExcept(input, 1);
System.out.println(input);
shuffleExcept(input, 1);
System.out.println(input);
shuffleExcept(input, 1);
System.out.println(input);
shuffleExcept(input, 1);
System.out.println(input);
shuffleExcept(input, 1);
System.out.println(input);
典型输出:
[6, 7, 5, 2, 1, 0]
[5, 7, 6, 1, 2, 0]
[6, 7, 2, 0, 5, 1]
[6, 7, 2, 0, 5, 1]
[2, 7, 0, 5, 6, 1]
[6, 7, 0, 2, 5, 1]
[5, 7, 2, 0, 1, 6]
【讨论】: