web-dev-qa-db-fra.com

Shuffling aléatoire d'un tableau

Je dois mélanger au hasard le tableau suivant:

int[] solutionArray = {1, 2, 3, 4, 5, 6, 6, 5, 4, 3, 2, 1};

Y a-t-il une fonction pour faire ça?

192
Hubert

Utiliser Collections pour mélanger un tableau de types primitifs est un peu exagéré ...

Il est assez simple de mettre en oeuvre la fonction vous-même, en utilisant par exemple le Fisher – Yates shuffle :

import Java.util.*;
import Java.util.concurrent.ThreadLocalRandom;

class Test
{
  public static void main(String args[])
  {
    int[] solutionArray = { 1, 2, 3, 4, 5, 6, 16, 15, 14, 13, 12, 11 };

    shuffleArray(solutionArray);
    for (int i = 0; i < solutionArray.length; i++)
    {
      System.out.print(solutionArray[i] + " ");
    }
    System.out.println();
  }

  // Implementing Fisher–Yates shuffle
  static void shuffleArray(int[] ar)
  {
    // If running on Java 6 or older, use `new Random()` on RHS here
    Random rnd = ThreadLocalRandom.current();
    for (int i = ar.length - 1; i > 0; i--)
    {
      int index = rnd.nextInt(i + 1);
      // Simple swap
      int a = ar[index];
      ar[index] = ar[i];
      ar[i] = a;
    }
  }
}
237
PhiLho

Voici un moyen simple en utilisant une ArrayList:

List<Integer> solution = new ArrayList<>();
for (int i = 1; i <= 6; i++) {
    solution.add(i);
}
Collections.shuffle(solution);
143
methodin

Voici une fonction réseau efficace et efficace de Fisher – Yates:

private static void shuffleArray(int[] array)
{
    int index;
    Random random = new Random();
    for (int i = array.length - 1; i > 0; i--)
    {
        index = random.nextInt(i + 1);
        if (index != i)
        {
            array[index] ^= array[i];
            array[i] ^= array[index];
            array[index] ^= array[i];
        }
    }
}

ou

private static void shuffleArray(int[] array)
{
    int index, temp;
    Random random = new Random();
    for (int i = array.length - 1; i > 0; i--)
    {
        index = random.nextInt(i + 1);
        temp = array[index];
        array[index] = array[i];
        array[i] = temp;
    }
}
93
Dan Bray

Collections class a une méthode efficace pour mélanger, qui peut être copiée pour ne pas en dépendre:

/**
 * Usage:
 *    int[] array = {1, 2, 3};
 *    Util.shuffle(array);
 */
public class Util {

    private static Random random;

    /**
     * Code from method Java.util.Collections.shuffle();
     */
    public static void shuffle(int[] array) {
        if (random == null) random = new Random();
        int count = array.length;
        for (int i = count; i > 1; i--) {
            swap(array, i - 1, random.nextInt(i));
        }
    }

    private static void swap(int[] array, int i, int j) {
        int temp = array[i];
        array[i] = array[j];
        array[j] = temp;
    }
}
22
KitKat

Regardez la Collections class, en particulier shuffle(...).

12
Dave

Vous avez deux options ici. Une liste est un peu différente d’un tableau quand il s’agit de mélanger.

Comme vous pouvez le voir ci-dessous, un tableau est plus rapide qu'une liste et un tableau primitif est plus rapide qu'un tableau d'objets.

Durée des échantillons

List<Integer> Shuffle: 43133ns
    Integer[] Shuffle: 31884ns
        int[] Shuffle: 25377ns

Ci-dessous, trois implémentations différentes d'un mélange. Vous ne devriez utiliser Collections.shuffle que si vous avez affaire à une collection. Il n'est pas nécessaire de placer votre tableau dans une collection simplement pour le trier. Les méthodes ci-dessous sont très simples à mettre en œuvre.

ShuffleUtil Class

import Java.lang.reflect.Array;
import Java.util.*;

public class ShuffleUtil<T> {
    private static final int[] EMPTY_INT_ARRAY = new int[0];
    private static final int SHUFFLE_THRESHOLD = 5;

    private static Random Rand;

Méthode principale

    public static void main(String[] args) {
        List<Integer> list = null;
        Integer[] arr = null;
        int[] iarr = null;

        long start = 0;
        int cycles = 1000;
        int n = 1000;

        // Shuffle List<Integer>
        start = System.nanoTime();
        list = range(n);
        for (int i = 0; i < cycles; i++) {
            ShuffleUtil.shuffle(list);
        }
        System.out.printf("%22s: %dns%n", "List<Integer> Shuffle", (System.nanoTime() - start) / cycles);

        // Shuffle Integer[]
        start = System.nanoTime();
        arr = toArray(list);
        for (int i = 0; i < cycles; i++) {
            ShuffleUtil.shuffle(arr);
        }
        System.out.printf("%22s: %dns%n", "Integer[] Shuffle", (System.nanoTime() - start) / cycles);

        // Shuffle int[]
        start = System.nanoTime();
        iarr = toPrimitive(arr);
        for (int i = 0; i < cycles; i++) {
            ShuffleUtil.shuffle(iarr);
        }
        System.out.printf("%22s: %dns%n", "int[] Shuffle", (System.nanoTime() - start) / cycles);
    }

Mélanger une liste générique

    // ================================================================
    // Shuffle List<T> (Java.lang.Collections)
    // ================================================================
    @SuppressWarnings("unchecked")
    public static <T> void shuffle(List<T> list) {
        if (Rand == null) {
            Rand = new Random();
        }
        int size = list.size();
        if (size < SHUFFLE_THRESHOLD || list instanceof RandomAccess) {
            for (int i = size; i > 1; i--) {
                swap(list, i - 1, Rand.nextInt(i));
            }
        } else {
            Object arr[] = list.toArray();

            for (int i = size; i > 1; i--) {
                swap(arr, i - 1, Rand.nextInt(i));
            }

            ListIterator<T> it = list.listIterator();
            int i = 0;

            while (it.hasNext()) {
                it.next();
                it.set((T) arr[i++]);
            }
        }
    }

    public static <T> void swap(List<T> list, int i, int j) {
        final List<T> l = list;
        l.set(i, l.set(j, l.get(i)));
    }

    public static <T> List<T> shuffled(List<T> list) {
        List<T> copy = copyList(list);
        shuffle(copy);
        return copy;
    }

Mélanger un tableau générique

    // ================================================================
    // Shuffle T[]
    // ================================================================
    public static <T> void shuffle(T[] arr) {
        if (Rand == null) {
            Rand = new Random();
        }

        for (int i = arr.length - 1; i > 0; i--) {
            swap(arr, i, Rand.nextInt(i + 1));
        }
    }

    public static <T> void swap(T[] arr, int i, int j) {
        T tmp = arr[i];
        arr[i] = arr[j];
        arr[j] = tmp;
    }

    public static <T> T[] shuffled(T[] arr) {
        T[] copy = Arrays.copyOf(arr, arr.length);
        shuffle(copy);
        return copy;
    }

Mélanger un tableau primitif

    // ================================================================
    // Shuffle int[]
    // ================================================================
    public static <T> void shuffle(int[] arr) {
        if (Rand == null) {
            Rand = new Random();
        }

        for (int i = arr.length - 1; i > 0; i--) {
            swap(arr, i, Rand.nextInt(i + 1));
        }
    }

    public static <T> void swap(int[] arr, int i, int j) {
        int tmp = arr[i];
        arr[i] = arr[j];
        arr[j] = tmp;
    }

    public static int[] shuffled(int[] arr) {
        int[] copy = Arrays.copyOf(arr, arr.length);
        shuffle(copy);
        return copy;
    }

Méthodes utilitaires

Méthodes simples pour copier et convertir des tableaux en listes et vice-versa.

    // ================================================================
    // Utility methods
    // ================================================================
    protected static <T> List<T> copyList(List<T> list) {
        List<T> copy = new ArrayList<T>(list.size());
        for (T item : list) {
            copy.add(item);
        }
        return copy;
    }

    protected static int[] toPrimitive(Integer[] array) {
        if (array == null) {
            return null;
        } else if (array.length == 0) {
            return EMPTY_INT_ARRAY;
        }
        final int[] result = new int[array.length];
        for (int i = 0; i < array.length; i++) {
            result[i] = array[i].intValue();
        }
        return result;
    }

    protected static Integer[] toArray(List<Integer> list) {
        return toArray(list, Integer.class);
    }

    protected static <T> T[] toArray(List<T> list, Class<T> clazz) {
        @SuppressWarnings("unchecked")
        final T[] arr = list.toArray((T[]) Array.newInstance(clazz, list.size()));
        return arr;
    }

Classe Range

Génère une plage de valeurs, similaire à la fonction range de Python.

    // ================================================================
    // Range class for generating a range of values.
    // ================================================================
    protected static List<Integer> range(int n) {
        return toList(new Range(n), new ArrayList<Integer>());
    }

    protected static <T> List<T> toList(Iterable<T> iterable) {
        return toList(iterable, new ArrayList<T>());
    }

    protected static <T> List<T> toList(Iterable<T> iterable, List<T> destination) {
        addAll(destination, iterable.iterator());

        return destination;
    }

    protected static <T> void addAll(Collection<T> collection, Iterator<T> iterator) {
        while (iterator.hasNext()) {
            collection.add(iterator.next());
        }
    }

    private static class Range implements Iterable<Integer> {
        private int start;
        private int stop;
        private int step;

        private Range(int n) {
            this(0, n, 1);
        }

        private Range(int start, int stop) {
            this(start, stop, 1);
        }

        private Range(int start, int stop, int step) {
            this.start = start;
            this.stop = stop;
            this.step = step;
        }

        @Override
        public Iterator<Integer> iterator() {
            final int min = start;
            final int max = stop / step;

            return new Iterator<Integer>() {
                private int current = min;

                @Override
                public boolean hasNext() {
                    return current < max;
                }

                @Override
                public Integer next() {
                    if (hasNext()) {
                        return current++ * step;
                    } else {
                        throw new NoSuchElementException("Range reached the end");
                    }
                }

                @Override
                public void remove() {
                    throw new UnsupportedOperationException("Can't remove values from a Range");
                }
            };
        }
    }
}
9
Mr. Polywhirl

Voici une solution complète utilisant l'approche Collections.shuffle:

public static void shuffleArray(int[] array) {
  List<Integer> list = new ArrayList<>();
  for (int i : array) {
    list.add(i);
  }

  Collections.shuffle(list);

  for (int i = 0; i < list.size(); i++) {
    array[i] = list.get(i);
  }    
}

Notez qu'il souffre de l'incapacité de Java à traduire en douceur int[] et Integer[] (et donc int[] et List<Integer>).

9
Duncan Jones

Utiliser ArrayList<Integer> peut vous aider à résoudre le problème du brassage sans appliquer beaucoup de logique et prendre moins de temps. Voici ce que je suggère:

ArrayList<Integer> x = new ArrayList<Integer>();
for(int i=1; i<=add.length(); i++)
{
    x.add(i);
}
Collections.shuffle(x);
8
SalmaanKhan

Le code suivant réalisera un ordre aléatoire sur le tableau. 

// Shuffle the elements in the array
Collections.shuffle(Arrays.asList(array));

de: http://www.programcreek.com/2012/02/Java-method-to-shuffle-an-int-array-with-random-order/

6
Rajib Biswas

Vous pouvez utiliser Java 8 maintenant:

Collections.addAll(list, arr);
Collections.shuffle(list);
cardsList.toArray(arr);

Voici une version générique pour les tableaux:

import Java.util.Random;

public class Shuffle<T> {

    private final Random rnd;

    public Shuffle() {
        rnd = new Random();
    }

    /**
     * Fisher–Yates shuffle.
     */
    public void shuffle(T[] ar) {
        for (int i = ar.length - 1; i > 0; i--) {
            int index = rnd.nextInt(i + 1);
            T a = ar[index];
            ar[index] = ar[i];
            ar[i] = a;
        }
    }
}

Considérant qu'ArrayList est fondamentalement juste un tableau, il peut être conseillé de travailler avec ArrayList au lieu du tableau explicite et d'utiliser Collections.shuffle (). Cependant, les tests de performance ne montrent aucune différence significative entre ce qui précède et Collections.sort ():

Shuffe<Integer>.shuffle(...) performance: 576084 shuffles per second
Collections.shuffle(ArrayList<Integer>) performance: 629400 shuffles per second
MathArrays.shuffle(int[]) performance: 53062 shuffles per second

L'implémentation MathArrays.shuffle d'Apache Commons est limitée à int [] et la pénalité de performance est probablement due au générateur de nombres aléatoires utilisé.

3
user1050755

Voici une solution utilisant Apache Commons Math 3.x (pour les tableaux int [] uniquement):

MathArrays.shuffle(array);

http://commons.Apache.org/proper/commons-math/javadocs/api-3.6.1/org/Apache/commons/math3/util/MathArrays.html#shuffle (int [])

Sinon, Apache Commons Lang 3.6 a introduit de nouvelles méthodes de mélange dans la classe ArrayUtils (pour les objets et tout type de primitive).

ArrayUtils.shuffle(array);

http://commons.Apache.org/proper/commons-lang/javadocs/api-release/org/Apache/commons/lang3/ArrayUtils.html#shuffle-int:A-

3
Emmanuel Bourg
Random rnd = new Random();
for (int i = ar.length - 1; i > 0; i--)
{
  int index = rnd.nextInt(i + 1);
  // Simple swap
  int a = ar[index];
  ar[index] = ar[i];
  ar[i] = a;
}

A propos, j'ai remarqué que ce code renvoyait un nombre d'éléments ar.length - 1; si votre tableau contient 5 éléments, le nouveau tableau mélangé en aura 4. Cela se produit parce que la boucle for dit i>0. Si vous passez à i>=0, tous les éléments sont mélangés.

J'ai vu des informations manquantes dans certaines réponses, alors j'ai décidé d'en ajouter une nouvelle.

Collections Java Arrays.asList prend un var-arg de type T (T ...). Si vous passez un tableau primitif (int array), la méthode asList en déduira et générera un List<int[]>, qui est une liste à un élément (l'élément unique est le tableau primitif). Si vous mélangez cette liste d’éléments, elle ne changera rien.

Donc, vous devez d’abord convertir votre tableau primitif en tableau d’objets Wrapper. Pour cela, vous pouvez utiliser la méthode ArrayUtils.toObject d'Apache.commons.lang. puis passez le tableau généré à une liste et mélangez-le enfin.

  int[] intArr = {1,2,3};
  List<Integer> integerList = Arrays.asList(ArrayUtils.toObject(array));
  Collections.shuffle(integerList);
  //now! elements in integerList are shuffled!
3
Mr.Q
  1. Box de int[] à Integer[]
  2. Wrap un tableau dans une liste avec la méthode Arrays.asList
  3. Mélanger avec la méthode Collections.shuffle

    int[] solutionArray = { 1, 2, 3, 4, 5, 6, 6, 5, 4, 3, 2, 1 };
    
    Integer[] boxed = Arrays.stream(solutionArray).boxed().toArray(Integer[]::new);
    Collections.shuffle(Arrays.asList(boxed));
    
    System.out.println(Arrays.toString(boxed));
    // [1, 5, 5, 4, 2, 6, 1, 3, 3, 4, 2, 6]
    
2
YujiSoftware

Voici un autre moyen de mélanger une liste

public List<Integer> shuffleArray(List<Integer> a) {
List<Integer> b = new ArrayList<Integer>();
    while (a.size() != 0) {
        int arrayIndex = (int) (Math.random() * (a.size()));
        b.add(a.get(arrayIndex));
        a.remove(a.get(arrayIndex));
    }
    return b;
}

Choisissez un nombre aléatoire dans la liste d'origine et enregistrez-le dans une autre liste.Ensuite, supprimez le numéro de la liste d'origine.La taille de la liste d'origine continuera à diminuer d'un élément jusqu'à ce que tous les éléments soient déplacés vers la nouvelle liste. 

2
PS5

Une solution simple pour Groovy:

solutionArray.sort{ new Random().nextInt() }

Cela triera aléatoirement tous les éléments de la liste de tableaux qui archive le résultat souhaité du brassage de tous les éléments.

1
Hans Kristian

La solution la plus simple pour ce brassage aléatoire dans un tableau.

String location[] = {"delhi","banglore","mathura","lucknow","chandigarh","mumbai"};
int index;
String temp;
Random random = new Random();
for(int i=1;i<location.length;i++)
{
    index = random.nextInt(i+1);
    temp = location[index];
    location[index] = location[i];
    location[i] = temp;
    System.out.println("Location Based On Random Values :"+location[i]);
}
1
Archit Goel

Le code le plus simple à mélanger:

import Java.util.*;
public class ch {
    public static void main(String args[])
    {
        Scanner sc=new Scanner(System.in);
        ArrayList<Integer> l=new ArrayList<Integer>(10);
        for(int i=0;i<10;i++)
            l.add(sc.nextInt());
        Collections.shuffle(l);
        for(int j=0;j<10;j++)
            System.out.println(l.get(j));       
    }
}
1
suraj

Je me fie à cette question très populaire parce que personne n'a écrit une version en copie aléatoire. Le style est fortement emprunté à Arrays.Java, car qui n’est pas pillant la technologie Java de nos jours? Implémentations génériques et int incluses.

   /**
    * Shuffles elements from {@code original} into a newly created array.
    *
    * @param original the original array
    * @return the new, shuffled array
    * @throws NullPointerException if {@code original == null}
    */
   @SuppressWarnings("unchecked")
   public static <T> T[] shuffledCopy(T[] original) {
      int originalLength = original.length; // For exception priority compatibility.
      Random random = new Random();
      T[] result = (T[]) Array.newInstance(original.getClass().getComponentType(), originalLength);

      for (int i = 0; i < originalLength; i++) {
         int j = random.nextInt(i+1);
         result[i] = result[j];
         result[j] = original[i];
      }

      return result;
   }


   /**
    * Shuffles elements from {@code original} into a newly created array.
    *
    * @param original the original array
    * @return the new, shuffled array
    * @throws NullPointerException if {@code original == null}
    */
   public static int[] shuffledCopy(int[] original) {
      int originalLength = original.length;
      Random random = new Random();
      int[] result = new int[originalLength];

      for (int i = 0; i < originalLength; i++) {
         int j = random.nextInt(i+1);
         result[i] = result[j];
         result[j] = original[i];
      }

      return result;
   }
1
QED

Il y a une autre façon aussi, pas encore poster

//that way, send many object types diferentes
public anotherWayToReciveParameter(Object... objects)
{
    //ready with array
    final int length =objects.length;
    System.out.println(length);
    //for ready same list
    Arrays.asList(objects);
}

de cette façon plus facile, dépend du contexte

1
Marcelo Ferreira

C'est l'algorithme de shuth shuffle.

public class Knuth { 

    // this class should not be instantiated
    private Knuth() { }

    /**
     * Rearranges an array of objects in uniformly random order
     * (under the assumption that <tt>Math.random()</tt> generates independent
     * and uniformly distributed numbers between 0 and 1).
     * @param a the array to be shuffled
     */
    public static void shuffle(Object[] a) {
        int n = a.length;
        for (int i = 0; i < n; i++) {
            // choose index uniformly in [i, n-1]
            int r = i + (int) (Math.random() * (n - i));
            Object swap = a[r];
            a[r] = a[i];
            a[i] = swap;
        }
    }

    /**
     * Reads in a sequence of strings from standard input, shuffles
     * them, and prints out the results.
     */
    public static void main(String[] args) {

        // read in the data
        String[] a = StdIn.readAllStrings();

        // shuffle the array
        Knuth.shuffle(a);

        // print results.
        for (int i = 0; i < a.length; i++)
            StdOut.println(a[i]);
    }
}
1
BufBills

Une des solutions consiste à utiliser la permutation pour pré-calculer toutes les permutations et les stocker dans la liste ArrayList.

Java 8 a introduit une nouvelle méthode, ints (), dans la classe Java.util.Random. La méthode ints () renvoie un flux illimité de valeurs int pseudo-aléatoires. Vous pouvez limiter les nombres aléatoires entre une plage spécifiée en fournissant les valeurs minimale et maximale.

Random genRandom = new Random();
int num = genRandom.nextInt(arr.length);

Avec l’aide de la génération du nombre aléatoire, vous pouvez parcourir la boucle et permuter avec l’index en cours avec le nombre aléatoire .. C’est ainsi que vous pouvez générer un nombre aléatoire avec une complexité d’espace O(1).

0
Maulik Sakhida

L'utilisation de Ints.asList() de Guava est aussi simple que:

Collections.shuffle(Ints.asList(array));
0
BeeOnRope
public class ShuffleArray {
public static void shuffleArray(int[] a) {
    int n = a.length;
    Random random = new Random();
    random.nextInt();
    for (int i = 0; i < n; i++) {
        int change = i + random.nextInt(n - i);
        swap(a, i, change);
    }
}

private static void swap(int[] a, int i, int change) {
    int helper = a[i];
    a[i] = a[change];
    a[change] = helper;
}

public static void main(String[] args) {
    int[] a = new int[] { 1, 2, 3, 4, 5, 6, 6, 5, 4, 3, 2, 1 };
    shuffleArray(a);
    for (int i : a) {
        System.out.println(i);
    }
}
}
0
nikhil gupta

similaire sans utiliser swap b

        Random r = new Random();
    int n = solutionArray.length;
    List<Integer> arr =  Arrays.stream(solutionArray).boxed().collect(Collectors.toList());
    for (int i = 0; i < n-1; i++) {
        solutionArray[i] = arr.remove( r.nextInt(arr.size())); // randomize base on size
    }
    solutionArray[n-1] = arr.get(0);
0
digitebs
import Java.util.ArrayList;
import Java.util.Random;
public class shuffle {
    public static void main(String[] args) {
        int a[] =  {1,2,3,4,5,6,7,8,9};
         ArrayList b = new ArrayList();
       int i=0,q=0;
       Random Rand = new Random();

       while(a.length!=b.size())
       {
           int l = Rand.nextInt(a.length);
//this is one option to that but has a flaw on 0
//           if(a[l] !=0)
//           {
//                b.add(a[l]);
//               a[l]=0;
//               
//           }
//           
// this works for every no. 
                if(!(b.contains(a[l])))
                {
                    b.add(a[l]);
                }



       }

//        for (int j = 0; j <b.size(); j++) {
//            System.out.println(b.get(j));
//            
//        }
System.out.println(b);
    }

}
0
aurobind singh