Permutations d'éléments de matrice

Fermé
quaze Messages postés 9 Date d'inscription mardi 25 juin 2013 Statut Membre Dernière intervention 4 février 2014 - 25 juin 2013 à 14:57
KX Messages postés 16734 Date d'inscription samedi 31 mai 2008 Statut Modérateur Dernière intervention 24 avril 2024 - 27 juin 2013 à 10:16
Salut,

J'ai une matrice M de taille n*m (ArrayList d'arrayList).
Je voudrais calculer les "permutations" en ne prenant qu'un seul élément par ligne :

par exemple pour M de taille 3lignes 2 colonnes avec M = [[a,b];[c;d];[e;f]]
je veux qu'il me donne ace acf ade adf bce bcf bde bdf.

Je m'embrouille avec mes boucles for...

Merci ;)

5 réponses

KX Messages postés 16734 Date d'inscription samedi 31 mai 2008 Statut Modérateur Dernière intervention 24 avril 2024 3 015
26 juin 2013 à 21:16
J'ai retrouvé le code que je cherchais, avant de te le donner tel quel (c'est un peu long même si tu pourras en supprimer une grande partie), voici un exemple d'utilisation qui te permettras de faire ce que tu veux (il faudra bien sûr adapter avec tes ClasseBidon ou autres)

public class TestEnumerator 
{
    public static void main(String[] args)
    {
        String[][] mat = {{"a","b"},{"c","d"},{"e","f"}};
        int m = mat.length;
        int n = mat[0].length;

        Enumerator enumerator = new Enumerator(m, Enumerator.Bounds(0), Enumerator.Bounds(n), Enumerator.Bounds(1), false);

        while (enumerator.hasNext())
        {
            long[] index = enumerator.next();

            for (int i=0; i<m; i++)
                System.out.print(mat[i][(int) index[i]]);

            System.out.println();
        }
    }
}

Ce qui affichera :
ace
acf
ade
adf
bce
bcf
bde
bdf

Voici le code de la classe Enumerator, c'est en parti documenté et il y a quelques exemples d'utilisation dans le main...

import java.util.Arrays;
import java.util.HashSet;

/**
 * Un énumérateur pour simuler l'imbrication de plusieurs boucles for.
 * On génère un tableau où chaque valeur est progressivement incrémenté à chaque pas.
 * 
 * Le mode strict permet de ne conserver que les occurences qui contiennent des valeurs distinctes.
 */
public class Enumerator
{
    /**
     * Décrit une des trois bornes de la boucle for.
     */
    protected static class Bounds
    {
        private Long n;
        private long[] tab;

        /**
         * Décrit une des trois bornes de la boucle for.
         * L'un des deux paramètre devrait être null.
         * @param n entier qui remplit toutes les valeurs du tableau, ou null
         * @param tab le tableau qui contient toutes les valeurs du tableau, ou null
         */
        private Bounds(Long n,long[] tab)
        {
            this.n=n;
            this.tab=tab;
        }
    }

    /**
     * Construit une borne de la boucle for, en imposant la même valeur entière pour toutes les boucles.
     * @param n l'entier de la borne
     * @return la borne de la boucle
     */
    public static Bounds Bounds(long n)
    {
        return new Bounds(n,null);
    }

    /**
     * Construit une borne de la boucle for, en imposant toutes les valeurs du tableau.
     * @param tab les valeurs que doivent prendre les boucles
     * @return la borne de la boucle
     */
    public static Bounds Bounds(long...tab)
    {
        if (tab==null)
            throw new NullPointerException();

        return new Bounds(null,tab);
    }

    /**
     * Une exception générée lorsqu'il n'y a pas correspondance entre le nombre de boucles imbriquées et la taille des bornes.
     */
    protected class DimensionException extends RuntimeException
    {
        private static final long serialVersionUID = 1;

        protected DimensionException(String message)
        {
            super(message);
        }
    }

    private transient final HashSet<Long> cacheStrict;

    /** Choix du mode strict ou non. */
    protected final boolean strict;

    /** Le tableau des valeurs initiales (inclues). */
    protected final long[] tabB;

    /** Le tableau des valeurs finales (exclues). */
    protected final long[] tabE;

    /** Le tableau des valeurs d'incrémentations. */
    protected final long[] tabI;

    /** Le tableau des valeurs courantes. */
    protected final long[] tab;

    /** Le nombre de boucles imbriquées. */
    protected final int n;

    /** S'il reste des valeurs à itérer. */
    protected boolean has;

    /**
     * @param tab1 le tableau à initialiser
     * @param tab2 les valeurs du tableau de valeurs, ou null
     * @param val la valeur à donner à chaque case de tab1
     * @param str le rôle du tableau (pour le message d'erreur)
     * @throws DimensionException si tab2 est de taille inférieur à n
     * @throws NullPointerException si tab2 et val sont tous deux null
     */
    private void setTab(long[] tab1, long[] tab2, Long val, String str)
    {
        if (tab2==null)
        {
            if (val==null)
                throw new NullPointerException("Array and Integer representations of '"+str+"' Bounds can't be twice null.");

            for (int i=0; i<n; i++)
                tab1[i]=val;
        }
        else if (tab1.length<n)
        {
            throw new DimensionException("Array length of parameter '"+str+"' must be at least equals at parameter 'dim'");
        }
        else
        {
            for (int i=0; i<n; i++)
                tab1[i]=tab2[i];
        }
    }

    public Enumerator(int dim,Bounds begin,Bounds end,Bounds incr,boolean strict)
    {
        if (dim<=0)
            throw new DimensionException("Value of parameter 'dim' must be strictly positive");
        else
            n=dim;

        tab = new long[n];
        setTab(tab,begin.tab,begin.n,"begin");

        tabB = new long[n];
        setTab(tabB,begin.tab,begin.n,"begin");

        tabE = new long[n];
        setTab(tabE,end.tab,end.n,"end");

        tabI = new long[n];
        setTab(tabI,incr.tab,incr.n,"incr");

        has=true;

        this.strict = strict;

        if (strict)
        {
            cacheStrict = new HashSet<Long>(n);
            checkStrict();
        }
        else 
        {
            cacheStrict = null;
        }
    }

    public Enumerator(int dim,long[] begin,long[] end,long[] incr,boolean strict)
    {
        this(dim,new Bounds(0L,begin),new Bounds(1L,end),new Bounds(1L,incr),strict);
    }

    public Enumerator(int dim,long begin,long end,long incr,boolean strict)
    {
        this(dim,Bounds(begin),Bounds(end),Bounds(incr),strict);
    }

    public boolean hasNext()
    {
        return has;
    }

    public long[] get()
    {
        long[] res = new long[n];
        for (int i=0; i<n; i++)
            res[i]=tab[i];
        return res;
    }

    protected void incr()
    {
        has=false;

        for (int i=n-1; i>=0; i--)
        {
            tab[i]+=tabI[i];

            if ((tabI[i]>=0) ? tab[i]<tabE[i] : tab[i]>tabE[i])
            {
                has=true;
                break;
            }
            else
            {
                tab[i]=tabB[i];
            }
        }
    }

    protected void checkStrict()
    {
        while (has)
        {
            cacheStrict.clear();

            for (int i=0; i<n; i++)
            {
                if (cacheStrict.contains(tab[i]))
                    break;
                else
                    cacheStrict.add(tab[i]);
            }

            if (cacheStrict.size()==n)
                break;
            else
                incr();
        }
    }

    public long[] next()
    {
        long[] res = get();

        incr();

        if (strict)
            checkStrict();

        return res;
    }

    @Override
    public String toString()
    {
        return "for (long i="+Arrays.toString(tabB)+"; i<"+Arrays.toString(tabE)+"; i+="+Arrays.toString(tabI)+");";
    }

    private static void test(Enumerator e)
    {
        System.out.println(e);
        while (e.hasNext())
        {
            for (long l : e.next())
                System.out.print(l+" ");

            System.out.println();
        }
        System.out.println();
    }

    public static void main(String...args)
    {
        test(new Enumerator(3,0,3,1,false));
        test(new Enumerator(3,0,3,1,true));        
        test(new Enumerator(3,Bounds(0),Bounds(3),Bounds(1),true));
        test(new Enumerator(3,new long[]{0,0,0},new long[]{3,3,3},new long[]{1,1,1},true));
        test(new Enumerator(3,Bounds(0,0,0),Bounds(3,3,3),Bounds(1,1,1),true));
    }
}
1
KX Messages postés 16734 Date d'inscription samedi 31 mai 2008 Statut Modérateur Dernière intervention 24 avril 2024 3 015
25 juin 2013 à 15:19
Pourquoi avoir pris une ArrayList<ArrayList> ? Vu ce que tu expliques, la taille de la matrice est fixe (n*m) donc un tableau à deux dimensions tab[][] aurait été plus léger (c'est une simple question de performance...)

Sinon, fais voir tes boucles for où tu t'embrouilles, ainsi que le reste de ton code, ce sera plus facile pour t'aider.
0
quaze Messages postés 9 Date d'inscription mardi 25 juin 2013 Statut Membre Dernière intervention 4 février 2014
25 juin 2013 à 15:40
Disons que c'est un peu plus compliqué, mes ClasseBidon sont d'autres classes du projet, tableIteration est correctement initialisé (cf commentaires) mais ça devrait vous donner une idée :

public class test {

	/**
	 * @param args
	 */

	public static void main(String[] args) {
		ArrayList<ArrayList<ClasseBidon3>> tableIteration = new ArrayList<ArrayList<ClasseBidon3>>();
		
		// tableIteration = this.createTable(); HERE
		int nbLignes= tableIteration.size();
		int nbColonnes = tableIteration.get(0).size();
		ClasseBidon s;
		ClasseBidon2 sortie;


		for (int i = 0; i < nbLignes; i++) {
			Map<String, ClasseBidon3> finalClasseBidon3 = new HashMap<String,ClasseBidon3>();
			ClasseBidon3 ti = tableIteration.get(0).get(i);

			for (int j =1; j< nbLignes; j++) {
				for (int k =0; k< nbColonnes; k++) {
					ClasseBidon3 t = tableIteration.get(j).get(k);
					finalClasseBidon3.put(t.getName(),t);
					finalClasseBidon3.put(t.getName(),ti);	
					s = new ClasseBidon(finalClasseBidon3);
					sortie.addClasseBidon(s);
				}

			}
		}
	}
	
	private class ClasseBidon {

		public ClasseBidon(Map<String, ClasseBidon3> finalClasseBidon3) {
			// TODO Auto-generated constructor stub
		}
		
	}
	private class ClasseBidon2 {

		public void addClasseBidon(ClasseBidon s) {
			// TODO Auto-generated method stub
			
		}
		
	}
	private class ClasseBidon3 {

		public String getName() {
			// TODO Auto-generated method stub
			return null;
		}
		
	}
}



merci beaucoup ;)
0
quaze Messages postés 9 Date d'inscription mardi 25 juin 2013 Statut Membre Dernière intervention 4 février 2014
26 juin 2013 à 09:17
Je dois pas être très clair, desolé de passer par des classesBidon, mais cela me permet de pas avoir à mettre tout le code de ces classes...

Pour essayer d'expliquer plus précisement ce que je veux faire, j'ai une fonction createTable qui me renvoie une arraylist d'arraylist (je vais effectivement changer pour des tableaux) de ClasseBidon3 (une matrice d'éléments ClasseBidon3). Je combiner chaque élément de chaque ligne avec les éléments de toutes les autres lignes.
L'ordre n'a pas d'importance.
A la fin, je veux avoir un tableau contenant nbcolonnes puissance nbLigne tableau t1, ou chaque tableau t1 à exactement nombreLigne éléments. Un tableau t1 contient : un unique élément de chaque ligne pour toputes les lignes. Tous les tabelaux t1 sont différents (je veux avoir toutes les permutations possibles)

Si vous avez des idées, hésitez-pas ;) merci
0
KX Messages postés 16734 Date d'inscription samedi 31 mai 2008 Statut Modérateur Dernière intervention 24 avril 2024 3 015
26 juin 2013 à 09:45
Je ne t'ai pas oublié, mais il faudrait que je retrouve un code que j'avais déjà fait dans le genre, et là je l'ai pas sous le coude...
0
quaze Messages postés 9 Date d'inscription mardi 25 juin 2013 Statut Membre Dernière intervention 4 février 2014
26 juin 2013 à 09:53
Merci ;)
0

Vous n’avez pas trouvé la réponse que vous recherchez ?

Posez votre question
Merci beaucoup !

Je vais pas faire le difficile mais je m'interroge quand même sur la possibilité de le faire plus "simplement", ie avec quelques boucles for...

En tout cas, j'ai adapté à mon projet, ca marche tout bien c'est parfait, merci !
0
KX Messages postés 16734 Date d'inscription samedi 31 mai 2008 Statut Modérateur Dernière intervention 24 avril 2024 3 015
27 juin 2013 à 10:16
Le problème des boucles for c'est qu'il en faudrait un nombre variable imbriquées les unes dans les autres, ce qu'il est impossible à faire de manière générale.

Si je reprends l'exemple que je t'ai donné, ma classe Enumerator est équivalente à ceci (à vérifier)

public class TestEnumerator 
{
    public static void main(String[] args)
    {
        String[][] mat = {{"a","b"},{"c","d"},{"e","f"}};

        long[] index = new long[3];

        for (index[0]=0; index[0]<2; index[0]++)
        for (index[1]=0; index[1]<2; index[1]++)
        for (index[2]=0; index[2]<2; index[2]++)
        {
            for (int i=0; i<3; i++)
                System.out.print(mat[i][(int) index[i]]);

            System.out.println();
        }
    }
}

Il est évident qu'avec ce code tu ne pourras jamais traiter d'autres matrices que celles de dimension 3, si tu devais traiter d'autres tailles tu devrais changer le code, ce qui est peu intéressant en programmation objet.

Moi j'avais fait ce code de manière suffisamment générale pour pouvoir être utilisé dans le plus grand nombre de cas possibles. Par exemple ton problème se résout immédiatement avec cette classe, sans avoir grand chose à coder en plus. Mais du coup une grande partie de mon code ne te sers pas, car il est destiné à d'autres usages,en particulier la gestion des permutations sans doublon, tu pourrais donc faire du ménage et ne garder que ce qui t'est vraiment utile.
Il peut cependant être intéressant de tout garder au cas où un jour tu veuilles modifier ton code et utiliser une fonctionnalité dont tu n'as pas utilité aujourd'hui mais qui serait déjà prise en charge par mon code... C'est tout l'intérêt de faire des classes les plus complètes possibles !
0