Jak randomizować dwie ArrayLists w ten sam sposób?

257

Mam dwie ArrayList filelisti imgListktóre powiązane ze sobą, na przykład „H1.txt” związane z „e1.jpg”. Jak automatycznie randomizować listę imgListwedług losowości fileList? Podobnie jak w programie Excel, jeśli posortujemy określoną kolumnę, druga kolumna automatycznie pojawi się za nią?

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);

wyjście po randomizacji np .:

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

planowana wydajność:

 imgList = {"e4.jpg","e6.jpg","e3.jpg","e5.jpg","e2.jpg","e1.jpg"};
Jessy
źródło

Odpowiedzi:

585

Użyj Collections.shuffle()dwa razy, z dwoma Randomobiektami zainicjowanymi tym samym ziarnem:

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

Użycie dwóch Randomobiektów z tym samym ziarnem gwarantuje, że obie listy zostaną przetasowane dokładnie w ten sam sposób. Pozwala to na dwie osobne kolekcje.

Michael Borgwardt
źródło
121

Zawiń je w inną klasę, abyś mógł otrzymać jedną tablicę lub Listte obiekty.

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

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

Przykład użycia:

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
źródło
10
To jest obiektowe rozwiązanie Java. Być może, jak należy to zrobić ... :)
Evan
22

Najprostszym podejściem jest zamknięcie dwóch wartości razem w typ, który zawiera zarówno obraz, jak i plik. Następnie budować ArrayListz że i przetasować go.

Poprawia to również enkapsulację, zapewniając właściwość polegającą na tym, że zawsze będziesz mieć automatycznie taką samą liczbę plików jak obrazy.

Alternatywą, jeśli naprawdę nie podoba ci się ten pomysł, byłoby samodzielne napisanie kodu losowego (istnieje wiele przykładów zmodyfikowanego losowania Fisher-Yates w Javie, w tym kilka podejrzewanych o przepełnienie stosu) i po prostu operowanie na obu listach w o tym samym czasie. Ale zdecydowanie zalecam stosowanie podejścia „poprawa enkapsulacji”.

Jon Skeet
źródło
11

Możesz to zrobić za pomocą map:

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

Spowoduje to iterację obrazów w losowej kolejności.

jjnguy
źródło
5

Można to zrobić przy użyciu metody losowej:

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
źródło
4

Zamiast mieć dwie tablice ciągów, miej jedną tablicę niestandardowej klasy, która zawiera dwa ciągi.

EboMike
źródło
3

Możesz utworzyć tablicę zawierającą liczby od 0 do 5 i przetasować je. Następnie użyj wyniku jako mapowania „oldIndex -> newIndex” i zastosuj to mapowanie do obu oryginalnych tablic.

Mark Byers
źródło
2

Nie do końca wiem, co rozumiesz przez „automatycznie” - możesz utworzyć obiekt kontenerowy, który pomieści oba obiekty:

klasa publiczna FileImageHolder {String fileName; Ciąg imageName; // TODO: wstaw tutaj rzeczy}

A następnie umieść to na liście tablic i losowo tę listę tablic.

W przeciwnym razie musisz śledzić, gdzie każdy element porusza się na jednej liście, a także przenosić go na drugim.

aperkins
źródło
2

Jeśli nie ma sposobu na odzyskanie starego indeksu elementów po ich przetasowaniu, zrobiłbym to na dwa sposoby:

A) Utwórz kolejną listę multi_shuffler = [0, 1, 2, ..., file.size ()] i potasuj ją. Pętlę nad nim, aby uzyskać porządek dla przetasowanych list plików / obrazów.

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

lub B) Utwórz klasę StringWrapper do przechowywania nazw plików / obrazów i połącz dwie listy, które już masz w jedną: ArrayList CombinedList;

ajwood
źródło