IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Python Discussion :

[Python 3.X] Création de coordonnées aléatoires sans répétition


Sujet :

Python

  1. #1
    Nouveau Candidat au Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Décembre 2016
    Messages
    1
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 28
    Localisation : France, Haut Rhin (Alsace)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Décembre 2016
    Messages : 1
    Points : 1
    Points
    1
    Par défaut [Python 3.X] Création de coordonnées aléatoires sans répétition
    Salut à tous !

    Je suis actuellement en 1ère année de CPGE et j'ai pour projet de travailler sur un TIPE lié à python, et je rencontre un "petit" problème qui suite à des recherches sur Google, ne semble pas pouvoir se résoudre simplement (du moins, je pense)

    Du coup voilà ce que je veux faire : créer un tableau contenant NbPt points de coordonnées aléatoires, et leurs coordonnées doivent être toutes différentes les unes des autres (pas de répétition de coordonnées du genre 2 points au même endroit, ni 2 points de mêmes abscisses/ordonnées). La fonction Point est créer , et à priori marche très bien (j'ai vérifier sur plusieurs cours en ligne, ça c'est bon)

    Ce que je n'arrive pas à faire : justement, c'est cette histoire de coordonnées totalement différentes qui n'aboutit pas... J'ai essayé plusieurs méthode et voilà le code qui, selon moi, est le plus aboutit :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
     
    import random
    def Tableau(NbPt):
        liste=[]
        for i in range (NbPt):
            a=random.randint(0,20)
            b=random.randint(0,20)
            if a!=b :
                for i in range (len(liste)):
                    if liste[i]!=a and liste[i]!=b :
                        liste.append(Point(a,b))
        return liste
    Ici je veux des coordonnées aléatoires comprises entre 0 et 20 ; mais le problème c'est que j'ai ce messages d'erreur () :
    File "H:\TIPE1.py", line 15, in Tableau
    if liste[i]!=a and liste[i]!=b :
    IndexError: list index out of range
    Du coup, semblerait il que je ne puisse pas comparer à chaque fois les coordonnées aux précédentes pour vérifier qu'elles soient non seulement différentes entre elles mais aussi différentes à celles qui les précèdent
    J'avais également tenter de créer 2 listes de nombres tous différents et d'ensuite piocher dans ces listes avec la fonction "sample" mais pas moyen d'aboutir, j'ai des messages d'erreurs ou alors des points qui ont parfois les mêmes abscisses/ordonnées

    Est ce qu'un petit coup de main serait possible ?

    Merci d'avance !

    EDIT : j'ai oublié de préciser (même si ça pourrait peut être sembler logique pour certains, je sais pas) mais "a" c'est l'abscisse du point et "b" l'ordonnée

  2. #2
    Rédacteur/Modérateur

    Homme Profil pro
    Ingénieur qualité méthodes
    Inscrit en
    Décembre 2013
    Messages
    4 038
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur qualité méthodes
    Secteur : Conseil

    Informations forums :
    Inscription : Décembre 2013
    Messages : 4 038
    Points : 9 347
    Points
    9 347
    Par défaut
    Ton tableau Liste contient des points (c.a.d des couples d'entiers) et non des entiers.
    Je verrais donc plutôt :

    if liste[i,1] != a and liste[i,2] != b ... mais je ne suis pas sûr du tout de la syntaxe.

    Sinon, comme ton nombre de valeurs (21*21) est assez limité, je ferais d'une autre façon :

    Etape 1. Tu prépares un tableau de 21x21 couples d'entiers : tous les points possibles (un peu moins peut-être car tu t'interdis les points de la diagonale de ce tableau). Appelons ce tableau complet le catalogue.

    Etape 2: Si tu veux X points différents, tu boucles X fois, et à chaque passage , tu sélectionnes aléatoirement 1 des points de ce tableau.
    Au 1er passage, tu choisis donc un nombre aléatoire entre 0 et 440, et tu prends l'élément correspondant.
    Bien entendu, tu retires ce couple du 'catalogue'
    Et au n-ième passage, tu choisis un nombre entre 0 et 440-n (puisqu'il n'y a plus que 441-n points dans le catalogue ), et tu prends ce point.
    N'oubliez pas le bouton Résolu si vous avez obtenu une réponse à votre question.

  3. #3
    Expert éminent sénior
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 241
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Manche (Basse Normandie)

    Informations professionnelles :
    Activité : Architecte technique retraité
    Secteur : Industrie

    Informations forums :
    Inscription : Juin 2008
    Messages : 21 241
    Points : 36 698
    Points
    36 698
    Par défaut
    Salut,

    Citation Envoyé par BlackShark68 Voir le message
    Est ce qu'un petit coup de main serait possible ?
    Le code que vous montrez ne peut pas produire cette erreur.
    Relisez:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
                for i in range (len(liste)):
                    if liste[i]!=a and liste[i]!=b :
                        liste.append(Point(a,b))
    Comme liste est initialisée à [], len(liste) est 0 et range(0) retournant une liste vide, on entrera jamais dans le corps de la boucle.
    nota: si la liste contient des objets Point(a,b), liste[i] sera toujours différents de a et b qui sont "entiers"... liste[i].a et liste[i].b sont peut être les valeurs à tester (mais on ne sait pas comment sont construits ces Points). Vous ajoutez un nouveau Point dans liste autant de fois qu'il y aura de points avec différents dans la liste (et non quand la liste ne contient pas le nouveau candidat...)

    Par ailleurs, écrire:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    def Tableau(NbPt):
        ...
        for i in range (NbPt):
            ...
                for i in range (len(liste)):
                     ...
    i.e. utiliser dans une boucle interne le même indice que la boucle externe va peut être fonctionner dans ce cas particulier mais a tendance à créer des effets de bords indésirables (et des comportements difficiles à comprendre).

    Enfin réfléchissez un peu, votre fonction est supposée retourner une liste de longueur NbPt, si vous écrivez "for i in range (NbPt):" vous allez essayez d'ajouter NbPt fois... et comme il y aura de mauvais points, à la sortie, la liste sera <= NbPt. Ce n'est pas ce que vous voulez!

    Ca fait quand même pas mal de problèmes pour ces quelques lignes de code...

    Ne serait-il pas plus "simple" de formuler "tant que la liste ne contient pas NbPt éléments essayons d'ajouter un point..."?

    Après côté technique, pour choisir (a, b) distincts dans 0..19 x 0..19, il est plus simple d'écrire:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    >>> numbers = list(range(0, 20))
    >>> random.shuffle(numbers)
    i.e. on prend 20 nombres différents, on mélange et on prend les deux premiers:
    Par construction, ab[0] et ab[1] sont différents.
    Pour tester qu'ils ne sont pas dans liste, on peut utiliser "in":
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    >>> if ab not in liste:
    ...    liste.append(ab)
    ...
    In fine, il n'y a plus de boucle "for" qui traînent et comme on ne fait que des .append à la liste, impossible d'avoir des IndexError...

    - W
    Architectures post-modernes.
    Python sur DVP c'est aussi des FAQs, des cours et tutoriels

  4. #4
    Expert éminent

    Homme Profil pro
    Inscrit en
    Octobre 2008
    Messages
    4 298
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations forums :
    Inscription : Octobre 2008
    Messages : 4 298
    Points : 6 778
    Points
    6 778
    Par défaut
    Salut,

    Soyons Python, soyons simple.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
    import random
    def Tableau(npts):
        points = set()
        while len(points) < npts:
            points.add((random.randint(0,20), random.randint(0,20)))
        return points

  5. #5
    Expert éminent sénior
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 241
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Manche (Basse Normandie)

    Informations professionnelles :
    Activité : Architecte technique retraité
    Secteur : Industrie

    Informations forums :
    Inscription : Juin 2008
    Messages : 21 241
    Points : 36 698
    Points
    36 698
    Par défaut
    Citation Envoyé par VinsS Voir le message
    Salut,

    Soyons Python, soyons simple.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
    import random
    def Tableau(npts):
        points = set()
        while len(points) < npts:
            points.add((random.randint(0,20), random.randint(0,20)))
        return points
    Rien n'exclut la diagonale... N'est ce pas trop simple?

    - W
    Architectures post-modernes.
    Python sur DVP c'est aussi des FAQs, des cours et tutoriels

  6. #6
    Membre émérite
    Homme Profil pro
    sans emploi
    Inscrit en
    Janvier 2014
    Messages
    539
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 51
    Localisation : France, Moselle (Lorraine)

    Informations professionnelles :
    Activité : sans emploi
    Secteur : Conseil

    Informations forums :
    Inscription : Janvier 2014
    Messages : 539
    Points : 2 601
    Points
    2 601
    Par défaut
    Bonjour,

    Si tu choisis N points Pi de coordonnées entières tels que leurs coordonnées (xi,yi) vérifient 0≤xi<MaxX et 0≤yi<MaxY avec 0≤i≤N≤min(MaxX,MaxY) alors je pense que le plus simple est de créer une permutation de [0,MaxX[ et une permutation de [0,MaxY[ et de prendre les abscisses dans la première permutation, les ordonnées dans la seconde.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    abs = list(range(0,MaxX))
    ord = list(range(0,MaxY))
    random.shuffle(abs)
    random.shuffle(ord)
    points = list(zip( abs[:N+1], ord[:N+1]))

  7. #7
    Expert éminent

    Homme Profil pro
    Inscrit en
    Octobre 2008
    Messages
    4 298
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations forums :
    Inscription : Octobre 2008
    Messages : 4 298
    Points : 6 778
    Points
    6 778
    Par défaut
    Citation Envoyé par picodev Voir le message
    Bonjour,

    Si tu choisis N points Pi de coordonnées entières tels que leurs coordonnées (xi,yi) vérifient 0≤xi<MaxX et 0≤yi<MaxY avec 0≤i≤N≤min(MaxX,MaxY) alors je pense que le plus simple est de créer une permutation de [0,MaxX[ et une permutation de [0,MaxY[ et de prendre les abscisses dans la première permutation, les ordonnées dans la seconde.
    Est-ce que tu te comprends toi-même ?

  8. #8
    Expert éminent

    Homme Profil pro
    Inscrit en
    Octobre 2008
    Messages
    4 298
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations forums :
    Inscription : Octobre 2008
    Messages : 4 298
    Points : 6 778
    Points
    6 778
    Par défaut
    Citation Envoyé par wiztricks Voir le message
    Rien n'exclut la diagonale... N'est ce pas trop simple?

    - W
    Salut wiztricks,

    Mon intention n'est, bien sur, pas de réduire à rien le travail de l'OP mais de proposer d'abord le travail principal par la simplicité et puis le détail on verra après.

  9. #9
    Rédacteur/Modérateur

    Homme Profil pro
    Ingénieur qualité méthodes
    Inscrit en
    Décembre 2013
    Messages
    4 038
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur qualité méthodes
    Secteur : Conseil

    Informations forums :
    Inscription : Décembre 2013
    Messages : 4 038
    Points : 9 347
    Points
    9 347
    Par défaut
    On est sur un forum python, c'est donc bien de montrer la syntaxe python. Si l'OP était intéressé par le côté algorithme, c'est vrai qu'il aurait posé la question sur un forum algorithme.
    N'oubliez pas le bouton Résolu si vous avez obtenu une réponse à votre question.

  10. #10
    Membre émérite
    Homme Profil pro
    sans emploi
    Inscrit en
    Janvier 2014
    Messages
    539
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 51
    Localisation : France, Moselle (Lorraine)

    Informations professionnelles :
    Activité : sans emploi
    Secteur : Conseil

    Informations forums :
    Inscription : Janvier 2014
    Messages : 539
    Points : 2 601
    Points
    2 601
    Par défaut
    Ce que le PO désire :
    Citation Envoyé par BlackShark68 Voir le message
    Du coup voilà ce que je veux faire : créer un tableau contenant NbPt points de coordonnées aléatoires, et leurs coordonnées doivent être toutes différentes les unes des autres (pas de répétition de coordonnées du genre 2 points au même endroit, ni 2 points de mêmes abscisses/ordonnées). La fonction Point est créer , et à priori marche très bien (j'ai vérifier sur plusieurs cours en ligne, ça c'est bon)
    C'est en gros «j'ai un carré et je veux y prendre une liste de plusieurs points. Ces points sont tous différents (pas deux pareils) et en plus aucun point ne partage la même abscisse ou ordonnée qu'un autre point = il est seul sur sa ligne et sur sa colonne».

    Citation Envoyé par VinsS Voir le message
    Est-ce que tu te comprends toi-même ?
    Bah, si tu n'as pas compris mon explication (désolé de parler math) ce n'est pas grave ; je pense que tu auras mieux compris le code python qui répond exactement à la demande du PO. En plus simple c'est une sorte de fisher yates en 2D (désolé de parler algo …).

    A priori le code que j'ai donné est le seul qui répond à sa demande en permettant le choix de n'importe quel point de la surface d'origine.

  11. #11
    Expert éminent Avatar de BufferBob
    Profil pro
    responsable R&D vidage de truites
    Inscrit en
    Novembre 2010
    Messages
    3 035
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations professionnelles :
    Activité : responsable R&D vidage de truites

    Informations forums :
    Inscription : Novembre 2010
    Messages : 3 035
    Points : 8 400
    Points
    8 400
    Par défaut
    salut,

    Citation Envoyé par picodev Voir le message
    Si tu choisis N points Pi de coordonnées entières tels que leurs coordonnées (xi,yi) vérifient 0≤xi<MaxX et 0≤yi<MaxY avec 0≤i≤N≤min(MaxX,MaxY) alors je pense que le plus simple est de créer une permutation de [0,MaxX[ et une permutation de [0,MaxY[ et de prendre les abscisses dans la première permutation, les ordonnées dans la seconde.
    parce que si on prend 20 fois une valeur aléatoire, on est pas assuré à la fin d'avoir 20 valeurs uniques
    du coup on prend la liste de nombres jusqu'à Max{x,y} dans sa totalité, on la mélange, et on en récupère les 20 premières valeurs

    quant à l'histoire de la diagonale, j'ai plutôt compris ça comme le fait qu'on ne doit pas avoir un point (15,10) et un point (15,8) par exemple, mais un point (6,6) est autorisé

    c'est bien ça ?

  12. #12
    Expert éminent

    Homme Profil pro
    Inscrit en
    Octobre 2008
    Messages
    4 298
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations forums :
    Inscription : Octobre 2008
    Messages : 4 298
    Points : 6 778
    Points
    6 778
    Par défaut
    Le fait que des abscisses ou ordonnées ne puissent être utilisées deux fois est ce que j'appelle le "détail" dans mon poste précédent.

    Et n'a franchement rien de compliqué.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     
    >>> import random
    >>> base = [i for i in range(20)]
    >>> random.shuffle(base)
    >>> abscisses = base[:]
    >>> while abscisses == base:
    ...     random.shuffle(base)
    ... 
    >>> points = [(a, o) for a, o in zip(abscisses, base)]
    >>> points
    [(18, 10), (2, 9), (14, 8), (9, 1), (12, 16), (8, 15), (15, 17), (5, 7), (16, 3), (1, 6), (0, 14), (6, 5), (11, 4), (19, 0), (10, 18), (3, 2), (4, 13), (7, 19), (13, 11), (17, 12)]
    Faudra sans doute rajouter une vérification de coordonnées identiques si celles-ci sont indésirables aussi.

  13. #13
    Rédacteur/Modérateur

    Homme Profil pro
    Ingénieur qualité méthodes
    Inscrit en
    Décembre 2013
    Messages
    4 038
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur qualité méthodes
    Secteur : Conseil

    Informations forums :
    Inscription : Décembre 2013
    Messages : 4 038
    Points : 9 347
    Points
    9 347
    Par défaut
    L'intitulé est très ambigu sur ces questions. Dans le code initial, il y a un test si a <> b , ce qui sous-entend que la diagonale serait interdite.
    Ca ne m'étonnerait pas que le vrai problème soit une généralisation mal comprise du problème des 8 dames.
    N'oubliez pas le bouton Résolu si vous avez obtenu une réponse à votre question.

  14. #14
    Membre émérite
    Homme Profil pro
    sans emploi
    Inscrit en
    Janvier 2014
    Messages
    539
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 51
    Localisation : France, Moselle (Lorraine)

    Informations professionnelles :
    Activité : sans emploi
    Secteur : Conseil

    Informations forums :
    Inscription : Janvier 2014
    Messages : 539
    Points : 2 601
    Points
    2 601
    Par défaut
    Citation Envoyé par tbc92 Voir le message
    L'intitulé est très ambigu sur ces questions. Dans le code initial, il y a un test si a <> b , ce qui sous-entend que la diagonale serait interdite.
    Ca ne m'étonnerait pas que le vrai problème soit une généralisation mal comprise du problème des 8 dames.
    Si on essaye de décoder le code du PO :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    import random
    def Tableau(NbPt):
        liste=[]
        for i in range (NbPt):
            a=random.randint(0,20)
            b=random.randint(0,20)
            if a!=b :
                for i in range (len(liste)):
                    if liste[i]!=a and liste[i]!=b :
                        liste.append(Point(a,b))
        return liste
    On peut imaginer que la ligne 7 essaye d'éviter des points sur la diagonale, et que la ligne 9 essaye de contraindre un point par abscisse et un point par ordonnée.
    D'un certain point de vue ça simplifie les choses car on peut réduire le problème à trouver un dérangement (une permutation sans point fixe) dans lequel on choisi les points.
    Pour donner un exemple simple on va partir d'une grille 6×6. Un dérangement de (0,1,2,3,4,5) peut être (5,2,1,0,3,4). À ce dérangement correspondent les points [ (0,5), (1,2), (2,1), (3,0), (4,3), (5,4) ]. Après il faut en choisir uniformément le nombre voulu.
    C'est une méthode simple pour une grille carrée. Pour une grille plus large que haute on ne peut plus se contenter d'énumérer les éléments d'un dérangement. Pour une grille plus haute que large on peut réduire le problème au cas précédent par transposition.

    Donc dans le cas d'une grille carrée de taille grid_size×grid_size on a un code relativement simple pour choisir count points :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    from random import shuffle, sample
     
    def pick( grid_size, count ):
      ys=list(range(grid_size))
      while not all(i!=y for i,y in enumerate(ys)):
        shuffle(ys)
      return sample( list(enumerate(ys)), count )

  15. #15
    Expert éminent sénior
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 241
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Manche (Basse Normandie)

    Informations professionnelles :
    Activité : Architecte technique retraité
    Secteur : Industrie

    Informations forums :
    Inscription : Juin 2008
    Messages : 21 241
    Points : 36 698
    Points
    36 698
    Par défaut
    Soit on lit l'énoncé, soit on essaie de déchiffrer ce qu'essaie de faire le code (et il fait autre chose) et de comprendre pourquoi il plante en IndexError.
    Ce qui fait pleins de sujets tant côté algo. que programmation.

    Côté programmation, un des soucis du PO est d'être encore trop débutant pour écrire des lignes de code sans trop comprendre ce que la machine va bien pouvoir en faire. C'est un problème que lui seul pourra résoudre en passant du temps à pianoter à la console Python... Et proposer une solution toute faite l'aidera sans doute à reporter à plus tard ce pianotage mais ne le fera pas beaucoup progresser.

    - W
    Architectures post-modernes.
    Python sur DVP c'est aussi des FAQs, des cours et tutoriels

Discussions similaires

  1. [OpenOffice][Texte] Création d'une TOC sans IHM
    Par lekekoo dans le forum OpenOffice & LibreOffice
    Réponses: 2
    Dernier message: 25/05/2007, 17h09
  2. Réponses: 6
    Dernier message: 23/02/2007, 17h27
  3. création des images gif sans arrière plan
    Par Amissan dans le forum Flash
    Réponses: 3
    Dernier message: 08/12/2006, 21h20
  4. Heure de création d'un enregistrement sans attribut DATE
    Par Cofondinde dans le forum Oracle
    Réponses: 1
    Dernier message: 06/09/2006, 17h42
  5. Création d'une fonction sans paramètre?
    Par falcon dans le forum Oracle
    Réponses: 3
    Dernier message: 13/12/2004, 12h32

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo