Como aleatorizar duas ArrayLists da mesma maneira?

257

Eu tenho dois arraylist fileliste imgListque se relacionam entre si, por exemplo, "H1.txt" relacionado a "e1.jpg". Como randomizar automaticamente a lista de imgListacordo com a randomização de fileList? Como no excel, se classificarmos determinada coluna, a outra coluna seguirá automaticamente?

String [] file = {"H1.txt","H2.txt","H3.txt","M4.txt","M5.txt","M6.txt"};
ArrayList<String> fileList = new ArrayList<String>(Arrays.asList(file));

String [] img = {"e1.jpg","e2.jpg","e3.jpg","e4.jpg","e5.jpg","e6.jpg"};
ArrayList<String> imgList = new ArrayList<String>(Arrays.asList(img));

//randomized files
Collections.shuffle(fileList);

saída após a randomização, por exemplo:

fileList = {"M4.txt","M6.txt","H3.txt","M5.txt","H2.txt","H1.txt"};

saída pretendida:

 imgList = {"e4.jpg","e6.jpg","e3.jpg","e5.jpg","e2.jpg","e1.jpg"};
Jessy
fonte

Respostas:

585

Use Collections.shuffle()duas vezes, com dois Randomobjetos inicializados com a mesma semente:

long seed = System.nanoTime();
Collections.shuffle(fileList, new Random(seed));
Collections.shuffle(imgList, new Random(seed));

O uso de dois Randomobjetos com a mesma semente garante que as duas listas sejam embaralhadas exatamente da mesma maneira. Isso permite duas coleções separadas.

Michael Borgwardt
fonte
121

Coloque-os em outra classe para que você possa terminar com uma única matriz ou Listcom esses objetos.

public class Data {
    private String txtFileName;
    private String imgFileName;

    // Add/generate c'tor, getter/setter, equals, hashCode and other boilerplate.
}

Exemplo de uso:

List<Data> list = new ArrayList<Data>();
list.add(new Data("H1.txt", "e1.jpg"));
list.add(new Data("H2.txt", "e2.jpg"));
// ...

Collections.shuffle(list);
BalusC
fonte
10
Esta é a solução orientada a objetos Java. Talvez, como isso deve ser feito ... :)
Evan
22

A abordagem mais simples é encapsular os dois valores em um tipo que tenha a imagem e o arquivo. Em seguida, construir um ArrayListde que e shuffle-lo.

Isso também melhora o encapsulamento, fornecendo a propriedade de que você sempre terá o mesmo número de arquivos que as imagens automaticamente.

Uma alternativa, se você realmente não gostar dessa idéia, seria escrever o código de reprodução aleatória (existem muitos exemplos de uma reprodução Fisher-Yates modificada em Java, incluindo vários no Stack Overflow, suspeito) e apenas operar nas duas listas em o mesmo tempo. Mas eu recomendo vivamente que adote a abordagem "melhorar o encapsulamento".

Jon Skeet
fonte
11

Você pode fazer isso com mapas:

Map<String, String> fileToImg:
List<String> fileList = new ArrayList(fileToImg.keySet());
Collections.shuffle(fileList);
for(String item: fileList) {
    fileToImf.get(item);
}

Isso irá percorrer as imagens na ordem aleatória.

jjnguy
fonte
5

Isso pode ser feito usando o método shuffle:

private List<Integer> getJumbledList() {
     List<Integer> myArrayList2 = new ArrayList<Integer>();
        myArrayList2.add(8);
        myArrayList2.add(4);
        myArrayList2.add(9);
        Collections.shuffle(myArrayList2);
        return myArrayList2;
Rohit Goyal
fonte
4

Em vez de ter duas matrizes de Strings, tenha uma matriz de uma classe personalizada que contenha suas duas strings.

EboMike
fonte
3

Você pode criar uma matriz contendo os números de 0 a 5 e embaralhá-los. Em seguida, use o resultado como um mapeamento de "oldIndex -> newIndex" e aplique esse mapeamento às duas matrizes originais.

Mark Byers
fonte
2

Não sabe ao certo o que você quer dizer com "automaticamente" - você pode criar um objeto contêiner que contenha os dois objetos:

classe pública FileImageHolder {String fileName; String imageName; // TODO: insira itens aqui}

E, em seguida, coloque isso em uma lista de matrizes e randomize essa lista de matrizes.

Caso contrário, você precisaria manter o controle de onde cada elemento se moveu em uma lista e também no outro.

aperkins
fonte
2

A menos que haja uma maneira de recuperar o índice antigo dos elementos depois que eles foram embaralhados, eu o faria de duas maneiras:

A) Crie outra lista multi_shuffler = [0, 1, 2, ..., file.size ()] e embaralhe-a. Faça um loop sobre ele para obter o pedido de suas listas de arquivos / imagens embaralhadas.

ArrayList newFileList = new ArrayList (); ArrayList newImgList = new ArrayList (); para (i = 0; i

ou B) Faça uma classe StringWrapper para armazenar os nomes de arquivo / imagem e combine as duas listas que você já inseriu em uma: ArrayList combinadoList;

ajwood
fonte