[Résolu][Python] Combinaison pour trouver une valeur cible

Discussions et questions sur tout ce qui concerne la programmation tous langages et tous modules confondus.

Modérateur : Vilains modOOs

Règles du forum
:alerte: Balisage obligatoire dans cette section !
Aidez-nous à vous aider au mieux en balisant correctement votre question : reportez-vous sur les règles de cette section avant de poster !
Rementis
Fraîchement OOthentifié
Messages : 9
Inscription : 12 juil. 2018 10:11

[Résolu][Python] Combinaison pour trouver une valeur cible

Message par Rementis »

Bien le bonjour, suite à mon premier message ici même, je viens ici pour avoir droit à vos lumières, moi, simple utilisateur d'Openoffice et n'ayant aucune connaissance en codage calc/excel.

Si vous souhaitez évité de lire le premier sujet, je vais résumé ici, avec le passage correspondants :

"Je participe à un concours sur un jeu ou je dois former une équipe de 6 éléments. Chaque élément possède un nombre différent. Et avec ses 6 éléments je dois me rapprocher le plus proche possible d'une valeur donné en les additionnant seulement. Le truc c'est que j'ai un bon nombre d'éléments à tester pour trouver une combinaison. J'aimerai donc une fonction permettant de calculer, trouver, et proposer une liste de combinaison possible."

Je reprends l'image de @Jurassic Pork qui a posté un exemple de tableur qui je pense corresponds totalement à ce que je recherche :

Image

Liste des nombres : Les différentes nombres à ma disposition
Cible : La valeur cible à trouver
nb éléments : le nombre d'éléments à additionner pour trouver la valeur cible
Résultats : Liste des combinaisons possibles, avec les valeurs affichés.
Dernière modification par micmac le 17 juil. 2018 16:43, modifié 2 fois.
Raison : Ajout de [Résolu] et adaptation de la longueur du titre
OpenOffice Apache 4.1.5
Windows 7
Avatar de l’utilisateur
Jurassic Pork
PassiOOnné
PassiOOnné
Messages : 629
Inscription : 09 août 2017 22:15

Re: [Python] Calcul de combinaison pour trouver une valeur c

Message par Jurassic Pork »

hello,
voici ce que je te propose (en pièce jointe) :
CalcCombSomme.png
On utilise des plages nommées pour repérer les différents éléments.
Si il n'y pas de résultat cela s'affiche en C2.
Si il faut chercher le résultat le plus approchant de la cible cela se complique :
Il faut trouver un autre algorithme qui sera plus compliqué.
La macro est contenue dans le fichier.
Pour pouvoir l'éditer facilement il faut utiliser l'extension APSO et définir dans les options de cette extension, l'éditeur que l'on veut utiliser (ex: Geany ou notepad++)
voici le code du module python du fichier :

Code : Tout sélectionner

# -*- coding: utf-8 -*-
from __future__ import unicode_literals
import uno

def subset_sum(numbers, target,nbelem,resultat, partial=[]):
	s = sum(partial)
	# check if the partial sum is equals to target
	if s == target:
		if len(partial) == nbelem:
			resultat.append((str(partial),))
		#print ("sum(%s)=%s" % (partial, target))
	if s >= target:
		return  # if we reach the number why bother to continue
	for i in range(len(numbers)):
		n = numbers[i]
		remaining = numbers[i+1:]
		subset_sum(remaining, target,nbelem,resultat, partial + [n]) 

def calcCombinSum(*args):
	doc = XSCRIPTCONTEXT.getDocument()
	feuille = doc.CurrentController.getActiveSheet()
	#On efface les résultats précédents
	doc.NamedRanges.getByName("ListeResultats").getReferredCells().clearContents(31)
	plage = doc.NamedRanges.getByName("ListeNombres").getReferredCells()
	# on récupere la liste des nombres en une seule fois
	valeurs = plage.getDataArray()
	#print(valeurs)
	# on crée une liste à une dimension à partir de la plage
	listeNombres = [item for sublist in valeurs for item in sublist]
	cible = doc.NamedRanges.getByName("ValeurCible").getReferredCells().getValue()
	nbelems = doc.NamedRanges.getByName("NbElems").getReferredCells().getValue()
	resultat = []
	subset_sum(listeNombres,cible,nbelems,resultat)
	#print(resultat)
	if len(resultat) >0:
		dest = feuille.getCellRangeByPosition(2,1,2,len(resultat))
		dest.setDataArray(tuple(tuple(resultat)))
	else:
		feuille.getCellRangeByName("C2").String = "Pas de résultat"

g_exportedScripts = calcCombinSum,
Ami calmant, J.P
Vous ne pouvez pas consulter les pièces jointes insérées à ce message.
LibreOffice 7.6.2.1 et OpenOffice 4.1.15 sous windows 11
LibreOffice 24.2.0 et OpenOffice 4.1.15 sous Ubuntu 20.04
Rementis
Fraîchement OOthentifié
Messages : 9
Inscription : 12 juil. 2018 10:11

Re: [Python] Calcul de combinaison pour trouver une valeur c

Message par Rementis »

Merci énormément J.P !

J'ai donc installé l'extension APSO comme tu me l'a conseillé, néanmoins étant vraiment un novice absolu, je ne comprends pas ou je dois copier/coller le code du module que tu m'a fourni. Si tu peux m'aider je t'en remercie beaucoup ! :D
OpenOffice Apache 4.1.5
Windows 7
Avatar de l’utilisateur
Jurassic Pork
PassiOOnné
PassiOOnné
Messages : 629
Inscription : 09 août 2017 22:15

Re: [Python] Calcul de combinaison pour trouver une valeur c

Message par Jurassic Pork »

Le code est déjà dans le fichier :mrgreen:
LibreOffice 7.6.2.1 et OpenOffice 4.1.15 sous windows 11
LibreOffice 24.2.0 et OpenOffice 4.1.15 sous Ubuntu 20.04
Avatar de l’utilisateur
Hubert Lambert
SuppOOrter
SuppOOrter
Messages : 1214
Inscription : 06 avr. 2016 07:26

Re: [Python] Calcul de combinaison pour trouver une valeur c

Message par Hubert Lambert »

Bonjour à vous deux,

Juste pour information : python possède une très puissante bibliothèque "itertools" dédiée à ce genre d'exercice, qui permet à la fois de simplifier le code et de l'accélérer :

Code : Tout sélectionner

from itertools import combinations

def calcCombinSum(*args):
    [...]
    valeurs = list(zip(*plage.getDataArray()))[0]
    combinaisons = combinations(valeurs, int(nbelems))
    resultat = tuple((str(x),) for x in combinaisons if sum(x)==cible)
    if resultat:
        dest = feuille.getCellRangeByPosition(2,1,2,len(resultat))
        dest.setDataArray(resultat)
Cordialement :wink: .
Vous ne pouvez pas consulter les pièces jointes insérées à ce message.
AOOo 4.1.7 sur Win10
AOOo 4.1.x sur Linux Mint
LibreOffice 5.x/6.x sur Linux Mint
--
| « Nos défauts devraient nous donner une qualité : l'indulgence pour les défauts des autres » (Rivarol)
Rementis
Fraîchement OOthentifié
Messages : 9
Inscription : 12 juil. 2018 10:11

Re: [Résolu][Python] Combinaison pour trouver une valeur cib

Message par Rementis »

Merci a vous, en revanche quand je clique sur "calcul" pour effecter la recherche, j'ai un message d'erreur qui s'affiche, et comme je suis un novice, je n'ai aucune idée de ce que cela signifie. Le voici :

Code : Tout sélectionner

Erreur de OpenOffice

com.sun.star.uno.RuntimeException (Error during invoking function calcCombinSum in module vnd.sun.star.tdoc:/1/Scripts/python/ModulePython.py (<class 'uno.com.sun.star.uno.RuntimeException'>:
vnd.sun.star.tdoc:/1/Scripts/python/ModulePython.py:22 in function calcCombinSum() [None]
 C:\Program Files (x86)\OpenOffice 4\program\pythonscript.py:866 in function invoke() [ret = self.func( *arg)]
))
Pouvez vous m'éclaircir ?
OpenOffice Apache 4.1.5
Windows 7
Avatar de l’utilisateur
Hubert Lambert
SuppOOrter
SuppOOrter
Messages : 1214
Inscription : 06 avr. 2016 07:26

Re: [Résolu][Python] Combinaison pour trouver une valeur cib

Message par Hubert Lambert »

Ton document n'est pas en mode édition.
Enregistre-le sur ton disque dur avant d'exécuter la macro.
AOOo 4.1.7 sur Win10
AOOo 4.1.x sur Linux Mint
LibreOffice 5.x/6.x sur Linux Mint
--
| « Nos défauts devraient nous donner une qualité : l'indulgence pour les défauts des autres » (Rivarol)
Avatar de l’utilisateur
Jean-Louis Cadeillan
GourOOu
GourOOu
Messages : 5753
Inscription : 02 janv. 2009 23:56

Re: [Résolu][Python] Combinaison pour trouver une valeur cib

Message par Jean-Louis Cadeillan »

Bonsoir,
Selon ta capture d'écran de départ
Rementis_20180712_ini01.png
et l'exemple que tu donnes, il semble que tu recherches des solutions qui n'ont pas forcément toutes le même nombre d'éléments, en d'autres termes que tu cherches toutes les combinaisons de p éléments qui répondent à la fois aux critères suivants :
  • • p éléments différents entre eux
    • p parmi n éléments imposés
    • avec p =1 ou 2 ou 3... ou n éléments
    • somme(p éléments) = nombre imposé
Ce qui suppose de relancer la macro, dans l'exemple 6 fois avec Nb éléments =1, puis 2... puis 6.
À moins de faire une boucle supplémentaire dans le code sur ce Nb d'éléments...
Cordialement,
Jean-Louis
Vous ne pouvez pas consulter les pièces jointes insérées à ce message.
LibO 7.6.6.3 (x64 avec Java 1.8.0_411) et AOO 4.1.15 (avec Java x32 1.8.0_381), Windows 7 Édition Intégrale 64 SP1
Avatar de l’utilisateur
Jurassic Pork
PassiOOnné
PassiOOnné
Messages : 629
Inscription : 09 août 2017 22:15

Re: [Résolu][Python] Combinaison pour trouver une valeur cib

Message par Jurassic Pork »

hello,
Rementis a écrit :Merci a vous, en revanche quand je clique sur "calcul" pour effecter la recherche, j'ai un message d'erreur qui s'affiche, et comme je suis un novice, je n'ai aucune idée de ce que cela signifie. Le voici :

Code : Tout sélectionner

Erreur de OpenOffice
com.sun.star.uno.RuntimeException (Error during invoking function calcCombinSum in module vnd.sun.star.tdoc:/1/Scripts/python/ModulePython.py (<class 'uno.com.sun.star.uno.RuntimeException'>:
vnd.sun.star.tdoc:/1/Scripts/python/ModulePython.py:22 in function calcCombinSum() [None]
 C:\Program Files (x86)\OpenOffice 4\program\pythonscript.py:866 in function invoke() [ret = self.func( *arg)]
))
Pouvez vous m'éclaircir ?
Peut être un souci de version python : Il est vrai que je suis en LibreOffice qui utilise du python 3.5.4. Qu'en est-il de OpenOffice 4.1.5 ?
ou alors un pb d'interface (différence entre LibreOffice et OpenOffice).
Ami calmant, J.P
LibreOffice 7.6.2.1 et OpenOffice 4.1.15 sous windows 11
LibreOffice 24.2.0 et OpenOffice 4.1.15 sous Ubuntu 20.04
Avatar de l’utilisateur
Jurassic Pork
PassiOOnné
PassiOOnné
Messages : 629
Inscription : 09 août 2017 22:15

Re:[Python] Combinaison pour trouver une valeur cible

Message par Jurassic Pork »

hello,
Jean-Louis Cadeillan a écrit :il semble que tu recherches des solutions qui n'ont pas forcément toutes le même nombre d'éléments, en d'autres termes que tu cherches toutes les combinaisons de p éléments qui répondent à la fois aux critères suivants :
  • • p éléments différents entre eux
    • p parmi n éléments imposés
    • avec p =1 ou 2 ou 3... ou n éléments
    • somme(p éléments) = nombre imposé
Ce qui suppose de relancer la macro, dans l'exemple 6 fois avec Nb éléments =1, puis 2... puis 6.
À moins de faire une boucle supplémentaire dans le code sur ce Nb d'éléments...
j'ai fait une modification dans mon code pour que si le nombre d'éléments demandé est inférieur à 1 (ex: 0 ou -1)
on affiche toutes les combinaisons possibles. Le temps de calcul en microsecondes est également affiché en E1 :
CalcSolver.png
Cela se traduit dans le code par cette modification dans subset_sum

Code : Tout sélectionner

def subset_sum(numbers, target,nbelem,resultat, partial=[]):
    s = sum(partial)
    # check if the partial sum is equals to target
    if s == target:
        if nbelem < 1:
            resultat.append((str(partial),))
        else:
            if len(partial) == nbelem:
                resultat.append((str(partial),))

Tant qu'à faire des calculs, j'en ai profité pour rajouter dans mon classeur en feuille 2 un solveur de Compte est bon (le jeu télévisé).
Il y a un bouton qui permet de faire le tirage (6 plaques + compte à trouver).
et un bouton qui permet d'afficher une solution. Si il n'y a pas de solution, est affiché le calcul le plus approchant.
Voici ce que cela donne (cliquer sur l'image pour voir l'animation) :
CompteEstBon.gif
ce qui est louche c'est cette solution (((75/25)-((6-50)*10))-7)=436 -> En fait c'est la même chose que (50-6)*10 - 7 + 75/25 on retrouve 436.

Le code est en python et l'algorithme de calcul de solution arithm_expr_target est tiré de l'excellente bibliothèque python tryalgo (de licence MIT).
Pour ce qui veulent comprendre comment marche l'algorithme à mon avis cela ne va pas être de la tarte ( complexity : huge ! ) et il tient en moins de 50 lignes. Il faut être grand gourou (pas Skippy) du python pour y comprendre quelque chose.

Le classeur calc contenant la modification de mon code précédent et le compte est bon est en pièce jointe.
J'ai testé ce classeur avec OpenOffice 4.1.5 (pour le problème à Rementis) et LibreOffice 5.4.4.2 sous windows 10. Je n'ai pas de problème pour exécuter les macros. A noter qu' avec OpenOffice 4.1.5 c'est du python 2 qui est utilisé ( la version 2.7.6 ).
Ami calmant, J.P
Vous ne pouvez pas consulter les pièces jointes insérées à ce message.
LibreOffice 7.6.2.1 et OpenOffice 4.1.15 sous windows 11
LibreOffice 24.2.0 et OpenOffice 4.1.15 sous Ubuntu 20.04
Rementis
Fraîchement OOthentifié
Messages : 9
Inscription : 12 juil. 2018 10:11

Re: [Résolu][Python] Combinaison pour trouver une valeur cib

Message par Rementis »

Re-Bonjour à nouveau.

Alors, j'ai essayer d'enregistrer le document seulement une fois en mode édition, je ne peux plus cliquer sur "calcul" cela me propose seulement d'agrandir la taille de la cellule.

Mon dernier espoir, je vais essayer de télécharger Libreoffice et voir si cette fois cela focntionne, je vous tiens au courant ^^
OpenOffice Apache 4.1.5
Windows 7
Rementis
Fraîchement OOthentifié
Messages : 9
Inscription : 12 juil. 2018 10:11

Re: [Résolu][Python] Combinaison pour trouver une valeur cib

Message par Rementis »

Petit double poste (désolé) plutôt qu'édit.

Tout ça pour vous dire que cela a fonctionné avec LibreOffice ! Merci à vous tous qui m'avait aidé ! Vous êtes des pros :D
OpenOffice Apache 4.1.5
Windows 7