我正在使用Collections.shuffle(list);
洗牌清单,但我不知道如何取消洗牌?我想在洗牌之前保存列表,然后将其洗牌,以便维护备份,并且可以在需要时重新恢复,但这似乎是一种低效的方式它会花费时间和记忆....如果你知道一种更合乎逻辑的方式,你能详细说明吗?
顺便说一句,这是我的应用程序的样子:D
答案 0 :(得分:5)
没有这种无拘无束的概念 - 例如,在你洗牌后,你会如何回到以前的状态?
如果您的原始收藏品以某种明确的方式订购,请再次对其进行排序。否则(例如,如果它是手工订购的),你必须在你洗牌之前复制一份。
理论上你可以:
Random
并将其传递到shuffle
ArrayList<Integer>
Random
随机播放该列表
......但这是一项非常多的工作。除非你的集合真的太大而不能保留额外的副本(不要忘记它只是引用的副本,而不是整个对象),我只是在改组之前克隆该集合。
答案 1 :(得分:4)
首先,应该使用Jon的答案,因为这是最简单和最干净的。无论如何,可以用已知的随机源来反转混洗,因为Collections.shuffle()
指定了使用的算法。再一次,不要这样做,但这里是任何好奇的人的过程:
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Random;
public class Unshuffle {
public static void main(String[] args) {
List<Integer> data = new ArrayList<Integer>();
for (int i = 0; i < 20; i++) {
data.add(i);
}
System.out.println(data);
Collections.shuffle(data, new Random(42));
System.out.println(data);
unshuffle(data, new Random(42));
System.out.println(data);
}
private static <T> void unshuffle(List<T> list, Random rnd) {
int[] seq = new int[list.size()];
for (int i = seq.length; i >= 1; i--) {
seq[i - 1] = rnd.nextInt(i);
}
for (int i = 0; i < seq.length; i++) {
Collections.swap(list, i, seq[i]);
}
}
}
输出是:
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19] [15, 16, 14, 13, 5, 11, 17, 18, 8, 2, 6, 7, 3, 1, 19, 4, 12, 0, 9, 10] [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19]
答案 2 :(得分:0)
使用Collections.sort()将其排序回任何顺序(字母,数字等)
答案 3 :(得分:0)
我们没有洗牌清单,我们只是随机播放,随机播放 最简单的方法是从Collections调用shuffle方法并传递arraylist
List<String> myArrayList = new ArrayList<String>;
myArrayList.add("A");
myArrayList.add("B");
myArrayList.add("C");
myArrayList.add("D");
Collections.shuffle(myArrayList);
迭代列表。它被洗牌了。
答案 4 :(得分:0)
为列表中的每个项目添加额外的隐藏索引字段。在改组之前,为这个隐藏字段分配顺序号码:1,2,3,4,5 ......如果你想让列表恢复原来的顺序,只需对这个隐藏字段进行排序。
您需要足够的空间来存储隐藏的字段和少量的处理时间。
答案 5 :(得分:0)
我知道这很老了,但我可以自由实施*乔恩·斯凯特(Jon Skeet)的理论改组,因为这是一个很棒的主意。 PcgRandom算法的功能是允许人们“跳”到随机数生成器中的任意点,并且可以用来“记住”随机播放期间生成的值,并将其反转:
var currentIndex = m_currentIndex;
var lastIndex = (m_values.Length - 1);
while (-1 < currentIndex) {
m_randomNumberGenerator.Jump(-1);
var randomIndex = m_randomNumberGenerator.NextInt32(currentIndex, lastIndex);
var tempValue = m_values[randomIndex];
m_values[randomIndex] = m_values[currentIndex];
m_values[currentIndex--] = tempValue;
m_randomNumberGenerator.Jump(-1);
}
这是随机数生成器的完整实现:
/// <summary>
/// Represents an instance of a fast random number generator; relies on the Pcg32XshRr algorithm described by Melissa O'neil.
/// </summary>
/// <remarks>
/// http://pcg-random.org/paper.html
/// https://en.wikipedia.org/wiki/Lehmer_random_number_generator
/// https://en.wikipedia.org/wiki/Linear_congruential_generator
/// https://github.com/lemire/fastrange
/// </remarks>
public sealed class FastRandom : IRandomNumberGenerator
{
private const ulong MAX_STREAM_VALUE = ((1UL << 63) - 1UL);
private readonly ulong m_magic;
private readonly ulong m_stream;
private ulong m_state;
/// <summary>
/// Gets the default <see cref="FastRandom"/> instance.
/// </summary>
public static readonly FastRandom Default = new FastRandom();
/// <summary>
/// Initializes a new instance of the <see cref="FastRandom"/> class.
/// </summary>
/// <param name="state">The initial state of the random number generator.</param>
/// <param name="stream">The stream offset of the random number generator.</param>
[CLSCompliant(false)]
public FastRandom(ulong state, ulong stream) {
if (stream > MAX_STREAM_VALUE) {
throw new ArgumentOutOfRangeException(message: "stream offset must be a positive integer less than 2^63", paramName: nameof(stream));
}
m_magic = 6364136223846793005UL;
m_state = state;
m_stream = ((((~(stream & 1UL)) << 63) | stream) | 1UL);
}
/// <summary>
/// Initializes a new instance of the <see cref="FastRandom"/> class.
/// </summary>
/// <param name="state">The initial state of the random number generator.</param>
/// <param name="stream">The stream offset of the random number generator.</param>
public FastRandom(long state, long stream) : this(checked((ulong)state), checked((ulong)stream)) { }
/// <summary>
/// Initializes a new instance of the <see cref="FastRandom"/> class.
/// </summary>
/// <param name="state">The initial state of the random number generator.</param>
[CLSCompliant(false)]
public FastRandom(ulong state) : this(state, SecureRandom.Default.NextUInt64(0UL, MAX_STREAM_VALUE)) { }
/// <summary>
/// Initializes a new instance of the <see cref="FastRandom"/> class.
/// </summary>
/// <param name="state">The initial state of the random number generator.</param>
public FastRandom(long state) : this((ulong)state) { }
/// <summary>
/// Initializes a new instance of the <see cref="FastRandom"/> class.
/// </summary>
public FastRandom() : this(SecureRandom.Default.NextUInt64()) { }
/// <summary>
/// Moves the state of the generator forwards by the specificed number of steps.
/// </summary>
/// <param name="count">The number of states that will be jumped.</param>
[CLSCompliant(false)]
public void Jump(ulong count) {
Jump(ref m_state, m_magic, m_stream, count);
}
/// <summary>
/// Moves the state of the generator forwards or backwards by the specificed number of steps.
/// </summary>
/// <param name="count">The number of states that will be jumped.</param>
public void Jump(long count) {
Jump(ref m_state, m_magic, m_stream, unchecked((ulong)count));
}
/// <summary>
/// Generates a uniformly distributed double precision floating point value between the exclusive range (0, 1).
/// </summary>
public double NextDouble() {
return Operations.DoornikDouble(NextInt32(), NextInt32());
}
/// <summary>
/// Generates a uniformly distributed 32-bit signed integer between the range of int.MinValue and int.MaxValue.
/// </summary>
public int NextInt32() {
return ((int)NextUInt32());
}
/// <summary>
/// Generates a uniformly distributed 32-bit signed integer between the inclusive range [x, y].
/// </summary>
/// <param name="x">The value of x.</param>
/// <param name="y">The value of y.</param>
public int NextInt32(int x, int y) {
if (x > y) {
var z = x;
x = y;
y = z;
}
var range = ((uint)(y - x));
if (range != uint.MaxValue) {
return ((int)(Sample(ref m_state, m_magic, m_stream, exclusiveHigh: (range + 1U)) + x));
}
else {
return NextInt32();
}
}
/// <summary>
/// Generates a uniformly distributed single precision floating point value between the exclusive range (0, 1).
/// </summary>
public float NextSingle() {
return Operations.DoornikSingle(NextInt32());
}
/// <summary>
/// Generates a uniformly distributed 32-bit unsigned integer between the range of uint.MinValue and uint.MaxValue.
/// </summary>
[CLSCompliant(false)]
public uint NextUInt32() {
return Next(ref m_state, m_magic, m_stream);
}
/// <summary>
/// Generates a uniformly distributed 32-bit unsigned integer between the inclusive range [x, y].
/// </summary>
/// <param name="x">The value of x.</param>
/// <param name="y">The value of y.</param>
[CLSCompliant(false)]
public uint NextUInt32(uint x, uint y) {
if (x > y) {
var z = x;
x = y;
y = z;
}
var range = (y - x);
if (range != uint.MaxValue) {
return (Sample(ref m_state, m_magic, m_stream, exclusiveHigh: (range + 1U)) + x);
}
else {
return NextUInt32();
}
}
private static void Jump(ref ulong state, ulong magic, ulong stream, ulong count) {
var accMul = 1UL;
var accAdd = 0UL;
var curMul = magic;
var curAdd = stream;
while (count > 0UL) {
if (0UL < (count & 1UL)) {
accMul *= curMul;
accAdd = ((accAdd * curMul) + curAdd);
}
curAdd = ((curMul + 1UL) * curAdd);
curMul *= curMul;
count >>= 1;
}
state = ((accMul * state) + accAdd);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static uint Next(ref ulong state, ulong magic, ulong stream) {
state = unchecked((state * magic) + stream);
return Operations.RotateRight(value: ((uint)(((state >> 18) ^ state) >> 27)), count: ((int)(state >> 59)));
}
private static uint Sample(ref ulong state, ulong magic, ulong stream, uint exclusiveHigh) {
ulong sample = Next(ref state, magic, stream);
ulong result = (sample * exclusiveHigh);
uint leftover = ((uint)result);
if (leftover < exclusiveHigh) {
uint threshold = ((((uint)(-exclusiveHigh)) % exclusiveHigh));
while (leftover < threshold) {
sample = Next(ref state, magic, stream);
result = (sample * exclusiveHigh);
leftover = ((uint)result);
}
}
return ((uint)(result >> 32));
}
}
以及随机播放逻辑的完整实现:
/// <summary>
/// Represents a strongly typed collection that uses a random number generator to retrieve elements.
/// </summary>
/// <typeparam name="T">The type of elements encapsulated by the bag.</typeparam>
public sealed class ShuffleBag<T> : IEnumerable<T>, IEnumerator<T>
{
private readonly IRandomNumberGenerator m_randomNumberGenerator;
private readonly T[] m_values;
private int m_currentIndex;
/// <summary>
/// Gets the element in the collection at the current position of the enumerator.
/// </summary>
object IEnumerator.Current => Current;
/// <summary>
/// Gets the element in the collection at the current position of the enumerator.
/// </summary>
public T Current => m_values[m_currentIndex];
/// <summary>
/// Initializes a new instance of the <see cref="ShuffleBag{T}"/> class.
/// </summary>
/// <param name="randomNumberGenerator">The source of random numbers that will be used to perform the shuffle.</param>
/// <param name="values">The array of values that will be randomized.</param>
public ShuffleBag(IRandomNumberGenerator randomNumberGenerator, T[] values) {
if (randomNumberGenerator.IsNull()) {
throw new ArgumentNullException(message: "random number generator cannot be null", paramName: nameof(randomNumberGenerator));
}
if (values.IsNull()) {
throw new ArgumentNullException(message: "array of values cannot be null", paramName: nameof(values));
}
m_currentIndex = -1;
m_randomNumberGenerator = randomNumberGenerator;
m_values = values;
}
/// <summary>
/// Releases all resources used by this <see cref="ShuffleBag"/> instance.
/// </summary>
public void Dispose() { }
/// <summary>
/// Returns an enumerator that randomly yields elements from the bag.
/// </summary>
IEnumerator IEnumerable.GetEnumerator() {
return GetEnumerator();
}
/// <summary>
/// Returns an enumerator that randomly yields elements from the bag.
/// </summary>
public IEnumerator<T> GetEnumerator() {
while (MoveNext()) {
yield return Current;
}
}
/// <summary>
/// Advances the enumerator to the next random element in the collection.
/// </summary>
public bool MoveNext() {
var currentIndex = m_currentIndex;
var lastIndex = (m_values.Length - 1);
if (currentIndex < lastIndex) {
var randomIndex = m_randomNumberGenerator.NextInt32(++currentIndex, lastIndex);
var tempValue = m_values[randomIndex];
m_currentIndex = currentIndex;
m_values[randomIndex] = m_values[currentIndex];
m_values[currentIndex] = tempValue;
return true;
}
else {
return false;
}
}
/// <summary>
/// Sets the enumerator to its initial position.
/// </summary>
/// <param name="unshuffle">Indicates whether elements will be returned to their original, unshuffled, positions.</param>
public void Reset(bool unshuffle) {
if (unshuffle) {
var currentIndex = m_currentIndex;
var lastIndex = (m_values.Length - 1);
while (-1 < currentIndex) {
m_randomNumberGenerator.Jump(-1);
var randomIndex = m_randomNumberGenerator.NextInt32(currentIndex, lastIndex);
var tempValue = m_values[randomIndex];
m_values[randomIndex] = m_values[currentIndex];
m_values[currentIndex--] = tempValue;
m_randomNumberGenerator.Jump(-1);
}
}
m_currentIndex = -1;
}
/// <summary>
/// Sets the enumerator to its initial position and returns elements to their original, unshuffled, positions.
/// </summary>
public void Reset() {
Reset(unshuffle: true);
}
}
*对不起,它在C#中。