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 :

Liste aleatoire avec des conditions [Python 3.X]


Sujet :

Python

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre averti
    Homme Profil pro
    Technicien maintenance
    Inscrit en
    Août 2015
    Messages
    43
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Eure (Haute Normandie)

    Informations professionnelles :
    Activité : Technicien maintenance
    Secteur : Industrie

    Informations forums :
    Inscription : Août 2015
    Messages : 43
    Par défaut Liste aleatoire avec des conditions
    Bonjour à tous,

    Je manque de logique sur la façon de faire une liste bien particulière (ou un tableau si vous avez votre propre idée) :

    En gros j'ai besoin de générer une liste aléatoire mais avec des conditions. Pour l'instant j'ai réussi à faire 3 conditions mais je viens de voir que j'ai une exception que je n'avais pas prévu
    j'ai besoin de : une liste de 5 couples aleatoires (10 nombres) de 20 à 24 dans mon exemple, avec les conditions suivantes :
    1) jamais plus de 2 fois le même nombre dans une liste (ce qui revient à avoir obligatoirement chaque nombre présent 2 fois en tout dans la liste)
    2) jamais deux nombres identiques dans un même couple
    3) ce que je n'arrive pas à faire : jamais deux couples identiques au sein de la liste (si j'ai (20,21), je ne veux pas d'un autre (20,21), ni d'un (21,20)
    De plus le problème qu'il peut arriver c'est que la seule combinaison possible restante soit deux nombres identiques (mais donc impossible et ça boucle en continu)

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
     
    couples = []
    i = 0
    while len(couples) < 10:
        couples.append(randrange(20, 25))
        #Si l'alea en cours est égal à sa paire
        if i%2 == 1 and couples[i] == couples[i-1]:
            #le supprimer de la liste
            del couples[i]
            continue
        #Si on arrive au dernier alea et qu'il y a plus de 2 fois le meme nombre
        if i == 9 and couples.count(couples[i])>= 3 :
            #Reinitialiser la liste
            couples = []
            i = 0
            continue
        #A partir du deuxième couple, s'il y a plus de 2 fois le même nombre
        if i >= 2 and couples.count(couples[i])>= 3 :
            #supprimer l'alea en cours
            del couples[i]
            continue
        else:
            i += 1
    Si vous avez une idée et même une façon plus simple et plus propre de faire ça je suis preneur (comparaison de tableau peut etre)
    Merci d'avance.

    Bon week-end.

  2. #2
    Membre chevronné
    Homme Profil pro
    BTS SN IR
    Inscrit en
    Mai 2017
    Messages
    514
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 26
    Localisation : France, Saône et Loire (Bourgogne)

    Informations professionnelles :
    Activité : BTS SN IR

    Informations forums :
    Inscription : Mai 2017
    Messages : 514
    Par défaut
    Bonjour, je te propose quelques pistes:

    - il faut que tu récupère chaque nombre de ta liste de tuple.
    - génère 2 nombres, c1 et c2 de façon aléatoire.
    - que tu regarde combien de fois c1 est présent dans cette liste, de même pour c2.
    - que tu regarde que le couple (c1, c2) ne soit pas déjà dans ta liste de tuple, de même pour le couple (c2, c1).

    si jamais je te propose ma façon, elle semble faire ce que tu souhaite:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
     
    import random
    couples = []
    while len(couples) < 5:
    	# on récupère toutes les valeurs de la variable couples
    	list_nb = []
    	for couple in couples:
    		for nb in couple:
    			list_nb.append(nb)
     
    	c1, c2 = random.randrange(20, 25), random.randrange(20, 25)  # on génère c1 et c2
    	if c1 != c2: #on vérifie qu'ils sont différents
    		if list_nb.count(c1) <2 and list_nb.count(c2) <2: # on que c1 soit moins de 2 fois dans la liste des nombres, de même pour c2
    			if (c1, c2) not in couples and (c2, c1) not in couples:
    				couples.append((c1, c2))
     
    print(couples)
    # [(23, 22), (22, 24), (21, 20), (23, 20), (24, 21)]

  3. #3
    Membre Expert

    Homme Profil pro
    Ingénieur calcul scientifique
    Inscrit en
    Mars 2013
    Messages
    1 229
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Alpes Maritimes (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Ingénieur calcul scientifique

    Informations forums :
    Inscription : Mars 2013
    Messages : 1 229
    Par défaut
    Un autre algorithme est également possible puisque l'on sait que chaque nombre entre 20 et 24 doit être présent exactement 2 fois au final. On démarre de la liste :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    x=[[20, 20], [21, 21], [22, 22], [23, 23], [24, 24]]
    puis on choisit deux nombre i1 et i2 entre 0 et 4, et deux nombres j1 et j2 entre 0 et 1.
    (i1,j1) et (i2,j2) nous donne ainsi des positions dans le tableau, que l'on va pouvoir intervertir :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    x[i1][j1],x[i2][j2] = x[i2][j2],x[i1][j1]
    On répète cela un nombre arbitraire de fois (mettons 100 fois). A la fin on vérifie que c'est bien mélangé, c'est à dire qu'on répond bien à tous les critères, du style aucun couple identique. Et si ce n'est pas le cas on recommence les interversions jusqu'à ce que les critères soient ok.

    Au lieu de faire 100 fois, on peut aussi ne pas se fixer de nombre d'itération et tester après chaque itération si le mélange est correct et s'arrêté dès qu'il l'est.

  4. #4
    Membre averti
    Homme Profil pro
    Technicien maintenance
    Inscrit en
    Août 2015
    Messages
    43
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Eure (Haute Normandie)

    Informations professionnelles :
    Activité : Technicien maintenance
    Secteur : Industrie

    Informations forums :
    Inscription : Août 2015
    Messages : 43
    Par défaut
    Merci de votre aide.
    Je suis sur un truc comme ça :
    (c'est pas mal mais j'ai une erreur à regler je vous tiens au jus)

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    #!/usr/bin/python
    # -*- coding: latin-1 -*-
     
    from random import randrange
     
    #Le nombre de connexion à un interrupteur par led (2 max)
    led = [0, 0, 0, 0, 0]
    #Tous les couples possible (éliminer les doublons)
    combines = [[1,2], [1,3], [1,4], [1,5], [2,3], [2,4], [2,5], [3,4], [3,5], [4,5]]
    #Les couples choisis au hasard par bouton
    button = []
     
     
    def removeCombineContaining(ledIndex):
        i = 0
        for combine in combines:
            #Si la combinaison contient la ledIndex
            if combine[0] == ledIndex or combine[1] == ledIndex:
                #Supprimer l'élément en question
                del combines[i]
     
            i += 1
     
     
     
     
    def couples():
        #Parcours des 5 interrupteurs
        for i in range(0, 5):
            #Choisir un nombre aléatoire entre 0 et la taille du tableau
            index = randrange(0, len(combines)-1)
            #Choisir l'élément choisi à l'index 'index' dans les différentes combinaisons (tmp est une liste de deux)
            tmp = combines[index]
            #Incrémenter les compteurs de connexion pour les 2 leds
            led[tmp[0]-1] += 1
            led[tmp[1]-1] += 1
            #Supprimer l'élément choisi de la liste de toutes les combinaisons
            del combines[index]
            #Si après avoir fait nos petites actions, la led 1 du couple choisi possède 2 connexions
            if led[tmp[0]-1] >= 2:
                #Supprimer les autres combinaisons contenant la led en question
                removeCombineContaining(tmp[0])
            #Si après avoir fait nos petites actions, la led 2 du couple choisi possède 2 connexions
            if led[tmp[1]-1] >= 2:
                #Supprimer les autres combinaisons contenant la led en question
                removeCombineContaining(tmp[1])
            #Une fois toutes les actions terminés, rajouter la combinaison dans le tableau des bouttons
            button.append(tmp)
     
     
    couples()

  5. #5
    Membre Expert

    Homme Profil pro
    Ingénieur calcul scientifique
    Inscrit en
    Mars 2013
    Messages
    1 229
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Alpes Maritimes (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Ingénieur calcul scientifique

    Informations forums :
    Inscription : Mars 2013
    Messages : 1 229
    Par défaut
    Si tu part de l'ensemble des couples possibles, alors dans ce cas tu as juste à mélanger cette liste (cf. random.shuffle) et à prendre ce qu'il te faut dedans dans l'ordre. Comme un jeu de cartes que tu as mélangé et ensuite tu pioches les cartes une à une dans l'ordre.

  6. #6
    Membre très actif

    Homme Profil pro
    Bidouilleur
    Inscrit en
    Avril 2016
    Messages
    721
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Bidouilleur

    Informations forums :
    Inscription : Avril 2016
    Messages : 721
    Billets dans le blog
    1
    Par défaut
    Salut.

    En utilisant comme tu as fait avec les combinaisons possibles et avec une exception.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    import random
    import itertools
     
    mini = 1
    maxi = 5
    nbCombi = 5 # ne peut excéder maxi
     
    sel = []
    combi = list(itertools.combinations(range(mini, maxi + 1), 2))
    choix = combi.copy()
    occur = dict.fromkeys(range(mini, maxi + 1), 0)
    i = 0
     
    while True :
        try :
            s = random.choice(choix)
        except IndexError :
            # Retour arrière sur 2 éléments
            for _ in range(2) :
                occur[sel[-1][0]] -= 1
                occur[sel[-1][1]] -= 1
                combi.append(sel.pop())
                i -= 1
        else :
            sel.append(s)
            i += 1
            if i == nbCombi :
                break
            combi.remove(s)
            occur[s[0]] += 1
            occur[s[1]] += 1
        finally :
            choix = [n for n in combi if occur[n[0]] < 2 and occur[n[1]] < 2]
     
    """
    # Eventuel mélange des valeurs
    ind = [0, 1]
    for i, s in enumerate(sel) :
        random.shuffle(ind)
        sel[i] = (s[ind[0]], s[ind[1]])
    """
     
    print("selection :", sel)
    Il faut gérer le cas où toutes les occurences sont à 2 et une reste à 0, ce qui peut se produire parfois, d'où le retour arrière sur 2 éléments dans l'exception, on peut améliorer encore cela afin d'exclure les tuples ayant posés problèmes en effectuant une trace des éléments ajoutés pour les exclure avant la sélection au hasard, mais cela en vaut-il le coup, à voir.

    En attendant que quelqu'un d'autre propose mieux, ce qui ne saurait tarder ^^

  7. #7
    Membre Expert

    Homme Profil pro
    Ingénieur calcul scientifique
    Inscrit en
    Mars 2013
    Messages
    1 229
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Alpes Maritimes (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Ingénieur calcul scientifique

    Informations forums :
    Inscription : Mars 2013
    Messages : 1 229
    Par défaut
    Citation Envoyé par lg_53 Voir le message
    Un autre algorithme est également possible puisque l'on sait que chaque nombre entre 20 et 24 doit être présent exactement 2 fois au final. On démarre de la liste :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    x=[[20, 20], [21, 21], [22, 22], [23, 23], [24, 24]]
    puis on choisit deux nombre i1 et i2 entre 0 et 4, et deux nombres j1 et j2 entre 0 et 1.
    (i1,j1) et (i2,j2) nous donne ainsi des positions dans le tableau, que l'on va pouvoir intervertir :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    x[i1][j1],x[i2][j2] = x[i2][j2],x[i1][j1]
    On répète cela un nombre arbitraire de fois (mettons 100 fois). A la fin on vérifie que c'est bien mélangé, c'est à dire qu'on répond bien à tous les critères, du style aucun couple identique. Et si ce n'est pas le cas on recommence les interversions jusqu'à ce que les critères soient ok.

    Au lieu de faire 100 fois, on peut aussi ne pas se fixer de nombre d'itération et tester après chaque itération si le mélange est correct et s'arrêté dès qu'il l'est.
    Et qu'est ce qui ne vous plait pas dans la méthode que je vous ai donné là ? Car avec cet algo pas de problème de cas particulier où il faut revenir en arrière 1 voire 2 fois.
    Regardez


    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    from random import randrange
    from copy import deepcopy
     
    def tirage_valide(liste_de_couple):
        #### Retourne True ou False selon si la liste_de_couple est un tirage valide ou non.
        sort = [ sorted(couple) for couple in liste_de_couple ]
        n=len(liste_de_couple)
        ### Double for imbriqué : plus élégant et générique (ne dépend pas de la longueur de la liste) que :
        ####   if liste1 == liste2 or liste1 == liste3 or liste1 == liste4 or liste1 == liste5 or liste2 == liste3 or liste2 == liste4 or liste2 == liste5 or liste3 == liste4 or liste3 == liste5 or liste4 == liste5:
        for i in range(n):
            ### On teste si chaque élément du couple est bien différent
            if sort[i][0]==sort[i][1] : return False
            ### On teste si le couple n'est pas égal à un autre couple
            for j in range(i+1,n):
                if sort[i]==sort[j] : return False
        return True
     
    def melanger(x):
        y = deepcopy(x) ### Evite de modifier directement le paramètre x passé en entrée de la fonction
        n = len(y)
        while not tirage_valide(y):
            i1,j1 = randrange(0,n), randrange(0,2)
            i2,j2 = randrange(0,n), randrange(0,2)
            ## On interverti les positions (i1,j1) et (i2,j2)
            y[i1][j1],y[i2][j2] = y[i2][j2],y[i1][j1]
        return y
     
    x=[[20, 20], [21, 21], [22, 22], [23, 23], [24, 24]]      
    print(melanger(x))

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

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

    Informations forums :
    Inscription : Novembre 2010
    Messages : 3 041
    Par défaut
    salut,

    j'y vais de ma proposition également :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    import random, itertools
    while True:
       l1 = random.sample(range(20, 25), 5)
       l2 = random.sample(range(20, 25), 5)
       l3 = [{l1[i], l2[i]} for i in range(len(l1))]
       if all([len(i) == 2 for i in l3]):                             # pas de couples avec des valeurs identiques ? ex: (24, 24)
          if len([i for i,j in itertools.groupby(l3)]) == len(l3):    # pas de doublons, même inversés ? ex: {20, 23} == {23, 20}
             break                                                    # alors c'est qu'on a nos listes, on quitte la boucle
    et le résultat pour vérification :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    >>> print(f'l1 = {l1}\nl2 = {l2}\nl3 = {list(zip(l1,l2))}')
    l1 = [23, 20, 22, 24, 21]
    l2 = [20, 22, 21, 23, 24]
    l3 = [(23, 20), (20, 22), (22, 21), (24, 23), (21, 24)]

  9. #9
    Membre averti
    Homme Profil pro
    Technicien maintenance
    Inscrit en
    Août 2015
    Messages
    43
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Eure (Haute Normandie)

    Informations professionnelles :
    Activité : Technicien maintenance
    Secteur : Industrie

    Informations forums :
    Inscription : Août 2015
    Messages : 43
    Par défaut
    Et qu'est ce qui ne vous plait pas dans la méthode que je vous ai donné là ? Car avec cet algo pas de problème de cas particulier où il faut revenir en arrière 1 voire 2 fois.
    Regardez
    lg_53 : Ce n'est pas que ça ne me plait pas ^^, mais j'ai du mal avec :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    y[i1][j1],y[i2][j2] = y[i2][j2],y[i1][j1]
    Il faut que je regarde bien en détail je te remercie.
    je le teste en rentrant ce soir

    salut,

    Buffer_Bob : j'y vais de ma proposition également :
    C'est très court comme code, c'est pas mal je teste au aussi ce soir.

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Liste déroulante avec des conditions de saisie unique
    Par pagesalex dans le forum Macros et VBA Excel
    Réponses: 7
    Dernier message: 31/07/2018, 17h41
  2. Réponses: 45
    Dernier message: 06/03/2007, 16h30
  3. Makefile avec des conditions
    Par meufeu dans le forum Linux
    Réponses: 2
    Dernier message: 04/08/2006, 11h46
  4. Réponses: 1
    Dernier message: 30/06/2006, 16h01
  5. [ASE][T-SQL] Appel d'une sous-proc avec des conditions
    Par metheorn dans le forum Sybase
    Réponses: 1
    Dernier message: 19/05/2006, 18h38

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