如何对两个列表进行乱序处理,同时保持它们的一一对应的关系?
已知我们有两个列表
public class RandomizeTwoList {
public static String [] file = {"H1.txt","H2.txt","H3.txt","M4.txt","M5.txt","M6.txt"};
public static ArrayList<String> fileList = new ArrayList<String>(Arrays.asList(file));
public static String [] img = {"e1.jpg","e2.jpg","e3.jpg","e4.jpg","e5.jpg","e6.jpg"};
public static ArrayList<String> imgList = new ArrayList<String>(Arrays.asList(img));
}
其中fileList和imgList中的元素是一一对应的。
现在我们希望对两个列表进行随机排序,要求排序后它们依旧是一一对应的。
提示: java.util.Collections
可以使得一个列表乱序,但是下面的写法是不可以的:
import java.util.Collections;
public class RandomizeTwoListTest {
@Test
public void wrongRandomize(){
Collections.shuffle(fileList);
Collections.shuffle(imgList);
System.out.println(fileList);
System.out.println(imgList);
// [H3.txt, M5.txt, H2.txt, H1.txt, M6.txt, M4.txt]
// [e6.jpg, e3.jpg, e4.jpg, e1.jpg, e2.jpg, e5.jpg]
}
}
我们可以看到java.util.Collections
确实可以使得一个列表乱序,但是上面两次乱序后列表之间失去了一一对应的关系,所以是不行的。
那我们怎么解决呢?
方案一: 把它们绑定起来
我们之前的演示用例失败的原因是两次随机化的规则不一样,导致结果不能一一对应,那么我们现在可以
让它们一一绑定起来,构造出一个list(当然也可以是map、onject)容纳它们,然后再随机排序。
@Test
public void randomTogether(){
List<List<String>> compoundList = new ArrayList();
for (int i = 0; i < fileList.size(); i++) {
List<String> listItem = new ArrayList();
listItem.add(fileList.get(i));
listItem.add(imgList.get(i));
compoundList.add(listItem);
}
System.out.println(compoundList);
// [[H1.txt, e1.jpg], [H2.txt, e2.jpg], [H3.txt, e3.jpg], [M4.txt, e4.jpg], [M5.txt, e5.jpg], [M6.txt, e6.jpg]]
Collections.shuffle(compoundList);
System.out.println(compoundList);
// [[M5.txt, e5.jpg], [H2.txt, e2.jpg], [M4.txt, e4.jpg], [H3.txt, e3.jpg], [H1.txt, e1.jpg], [M6.txt, e6.jpg]]
for (int i = 0; i < fileList.size(); i++) {
fileList.set(i, compoundList.get(i).get(0));
imgList.set(i, compoundList.get(i).get(1));
}
System.out.println(fileList);
// [M5.txt, H2.txt, M4.txt, H3.txt, H1.txt, M6.txt]
System.out.println(imgList);
// [e5.jpg, e2.jpg, e4.jpg, e3.jpg, e1.jpg, e6.jpg]
}
参考这样的代码。看起来很复杂,其实思路很简单。
- 先把fileList第i个元素的值和imgList第i个元素的值绑定起来,构造出新的数组
- 然后对着数组进行乱序,乱序完成后原理的两个list的对应依旧保持一致
- 将list整理还原
方案2: 采取同样的方式随机化
我们来说一下Collections.shuffle 的原理。
当我们调用Collections.shuffle(List list)的时候,它其实做了这件事
public static void shuffle(List<?> list) {
Random rnd = r;
if (rnd == null)
r = rnd = new Random(); // harmless race.
shuffle(list, rnd);
}
那么void shuffle(List<?> list, Random rnd)
又做了什么呢?
简单的来说,它就是对传进来的list做一次i递减的for循环,然后在每次循环的时候把第i个元素和rnd.nextInt(i)的值互换,这样我们最终的list就是随机乱序的了。
这里大家明白了吧,如果每次产生的随机值一致,那么它们就随机排序的结果就是一致的。
好了,有的同学就开始写代码了,写出这样的代码了
@Test
public void randomize(){
long seed = System.nanoTime();
Random random = new Random(seed);
Collections.shuffle(fileList, random);
Collections.shuffle(imgList, random);
System.out.println(fileList);
System.out.println(imgList);
}
注意这样是不行的哦,因为虽然是同一个Random,但是每次调用nextInt的结果是不一样的。
应该这样写:
@Test
public void randomize2(){
long seed = System.nanoTime();
Collections.shuffle(fileList, new Random(seed));
Collections.shuffle(imgList, new Random(seed));
System.out.println(fileList);
System.out.println(imgList);
// [M5.txt, M4.txt, H1.txt, H2.txt, H3.txt, M6.txt]
// [e5.jpg, e4.jpg, e1.jpg, e2.jpg, e3.jpg, e6.jpg]
}
两个Random的随机种子一样,那么他们第i次的nextInt的值也是相等的。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。