View Full Version : [Qualsiasi / Pseudocodice] Numero variabile di condizioni dentro un if
tylerdurden83
09-05-2011, 08:26
Ragazzi, ho un problema concettuale più che legato ad un linguaggio in particolare, per cui mi va bene un esempio in qualsiasi linguaggio o pseudocodice.
Attualmente il mio programma ha un blocchetto di codice del tipo
if (haProprieta(A)== false && haProprieta(B)== false){
...
} else if (haProprieta(A)== false && haProprieta(B)== true){
...
} else if (haProprieta(A)== true && haProprieta(B)== false){
...
} else if (haProprieta(A)== true && haProprieta(B)== true){
...
}
A e B sono due proprietà del mio oggetto.
Ora però mi è stato chiesto di far si che possa avere un numero variabile di proprietà.
Il problema è come fare ad avere un numero parametrico di if then else nel mio software?
Ad esempio, nel caso abbia tre proprietà, dovrei avere:
if (haProprieta(A)== false && haProprieta(B)== false && haProprieta(C)== false){
...
} else if (haProprieta(A)== false && haProprieta(B)== false && haProprieta(C)== true){
...
} else if (haProprieta(A)== false && haProprieta(B)== true && haProprieta(C)== false){
...
} else if (haProprieta(A)== false && haProprieta(B)== true && haProprieta(C)== true){
...
} ...
La struttura dati per contenere le proprietà non è un problema.
La creazione dei vari casi, anche usando una funzione ricorsiva, l'ho risolta, ma non riesco a capire se mi può essere d'aiuto (per capirci, ho capito come generare, nel caso di cui sopra, una matrice del tipo
0,0,0
0,0,1
0,1,0
0,1,1
...
che in effetti modella i vari blocchetti if then else, ma mi serve a qualcosa? E, se si, come usarla?...
Grazie a tutti, come sempre.
TD
dipende molto da che ti serve :)
devi uscire in qualche punto?
se invece devi fare un matching credo che l'unica sia inserire tutte le variabili in una matrice e fare dei case con quella
case matrice
000 then qualcosa
001 then qualcosa
ecc ecc
Dovresti essere un po' più preciso.
Quando parli di oggetto ne parli in chiave object oriented?
Quando parli di proprietà associate ad un oggetto, ne parli alla stessa maniera?
O è molto più astratto?
Quali sono i tuoi oggetti, le proprietà cosa descrivono con esattezza?
Se queste proprietà potessero essere associate a dei flags, potresti pensare di creare una struttura simile ad un array di bit.
Se il tuo problema è aggiungere nuove proprietà a run-time, dovresti fare in modo di caricare queste proprietà dall'esterno (ad esempio da file) e creare una struttura apposita.
Un'idea per evitare di usare IF-ELSE è usare una lista o un array di puntatori a funzioni.
Per cui ad esempio in posizione 0 hai una certa funzione, in posizione 1 un'altra, così facendo, in base ad un certo codice potresti lanciare la funzione corrispondente senza usare IF.
Un'altra soluzione è vedere tutto in chiave object oriented, per cui implementi un'oggetto chiamato PROPRIETA', e un oggetto OBJECT che contiene una lista di queste proprietà.
Ma rimaniamo sempre nel campo delle ipotesi, spiega meglio cosa intendi per proprietà, oggetto e quant'altro...
tylerdurden83
09-05-2011, 14:14
Posto un pezzo del codice originale, poi lo commento un pochino.
while (iter.hasNext()) {
Item item = iter.next();
boolean hasHit =item.hasStat(WoWConstants.Stats.HIT);
boolean hasExpertise =item.hasStat(WoWConstants.Stats.EXPERTISE);
if(hasHit && !hasExpertise){
// the item has only hit and not expertise
if(item.getStat(WoWConstants.Stats.HIT).getAmount()>=leastAmountOfHit && leastAmountOfHit>0){
// if this isnt the first item being tested and ...
...
iter.remove();
continue;
}
// set leastamountofhit. if this is the first item, set it to that item's hit
if(firstItem){
leastAmountOfHit=item.getStat(WoWConstants.Stats.HIT).getAmount();
} else if(leastAmountOfHit==0 || leastAmountOfHit>item.getStat(WoWConstants.Stats.HIT).getAmount()){
// otherwise update it only if this item has less hit, or leastamountofhit is still zero (the first item processed might not verify the hasHit !hasExpertise condition)
leastAmountOfHit=item.getStat(WoWConstants.Stats.HIT).getAmount();
}
} else if(!hasHit && hasExpertise){
// the item has expertise only, not hit
if(item.getStat(WoWConstants.Stats.EXPERTISE).getAmount()>=leastAmountOfExpertise && leastAmountOfExpertise>0){
...
iter.remove();
continue;
}
if(firstItem){
leastAmountOfExpertise=item.getStat(WoWConstants.Stats.EXPERTISE).getAmount();
} else if(leastAmountOfExpertise==0 || leastAmountOfExpertise>item.getStat(WoWConstants.Stats.EXPERTISE).getAmount()){
leastAmountOfExpertise=item.getStat(WoWConstants.Stats.EXPERTISE).getAmount();
}
} else if(hasHit && hasExpertise){
// the item has both expertise and hit
if(item.getStat(WoWConstants.Stats.HIT).getAmount()>=leastAmountOfHitWhenBothPresent
&& item.getStat(WoWConstants.Stats.EXPERTISE).getAmount()>=leastAmountOfExpertiseWhenBothPresent
&& !firstItem){
...
iter.remove();
continue;
}
// the values for items with both must be exclusive to them and updated at once, only if both are higher
if(firstItem){
leastAmountOfHitWhenBothPresent=item.getStat(WoWConstants.Stats.HIT).getAmount();
leastAmountOfExpertiseWhenBothPresent=item.getStat(WoWConstants.Stats.EXPERTISE).getAmount();
} else if((leastAmountOfHitWhenBothPresent>item.getStat(WoWConstants.Stats.HIT).getAmount() && leastAmountOfExpertiseWhenBothPresent>item.getStat(WoWConstants.Stats.EXPERTISE).getAmount())
|| (leastAmountOfHitWhenBothPresent==0 && leastAmountOfExpertiseWhenBothPresent==0) ){
leastAmountOfHitWhenBothPresent=item.getStat(WoWConstants.Stats.HIT).getAmount();
leastAmountOfExpertiseWhenBothPresent=item.getStat(WoWConstants.Stats.EXPERTISE).getAmount();
}
}
...
In pratica, ogni item può avere n WoWConstants.Stats (valori di un'enumeration). Tuttavia, solo due delle n Stats mi interessano per decidere se effettuare delle remove da una lista. A seconda di quale è presente sull'i-esimo item, mi comporto diversamente, aggiorno variabili/contatori differenti, etc.
L'obiettivo è slegarmi dall'avere scolpito nel codice questo comportamento soltanto per quei due valori di WoWConstants.Stats, in modo da avere in input una lista di WoWConstants.Stats (1,2,n valori) al suo posto.
banryu79
09-05-2011, 16:21
Ciao tylerdurden83,
presumo tu non conosca la libreria Guava (http://code.google.com/p/guava-libraries/) di Google.
Facendo riferimento ad essa, ed utilizzando Predicate/Predicates e Function/Functions potresti fattorizzare e rendere modulare quest'aspetto della tua applicazione.
Un Predicate<Item> è un oggetto che rappresenta un predicato su un Item: cioè prende in ingresso un Item, e risponde con true se il predicato è vero per quell'Item.
Una Function<O,I> è un oggetto che rappresenta una funzione: prende in input un I (nel tuo caso un Item) e restituisce in output un O (quello che vuoi).
[in pratica Predicate è un caso speciale di Function: prende in input un tipo parametrico e restituisce un booleano]
Immagina ora di mappare (map) un dato predicato con una funzione.
Immagina di rappresentare questa mappa Predicati-Funzioni come una classe che, dato un Item è capace di scegliere ed eseguire su quell'Item la funzione associata al predicato per cui quell'Item è vero.
Un'istanza di tale classe potrà anche aggiungere-rimuovere dalla mappa associazioni arbitrarie di predicati-funzioni a runtime.
*Edit: trovi Predicate e Function nel package com.google.common.base; qualche tutorial nel web lo trovi facilmente, comunque i javadoc dovrebbero essere sufficienti.
Guava poi ha un sacco di altra roba comodissima, in particolare il package com.google.common.collect è una manna, ma puoi sempre vedertela con calma più avanti.
sottovento
09-05-2011, 16:31
Ragazzi, ho un problema concettuale più che legato ad un linguaggio in particolare, per cui mi va bene un esempio in qualsiasi linguaggio o pseudocodice.
Attualmente il mio programma ha un blocchetto di codice del tipo
if (haProprieta(A)== false && haProprieta(B)== false){
...
} else if (haProprieta(A)== false && haProprieta(B)== true){
...
} else if (haProprieta(A)== true && haProprieta(B)== false){
...
} else if (haProprieta(A)== true && haProprieta(B)== true){
...
}
A e B sono due proprietà del mio oggetto.
Ora però mi è stato chiesto di far si che possa avere un numero variabile di proprietà.
Il problema è come fare ad avere un numero parametrico di if then else nel mio software?
Ad esempio, nel caso abbia tre proprietà, dovrei avere:
if (haProprieta(A)== false && haProprieta(B)== false && haProprieta(C)== false){
...
} else if (haProprieta(A)== false && haProprieta(B)== false && haProprieta(C)== true){
...
} else if (haProprieta(A)== false && haProprieta(B)== true && haProprieta(C)== false){
...
} else if (haProprieta(A)== false && haProprieta(B)== true && haProprieta(C)== true){
...
} ...
La struttura dati per contenere le proprietà non è un problema.
La creazione dei vari casi, anche usando una funzione ricorsiva, l'ho risolta, ma non riesco a capire se mi può essere d'aiuto (per capirci, ho capito come generare, nel caso di cui sopra, una matrice del tipo
che in effetti modella i vari blocchetti if then else, ma mi serve a qualcosa? E, se si, come usarla?...
Grazie a tutti, come sempre.
TD
Direi di si, mi sembra proprio il caso.
Se puoi, la soluzione che hai proposta e' semplice:
int condizione = hasProperty(A) ? 1 : 0;
condizione |= hasProperty(B) ? 2 : 0;
condizione |= hasProperty(C) ? 4 : 0;
hai il numero che puo' corrispondere all'indice di una matrice o al case di uno switch....
tylerdurden83
09-05-2011, 17:25
Grazie a entrambi, domani studio e provo e vi farò sapere!
tylerdurden83
10-05-2011, 11:45
Per quanto riguarda la prima strada, ho costruito una funzione ricorsiva per generare la seguente matrice (ad es nel caso, come sopra, di sole due Stat):
[!HIT, !EXPERTISE]
[!HIT, EXPERTISE]
[ HIT, !EXPERTISE]
[ HIT, EXPERTISE]
Se aggiungo una terza Stat, mi produce correttamente:
[!HIT, !EXPERTISE, !SPIRIT]
[!HIT, !EXPERTISE, SPIRIT]
[!HIT, EXPERTISE, !SPIRIT]
[!HIT, EXPERTISE, SPIRIT]
[ HIT, !EXPERTISE, !SPIRIT]
[ HIT, !EXPERTISE, SPIRIT]
[ HIT, EXPERTISE, !SPIRIT]
[ HIT, EXPERTISE, SPIRIT]
Ora mi manca però il passetto subito dopo, ossia, data ad es la prima riga della matrice di cui sopra, come ottengo l'equivalente di:
if(has(Hit)==false AND has(Expertise)== false AND has(Spirit)==false then ...
else if (has(Hit)==false AND has(Expertise)== false AND has(Spirit)==true then ...
Il problema non è chiaramente rimpiazzare Hit, Expertise e Spirit come input del metodo has(Stat), che potrebbero benissimo essere:
if(has(Matrix(0,0))==false AND has(Matrix(0,1))== false AND has(Matrix(0,2))==false then ...
else if (has(Matrix(1,0))==false AND has(Matrix(1,1))== false AND has(Matrix(1,2))==true then ...
Il problema è come mettere in AND un numero di condizioni variabili (dato che non posso fare simil-sql, dove chiamo append su una stringa che modella ad es una query, prima di eseguirla). L'unico dato che ho è che se la matrice ha 3 colonne, allora dovrò avere 3 condizioni dentro ogni if, e 2^3 blocchetti if. Come faccio con dei cicli parametrici ad ottenere:
if(has(Matrix(0,0))==false AND has(Matrix(0,1))== false AND has(Matrix(0,2))==false then ...
piuttosto che:
if(has(Matrix(0,0))==false AND has(Matrix(0,1))== false then ...
etc?
Per quanto riguarda la soluzione di banryu79... non sono sicuro di riuscire a seguirti, non per quelle classi, la documentazione mi pare buona e tutto, ma proprio da un punto di vista concettuale...
tylerdurden83
13-05-2011, 11:11
uppino :fagiano:
Visto che il thread langue diamogli una scossettina.
Uno dei modi più interessanti per risolvere un problema con un software è barare e spudoratamente.
Anzichè chiederci come si risolve il problema possiamo domandarci: data la soluzione che mi piacerebbe avere, che sarebbe comoda dal punto di vista della scrittura del codice, come ci arriviamo?
Ad esempio, sarebbe comodo, dato un Item, poter avere un elenco di proprietà diviso in due parti, una che esprime le proprietà che devono esserci e una quelle che non devono esserci, e collegarlo ad un certo blocco di codice?
Diremmo, in codice:
pippo = lista magica
pippo -> proprietà vere += A
pippo -> proprietà vere += B
pippo -> proprietà false += C
pippo -> se verificato per (Item) -> azione
Potremmo quindi pensare all'else come una concatenazione di pippi
superpippo = pippo1 else pippo2 else pippo3 else pippo4
superpippo -> se verificato per (item) -> azione
L'azione eseguita da superpippo sarebbe l'azione del pippo verificato per il concreto Item.
Un pippo sarebbe parametrico nelle proprietà e nella verità/falsità delle stesse, nell'item e nell'azione da eseguire nel caso in cui le condizioni si verifichino.
Superpippo sarebbe parametrico in pippo. Risulta che potremmo comporre a piacimento delle sequenze di proprietà/azioni da applicare ad una lista di Item per ottenere l'effetto desiderato.
In Scala scriveremmo:
package test {
/**
* Item di prova
*/
class Item(name: String) {
import collection.mutable.HashMap
private val map = HashMap[String, Any]()
/**
* Initializza questo item con un nome ed un set di proprietà
*/
def this(name: String, properties: (String, Any)*) {
this(name)
map ++= properties
}
/**
* true se questo item ha la proprietà col nome in argomento
*/
def hasStat(statName: String): Boolean = map.contains(statName)
/**
* Restituisce il nome dell'item
*/
override def toString(): String = {
name
}
}
/**
* Elenco di proprietà verificabili per esistenza/inesistenza in un item
*/
class PropVerifier {
import collection.mutable.ListBuffer
private val hasList = ListBuffer[String]()
private val hasNotList = ListBuffer[String]()
private var action: Option[Item => Unit] = None;
/**
* Aggiunge una proprietà che deve esistere nell'item affinchè questo verificatore
* restituisca true
*/
def has(propName: String): this.type = {
hasList.append(propName)
this
}
/**
* Aggiunge una proprietà che non deve esistere nell'item affinchè questo verificatore restituisca true
*/
def hasNot(propName: String): this.type = {
hasNotList.append(propName);
this
}
/**
* Imposta l'azione che il verificatore intraprende nel caso in cui un item abbia tutte le proprietà che
* deve avere e non abbia le proprietà che devono mancare
*/
def then(fun: Item => Unit): this.type = {
action = Some(fun)
this
}
/**
* Controlla che l'item in argomento abbia tutte le proprietà che deve avere e manchi di tutte quelle che
* non deve avere
*/
def check(item: Item): Boolean = {
val hasCheck = !hasList.exists(s => item.hasStat(s) == false)
val hasNotCheck = !hasNotList.exists(s => item.hasStat(s) == true)
return hasCheck && hasNotCheck
}
/**
* Esegue l'azione associata a questo verificatore
*/
def takeAction(item: Item) {
if(action.isDefined) action.get.apply(item)
}
}
/**
* Una serie di verificatori concatenati l'uno all'altro in reciproca esclusione
*/
class PropVerifierChain {
import collection.mutable.ListBuffer
private val verifiers = ListBuffer[PropVerifier]()
/**
* Aggiunge un verificatore alla catena
*/
def chain(v: PropVerifier): this.type = {
verifiers.append(v)
this
}
/**
* Controlla se esiste un verificatore valido per l'item in argomento e lo esegue
*/
protected def check(item: Item) {
val applicableVerifier = verifiers.find(e => e.check(item) == true)
if(applicableVerifier.isDefined) applicableVerifier.get.takeAction(item)
}
/**
* Applica la catena di verificatori ad un insieme di Item
*/
def apply(items: Iterable[Item]) {
items.foreach(e => check(e))
}
}
/**
* Main object
*/
object Test {
/**
* Esegue un test
*/
def main(args: Array[String]) {
/* Item di prova */
val item0 = new Item("pippo", ("exp", 100), ("life", 10))
val item1 = new Item("jhonny", ("exp", 10))
val item2 = new Item("carmelo", ("life", 1))
val item3 = new Item("augusto")
/* Lista di item da passare alla catena di verificatori */
val items = List(item0, item1, item2, item3)
/* Inizializza la catena di verificatori */
val verifier = new PropVerifierChain()
/* Passa se item ha exp ma non life */
.chain(new PropVerifier().has("exp").hasNot("life").then(withExpNotLife))
/* Passa se item ha life ma non exp*/
.chain(new PropVerifier().has("life").hasNot("exp").then(withLifeNotExp))
/* Passa se item non ha life nè exp */
.chain(new PropVerifier().hasNot("exp").hasNot("life").then(withNotExpLife))
/* Passa se item ha exp e life */
.chain(new PropVerifier().has("exp").has("life").then(withExpLife))
/* Applica il verificatore */
verifier.apply(items)
}
def withExpNotLife(item: Item) {
println(item + " has exp but not life")
}
def withLifeNotExp(item: Item) {
println(item + " has life but not exp")
}
def withNotExpLife(item: Item) {
println(item + " has not life and exp")
}
def withExpLife(item: Item) {
println(item + " has life and exp")
}
}
}
Ma lo stesso vale, salvo la sintassi, per qualsiasi linguaggio general purpose.
Nota che si può facilmente generalizzare la questione per supportare qualsiasi tipo di verifica (le condizioni di un if altro non sono che espressioni generiche le quali restituiscono true o false) o per eseguire insiemi di verifiche parzialmente esclusive (if-else-else, if if if else e via combinando).
tylerdurden83
15-05-2011, 20:27
Grazie per il tuo tempo PGI-Bis.
Riguardo il tuo approccio, l'ho letto ma c'è una cosa che non mi è ben chiara.
Ad esempio:
/* Inizializza la catena di verificatori */
val verifier = new PropVerifierChain()
/* Passa se item ha exp ma non life */
.chain(new PropVerifier().has("exp").hasNot("life").then(withExpNotLife))
Sostituire "exp", "life" etc è facile. Però hai scritto ".has(...).hasNot(...)". Hai quindi scolpito nel codice una lunghezza "due", per così dire. Hai ovviamente di conseguenza scolpito 4 casi, hasNot+hasNot, has+hasNot, hasNot+has, has+has.
Quello che servirebbe a me è non avere nulla di tutto ciò scolpito.
Per capirci, se questo non fosse java o c++ etc, ma una procedura sql, potrei avere che per la riga della matrice:
!has(HIT), has(SPIRIT)
faccio un append di:
where HIT = 0 and SPIRIT > 0
se avessi
!has(HIT), has(SPIRIT), !has(STAMINA)
la stessa procedura sql mi appenderebbe
where HIT = 0 and SPIRIT > 0 and stamina = 0
Chiaro, appendere condizioni ad una stringa per poi eseguire lo statement sql in essa contenuto è ben diverso che avere un numero variabile di condizioni dentro un if nel caso di linguaggi compilati tipo java... o non avrei dovuto chiedere aiuto!
Inizio a pensare che la cosa non si possa proprio risolvere...
Per chiarire, l'esempio permette di combinare un numero indefinito di c'è/non c'è, in sequenze arbitrarie.
Fa cioè esattamente la stessa cosa di un "if-then-else" salvo l'essere limitato alla verifica dell'esistenza/inesistenza di una proprietà (piglia come argomenti degli Item e invoca ha/non ha).
Il test è eseguito su un numero prefissato di stringhe ma nulla vieta che le stringhe non siano scritte nel codice ma arrivino da una gui piuttostochè da un qualsiasi altro flusso dati.
Tuttavia questo è evidente il che mi spinge a pensare che il problema sia da qualche altra parte.
Forse vuoi rendere dinamica anche l'espressione condizionale? Cioè non vuoi limitarti a dire "se ha/non ha una proprietà" ma più in generale poter dire "se una qualsiasi espressione applicata ad un Item è vera/falsa"?
Se è così allora la soluzione è in quella "facile generalizzazione" che forse non pare poi così facile ma basta osservare PropChain per vedere che ciò che gli interessa è semplicemente che una generica espressione booleana su un item sia vera o falsa. Che verifichi o no una proprietà è irrilevante.
Oppure il problema è un altro ancora, nel qual caso non ho capito :D.
tylerdurden83
15-05-2011, 22:09
Immagina questo codice:
List<Item> iMieiItem = ....
List<Proprieta> leProprieta = ....
for(Item item : iMieiItem){
if(leProprieta.length==1){
// ho solo due casi
if(item.haProprieta(leProprieta.get(0))){
....
} else {
....
}
} else if(leProprieta.length==2){
// ho 4 casi
if(item.haProprieta(leProprieta.get(0))==false && item.haProprieta(leProprieta.get(1))==false){
....
} else if(item.haProprieta(leProprieta.get(0))==false && item.haProprieta(leProprieta.get(1))==true){
....
} else if(item.haProprieta(leProprieta.get(0))==true && item.haProprieta(leProprieta.get(1))==false){
....
} else if(item.haProprieta(leProprieta.get(0))==true && item.haProprieta(leProprieta.get(1))==true){
....
} else if(leProprieta.length==3){
// ho 8 casi
if(item.haProprieta(leProprieta.get(0))==false && item.haProprieta(leProprieta.get(1))==false && item.haProprieta(leProprieta.get(2))==false){
....
} else if(item.haProprieta(leProprieta.get(0))==false && item.haProprieta(leProprieta.get(1))==false && item.haProprieta(leProprieta.get(2))==true){
....
} else if(leProprieta.length==4){
// ho 16 casi
....
}
Come lo scriveresti parametrico sulla lunghezza di leProprieta.length?
Per analogia, è facile scrivere una procedura sql che appende ad una stringa una condizione in più nella clausola where, passando quindi da
"where "+leProprieta.get(0)+" >0"
a
"where "+leProprieta.get(0)+" >0".concat(" and "+leProprieta.get(1)+" >0")
mentre non è facile passare dinamicamente da
if(item.haProprieta(leProprieta.get(0))==false && item.haProprieta(leProprieta.get(1))==false){
a
if(item.haProprieta(leProprieta.get(0))==false && item.haProprieta(leProprieta.get(1))==false && item.haProprieta(leProprieta.get(2))==false){
java non mi permette certo di scrivere il mio if come una stringa e poi eseguirlo una volta concatenati i vari pezzetti...
Ahhhhh!
E' facile in Java tanto quanto lo è in SQL: per niente. Per niente perchè è un problema di calcolo combinatorio. L'ultima volta che ho dovuto farci i conti è stato nel 1634 quindi è molto probabile che io stia per dirti un certo numero di panzane, occhio.
Anzichè usare il PropVerifier così com'è devi dichiarare due classi di condizioni (qualcosa che applicato ad un Item resitutisce true/false), una per "HaProprietà" e una per "NonHaProprietà".
Al PropVerifier - che poi sarebbe l'If "dinamico" - dai una lista sola di condizioni.
Vale a dire:
trait Condition {
def holds(item: Item): Boolean
}
class HasProperty(s: String) extends Condition {
def holds(item: Item) = item.hasStat(s);
override def toString() = "Ha " + s
}
class HasNotProperty(s: String) extends Condition {
def holds(item: Item) = !item.hasStat(s)
override def toString() = "Non ha " + s
}
class PropVerifier {
import collection.mutable.ListBuffer
private val conditions = ListBuffer[Condition]()
private var action: Option[Item => Unit] = None
def add(c: Condition): this.type = {
conditions.append(c)
this
}
def then(fun: Item => Unit): this.type = {
action = Some(fun)
this
}
def check(item: Item): Boolean = {
val failure = conditions.exists(c => !c.holds(item))
!failure
}
def takeAction(item: Item) {
if(action.isDefined) action.get.apply(item)
}
}
Che succede a 'sto punto. La stessa cosa di prima solo che stavolta operi sulle combinazioni di condizioni Ha/Non ha generate a partire dalla lista di proprietà.
Il caso 1 (bella forza :D)
object Test {
def main(args: Array[String]) {
/* Item di prova */
val item0 = new Item("pippo", ("exp", 100), ("life", 10))
val item1 = new Item("jhonny", ("exp", 10))
val item2 = new Item("carmelo", ("life", 1))
val item3 = new Item("augusto")
val properties = List("exp")
val conditions = scala.collection.mutable.ListBuffer[Condition]()
properties.foreach{ p =>
conditions.append(new HasProperty(p))
conditions.append(new HasNotProperty(p))
}
val verifier = new PropVerifierChain();
for(i <- 0 until properties.size) {
verifier.chain(new PropVerifier().add(conditions(i)).then(item => println(item + " " + conditions(i))))
}
verifier.apply(List(item0, item1, item2, item3))
}
}
}
Uso scala perchè è più sintetico ma è uguale in java, ci vuole solo qualche graffa in più.
Il punto è la parte in grassetto. In quel ciclo generi le combinazioni di condizioni ha/non ha dell'insieme che ottieni partendo dalla lista di proprietà.
Esiste al mille per mille la possibilità di generare in un ciclo molto più complicato le combinazioni possibili per un insieme di N condizioni (non ho capito bene la classe delle combinazioni che ti interessano ma credo che siano solo quelle di N elementi): una volta trovato l'algoritmo hai anche risolto il tuo problema.
Dovresti trovare qualcosa cercando "factoradics" in rete.
tylerdurden83
15-05-2011, 23:51
La generazione delle combinazioni in realtà l'ho risolta con una funzione ricorsiva che, ad es nel caso di 3 proprietà di input, mi crea una matrice di 8 righe per 3 colonne con tutte le combinazioni da testare.
[!HIT, !EXPERTISE, !SPIRIT]
[!HIT, !EXPERTISE, SPIRIT]
[!HIT, EXPERTISE, !SPIRIT]
[!HIT, EXPERTISE, SPIRIT]
[ HIT, !EXPERTISE, !SPIRIT]
[ HIT, !EXPERTISE, SPIRIT]
[ HIT, EXPERTISE, !SPIRIT]
[ HIT, EXPERTISE, SPIRIT]
Ora però come proseguire? Ad esempio, nel caso attuale, non parametrico, limitato a due condizioni, facevo:
....
if(!hasHit && hasExpertise){
// the item has expertise only, not hit
if(item.getStat(EXPERTISE).getAmount()>=leastAmountOfExpertise && leastAmountOfExpertise>0){
...
}
if(leastAmountOfExpertise==0 || leastAmountOfExpertise>item.getStat(EXPERTISE).getAmount()){
leastAmountOfExpertise=item.getStat(EXPERTISE).getAmount();
}
} else if(hasHit && hasExpertise){
// the item has both expertise and hit
if(item.getStat(HIT).getAmount()>=leastAmountOfHitWhenBothPresent
&& item.getStat(EXPERTISE).getAmount()>=leastAmountOfExpertiseWhenBothPresent
&& !firstItem){
...
}
if((leastAmountOfHitWhenBothPresent>item.getStat(HIT).getAmount() && leastAmountOfExpertiseWhenBothPresent>item.getStat(EXPERTISE).getAmount())
|| (leastAmountOfHitWhenBothPresent==0 && leastAmountOfExpertiseWhenBothPresent==0) ){
leastAmountOfHitWhenBothPresent=item.getStat(HIT).getAmount();
leastAmountOfExpertiseWhenBothPresent=item.getStat(EXPERTISE).getAmount();
}
Immagina di sostituire:
if(!hasHit && hasExpertise){
che potrebbe modellare la riga di una matrice tipo quella sopra:
[!HIT, EXPERTISE]
con
if(Matrix(i,j).getStat()==Matrix(i,j).getBoolean() && Matrix(i,j+1).getStat()==Matrix(i,j+1).getBoolean()){
siamo d'accordo che ho parametrizzato l'if originale.
Quest'ultimo aveva scolpito dentro sia i riferimenti a quali stat controllare, sia a cosa eguagliarne il confronto (in pratica !hasHit() aveva scolpito che la stat da controllare era Hit e che la si stava valutando contro false)
Il nuovo if è parametrico sia su quale stat controllare, che se confrontarla con true oppure false.
Quindi, la matrice
[!HIT, !EXPERTISE]
[!HIT, EXPERTISE]
[HIT, EXPERTISE]
[HIT, EXPERTISE]
può essere gestita tutta con quel solo if. Ciò fa si che la matrice
[SPIRIT, EXPERTISE]
[!SPIRIT, EXPERTISE]
[SPIRIT, EXPERTISE]
[!SPIRIT, !EXPERTISE]
che differisce dalla predecente in due cose, ha SPIRIT invece di HIT, e ha un diverso ordinamento (la prima riga era false-false, ora è true-true) delle Stat, sia analizzabile perfettamente sempre da quel solo if postato sopra.
Cosa rimane scolpito anche nel secondo if? Il fatto che sto valutando due condizioni (non 1, non 3, ma precisamente due).
Il problema è se la matrice diventa di 3 colonne, perchè in java non posso fare
String baseQuery = "if(Matrix(i,j).getStat()==Matrix(i,j).getBoolean() && Matrix(i,j+1).getStat()==Matrix(i,j+1).getBoolean()){"
if(la matrice ha 3 colonne){
baseQuery .concat("&& Matrix(i,j+2).getStat()==Matrix(i,j+2).getBoolean()")
}
Ti faccio un esempio con una sintassi java (perchè è più easy che pl-sql) di quello che saprei fare in sql e vorrei fare in java.
List<Item> iMieiItem = ....
List<Proprieta> leMieProprieta = ....
String baseQuery = "select A from B where "
for(Item item : iMieiItem){
for(Proprieta prop : leMieProprieta){
baseQuery = baseQuery.concat(prop.getStat+" ")
if(prop.getBoolean==true){
baseQuery = baseQuery.concat("> ")
} else {
baseQuery = baseQuery.concat("<= ")
}
baseQuery = baseQuery.concat("0")
}
Questo codice mi restituisce correttamente, per input:
[ HIT, !EXPERTISE]
select A from B where HIT > 0 and EXPERTISE <= 0
e per input:
[ HIT, !EXPERTISE, SPIRIT]
select A from B where HIT > 0 and EXPERTISE <= 0 and spirit > 0
E' quindi indipendente da quale stat, da se deve esserci o meno, e da quante voglio controllarne, 1, 2, n è indifferente.
Parliamo ma non ci capiamo :D.
Quello che devi fare è usare la composizione: è la stessa cosa del "concat" solo che anzichè concatenare stringhe concateni invocazioni di metodi di istanze.
Questa è la traduzione in Java della concatenazione di stringhe sql
import java.util.Arrays;
import java.util.List;
public class Main {
public static void main(String[] args) {
List<Item> items = Arrays.asList(new Item(), new Item(), new Item());
List<Property> properties = Arrays.asList(new Property("exp"), new Property("life"));
Query query = new Query();
for (Item item : items) {
for (Property prop : properties) {
if(prop.getBoolean() == true) {
query.gt(prop, 0);
} else {
query.let(prop, 0);
}
}
}
}
}
E questa è la query:
import java.util.LinkedList;
import java.util.List;
public class Query {
private static interface Condition {
boolean eval(Item i);
}
private List<Condition> conditions = new LinkedList<Condition>();
public void gt(final Property prop, final int threshold) {
conditions.add(new Condition() {
public boolean eval(Item item) {
return item.getStat(prop.getStat()) > threshold;
}
});
}
public void let(final Property prop, final int threshold) {
conditions.add(new Condition() {
public boolean eval(Item item) {
return item.getStat(prop.getStat()) <= threshold;
}
});
}
public boolean eval(Item item) {
for (Condition condition : conditions) {
if(!condition.eval(item)) return false;
}
return true;
}
}
Probabilmente non ti serve esattamente in questi termini ma Query combina un insieme di condizioni ed è poi in grado di verificare se quella combinazione sia vera o falsa, a prescindere da quante siano o dalla loro natura.
rеpne scasb
16-05-2011, 11:22
■
Per come l'ho intesa io la parte che gli interessa sono le "s", cioè la determinazione di falsità o verità di un attributo degli item in relazione ad una proprietà. Cioè non è l'IF che gli serve ma l'espressione che ne determinerebbe il risultato.
rеpne scasb
16-05-2011, 11:55
■
tylerdurden83
16-05-2011, 12:14
Il problema è che io non devo avere un solo ritorno booleano a partire da N condizioni in or o and.
In sintesi, non mi interessa avere un modo per dire che FALSE && TRUE = FALSE, oppure che FALSE && FALSE && TRUE = FALSE.
Posto un esempio funzionante da poter lanciare voi stessi:
import java.util.LinkedList;
import java.util.List;
public class ConcatenaIf {
private static class Item {
public int id;
Item(int id){
this.id=id;
}
public boolean hasStat(Stat s){
return true;
}
}
private static class Cella {
public boolean trueOFalse;
public Stat stat;
Cella(boolean trueOFalse, Stat stat){
this.trueOFalse=trueOFalse;
this.stat=stat;
}
}
private enum Stat {HIT, EXPERTISE};
private static List<List<Cella>> matrix = new LinkedList<List<Cella>>();
private static void initMatrix2x2(){
// costruisco la matrice a mano, ma so come farla dinamicamente, quindi questo non è un problema
Cella fHit = new Cella(false, Stat.HIT);
Cella tHit = new Cella(true, Stat.HIT);
Cella fExp = new Cella(false, Stat.EXPERTISE);
Cella tExp = new Cella(true, Stat.EXPERTISE);
List<Cella> riga1 = new LinkedList<Cella>();
riga1.add(fHit);
riga1.add(fExp);
List<Cella> riga2 = new LinkedList<Cella>();
riga2.add(fHit);
riga2.add(tExp);
List<Cella> riga3 = new LinkedList<Cella>();
riga3.add(tHit);
riga3.add(fExp);
List<Cella> riga4 = new LinkedList<Cella>();
riga4.add(tHit);
riga4.add(tExp);
matrix.add(riga1);
matrix.add(riga2);
matrix.add(riga3);
matrix.add(riga4);
}
public static void main(String[] args){
List<Item> oggetti = new LinkedList<Item>();
oggetti.add(new Item(1));
oggetti.add(new Item(2));
oggetti.add(new Item(3));
initMatrix2x2();
for(Item item : oggetti){
for(List<Cella> riga : matrix){
//if(item.hasStat(riga.get(0).stat)==riga.get(0).trueOFalse
// && item.hasStat(riga.get(1).stat)==riga.get(1).trueOFalse){
System.out.println("Con l'if commentato qui sopra sto valutando se l'item "+item.id+" corrente" +
((riga.get(0).trueOFalse) ? " ha " : " non ha ")+
"la Stat " +riga.get(0).stat + " e se"+
((riga.get(1).trueOFalse) ? " ha " : " non ha ")+
"la Stat " +riga.get(1).stat);
//}
}
}
}
}
Output:
Con l'if commentato qui sopra sto valutando se l'item 1 corrente non ha la Stat HIT e se non ha la Stat EXPERTISE
Con l'if commentato qui sopra sto valutando se l'item 1 corrente non ha la Stat HIT e se ha la Stat EXPERTISE
Con l'if commentato qui sopra sto valutando se l'item 1 corrente ha la Stat HIT e se non ha la Stat EXPERTISE
Con l'if commentato qui sopra sto valutando se l'item 1 corrente ha la Stat HIT e se ha la Stat EXPERTISE
Con l'if commentato qui sopra sto valutando se l'item 2 corrente non ha la Stat HIT e se non ha la Stat EXPERTISE
Con l'if commentato qui sopra sto valutando se l'item 2 corrente non ha la Stat HIT e se ha la Stat EXPERTISE
Con l'if commentato qui sopra sto valutando se l'item 2 corrente ha la Stat HIT e se non ha la Stat EXPERTISE
Con l'if commentato qui sopra sto valutando se l'item 2 corrente ha la Stat HIT e se ha la Stat EXPERTISE
Con l'if commentato qui sopra sto valutando se l'item 3 corrente non ha la Stat HIT e se non ha la Stat EXPERTISE
Con l'if commentato qui sopra sto valutando se l'item 3 corrente non ha la Stat HIT e se ha la Stat EXPERTISE
Con l'if commentato qui sopra sto valutando se l'item 3 corrente ha la Stat HIT e se non ha la Stat EXPERTISE
Con l'if commentato qui sopra sto valutando se l'item 3 corrente ha la Stat HIT e se ha la Stat EXPERTISE
Ora, immaginiamo di sostituire nel main la chiamata a initMatrix2x2(); con una a initMatrix8x3(); che genera la matrice 8 righe 3 colonne del caso 3 Stat. Mi sapreste trasformare l'if e la System.out in modo che stampi ad esempio:
Con l'if commentato qui sopra sto valutando se l'item 1 corrente non ha la Stat HIT e se non ha la Stat EXPERTISE e se non ha la Stat SPIRIT
...
ovviamente senza aggiungere dentro l'if
&& item.hasStat(riga.get(2).stat)==riga.get(2).trueOFalse
o dentro la System.out
"la Stat " +riga.get(1).stat + " e se"+
((riga.get(2).trueOFalse) ? " ha " : " non ha ")+
"la Stat " +riga.get(2).stat);
Questo è come il mio cervello vede l'assembly:
BIM BUM,BAM
CIP & ,CIOP
voulez vous une cigarette:
spock STAR,TREK[KIRK,PICARD]
shell ricordati di fare benzina
addavenì ajax,drago pulisan
addavenì bmx,1h al massimo 1h e mezza
ciomp ajax,drago pulisan
yoyo cigarette?
shelll hai fatto benzina?
addavenì ajax,drago pulisan
jmf ajax
avevo anche provato una volta a studiare il mips ma non è propio cosa.
Mi sentirei di scommettere un baffo circa il fatto che la difficoltà non stia nel numero variabile di proprietà.
Questo non toglie che trattare una concatenazione di combinazioni di condizioni booleane come un hashing perfetto non sia di per sè elegantissimo.
Mi sapreste trasformare...
In verde le aggiunte/modifiche.
import java.util.LinkedList;
import java.util.List;
public class ConcatenaIf {
private static class Item {
public int id;
Item(int id){
this.id=id;
}
public boolean hasStat(Stat s){
return true;
}
}
private static class Cella {
public boolean trueOFalse;
public Stat stat;
Cella(boolean trueOFalse, Stat stat){
this.trueOFalse=trueOFalse;
this.stat=stat;
}
}
private enum Stat {HIT, EXPERTISE};
private static List<List<Cella>> matrix = new LinkedList<List<Cella>>();
private static void initMatrix2x2(){
// costruisco la matrice a mano, ma so come farla dinamicamente, quindi questo non è un problema
Cella fHit = new Cella(false, Stat.HIT);
Cella tHit = new Cella(true, Stat.HIT);
Cella fExp = new Cella(false, Stat.EXPERTISE);
Cella tExp = new Cella(true, Stat.EXPERTISE);
List<Cella> riga1 = new LinkedList<Cella>();
riga1.add(fHit);
riga1.add(fExp);
List<Cella> riga2 = new LinkedList<Cella>();
riga2.add(fHit);
riga2.add(tExp);
List<Cella> riga3 = new LinkedList<Cella>();
riga3.add(tHit);
riga3.add(fExp);
List<Cella> riga4 = new LinkedList<Cella>();
riga4.add(tHit);
riga4.add(tExp);
matrix.add(riga1);
matrix.add(riga2);
matrix.add(riga3);
matrix.add(riga4);
}
static class Check {
private final Item item;
private final Cella cella;
private Check(Item item, Cella cella) {
this.item = item;
this.cella = cella;
}
boolean eval() {
return item.hasStat(cella.stat) == cella.trueOFalse;
}
@Override
public String toString() {
return (cella.trueOFalse ? " ha la stat " : " non ha la stat ") + cella.stat;
}
}
static class CheckList extends LinkedList<Check> {
void eval(Item item) {
StringBuilder buffer = new StringBuilder();
for (Check object : this) {
if(buffer.length() == 0) {
buffer.append("Con questo if sto valutando se l'item ").append(item.id).append(" corrente ");
buffer.append(object);
} else {
buffer.append(" e se ").append(object);
}
}
System.out.println(buffer);
}
}
public static void main(String[] args){
List<Item> oggetti = new LinkedList<Item>();
oggetti.add(new Item(1));
oggetti.add(new Item(2));
oggetti.add(new Item(3));
initMatrix2x2();
for(Item item : oggetti){
for(List<Cella> riga : matrix){
CheckList checks = new CheckList();
for (final Cella cella : riga) {
checks.add(new Check(item, cella));
}
checks.eval(item);
}
}
}
}
tylerdurden83
16-05-2011, 14:09
Ok ma la mia print non era l'obiettivo vero e proprio. Ogni print che stampavo era legata all'if commentato subito sopra, che è il vero obiettivo.
E' chiaro che la print parametrica sul numero di Stat non è un problema, basta concatenarle. Ad es, banalmente, il codice di prima diventa:
for(Item item : oggetti){
for(List<Cella> riga : matrix){
String messaggio = "Con l'if commentato qui sopra sto valutando se l'item "+item.id+" corrente";
for(Cella cella : riga){
messaggio = messaggio.concat(((cella.trueOFalse) ? " ha " : " non ha ")+
"la Stat " +cella.stat + " e se");
}
System.out.println(messaggio);
}
}
Così la print è indipendente dal numero di colonne della matrice. Come ottenere un if che modella ognuna di queste print, dato che non posso mica fare String if = "dasdasd".concat("adasda");?
EDIT:
ad esempio, la print
Con l'if commentato qui sopra sto valutando se l'item 1 corrente non ha la Stat HIT e se non ha la Stat EXPERTISE
era un riferimento al fatto che l'if commentato sopra di essa
//if(item.hasStat(riga.get(0).stat)==riga.get(0).trueOFalse
// && item.hasStat(riga.get(1).stat)==riga.get(1).trueOFalse){
in questo round del loop stava correttamente valutando che l'item corrente non ha HIT e non ha EXPERTISE
Quando col tuo codice stampo
Con l'if commentato qui sopra sto valutando se l'item 1 corrente non ha la Stat HIT e se non ha la Stat EXPERTISE e se non ha la Stat SPIRIT
qual'è il check che corrisponde a questa print?
qual'è il check che corrisponde a questa print?
Onde evitare fraintendimenti:
dopo aver generato le espressioni condizionali a te interessa andare ad associare una funzione che sia eseguita se l'espressione è verificata;
questa funzione varia a seconda delle condizioni controllate dall'espressione condizionale.
Vale a dire che, nel codice d'esempio, il check.eval(item) anzichè stampare la stringa deve - ovviamente - fare qualcos'altro (quello che avremmo messo nel corpo dell'if).
Confermi?
banryu79
16-05-2011, 14:37
Vale a dire che, nel codice d'esempio, il check.eval(item) anzichè stampare la stringa deve - ovviamente - fare qualcos'altro (quello che avremmo messo nel corpo dell'if).
Io avevo capito proprio così (http://www.hwupgrade.it/forum/showpost.php?p=35114227&postcount=5)... e avevo proposto come soluzione di associare dei predicati validi a delle funzioni.
Però poi mi sono venuti dei dubbi :D
E' la stessa sensazione che ho io e, per inciso, la libreria di google fa esattamente quello che stiamo cercando di fare qui ma ormai non sono più certo di nulla :D
banryu79
16-05-2011, 14:56
E' la stessa sensazione che ho io e, per inciso, la libreria di google fa esattamente quello che stiamo cercando di fare qui ma ormai non sono più certo di nulla :D
Oh, grazie della conferma, almeno so di non aver preso una cantonata micidiale... mi erano venuti dubbi esistenziali ormai :asd:
Comunque tutta la lettura del topic e delle varie soluzioni è stata interessante.
Fine mio ot :)
tylerdurden83
16-05-2011, 15:12
Ho capito che con esempi e similia non ci schiodiamo, posto direttamente il codice attualmente "bloccato" al caso di 2 Stat, che devo parametrizzare in modo da funzionare anche con 1,3,4... Stat
private void thirdOptimizationOfItemSets(Set<Item> itemSetToOptimize){
int leastAmountOfHit = 0;
int leastAmountOfExpertise = 0;
int leastAmountOfHitWhenBothPresent = 0;
int leastAmountOfExpertiseWhenBothPresent = 0;
boolean firstItem=true;
Iterator<Item> iter = itemSetToOptimize.iterator();
while (iter.hasNext()) {
Item item = iter.next();
boolean hasHit =item.hasStatRating(WoWConstants.Stats.HIT);
boolean hasExpertise =item.hasStatRating(WoWConstants.Stats.EXPERTISE);
if(hasHit && !hasExpertise){
// the item has only hit and not expertise
if(item.getStat(WoWConstants.Stats.HIT).getAmount()>=leastAmountOfHit && leastAmountOfHit>0){
// if this isnt the first item being tested
if(!firstItem){
iter.remove();
continue;
}
}
// set leastamountofhit. if this is the first item, set it to that item's hit
if(firstItem){
leastAmountOfHit=item.getStat(WoWConstants.Stats.HIT).getAmount();
} else if(leastAmountOfHit==0 || leastAmountOfHit>item.getStat(WoWConstants.Stats.HIT).getAmount()){
// otherwise update it only if this item has less hit, or leastamountofhit is still zero (the first item processed might not verify the hasHit !hasExpertise condition)
leastAmountOfHit=item.getStat(WoWConstants.Stats.HIT).getAmount();
}
} else if(!hasHit && hasExpertise){
// the item has expertise only, not hit
if(item.getStat(WoWConstants.Stats.EXPERTISE).getAmount()>=leastAmountOfExpertise && leastAmountOfExpertise>0){
if(!firstItem){
iter.remove();
continue;
}
}
if(firstItem){
leastAmountOfExpertise=item.getStat(WoWConstants.Stats.EXPERTISE).getAmount();
} else if(leastAmountOfExpertise==0 || leastAmountOfExpertise>item.getStat(WoWConstants.Stats.EXPERTISE).getAmount()){
leastAmountOfExpertise=item.getStat(WoWConstants.Stats.EXPERTISE).getAmount();
}
} else if(hasHit && hasExpertise){
// the item has both expertise and hit
if(item.getStat(WoWConstants.Stats.HIT).getAmount()>=leastAmountOfHitWhenBothPresent
&& item.getStat(WoWConstants.Stats.EXPERTISE).getAmount()>=leastAmountOfExpertiseWhenBothPresent
&& !firstItem){
iter.remove();
continue;
}
// the values for items with both must be exclusive to them and updated at once, only if both are higher
if(firstItem){
leastAmountOfHitWhenBothPresent=item.getStat(WoWConstants.Stats.HIT).getAmount();
leastAmountOfExpertiseWhenBothPresent=item.getStat(WoWConstants.Stats.EXPERTISE).getAmount();
} else if((leastAmountOfHitWhenBothPresent>item.getStat(WoWConstants.Stats.HIT).getAmount() && leastAmountOfExpertiseWhenBothPresent>item.getStat(WoWConstants.Stats.EXPERTISE).getAmount())
|| (leastAmountOfHitWhenBothPresent==0 && leastAmountOfExpertiseWhenBothPresent==0) ){
leastAmountOfHitWhenBothPresent=item.getStat(WoWConstants.Stats.HIT).getAmount();
leastAmountOfExpertiseWhenBothPresent=item.getStat(WoWConstants.Stats.EXPERTISE).getAmount();
}
}
if(firstItem){
firstItem=false;
}
}
}
Ok, quindi devi associare delle funzioni agli ipotetici CheckList.
Puoi farlo dinamicamente se sei in grado di determinare la funzione da applicare in astratto cioè se puoi dire:
date N proprietà l'if che riguarda le proprietà p0,p1...pn delle quali p0 sia vera/falsa, p1 sia vera/falsa... pn sia vera/falsa, poste le ulteriori condizioni a,b,c capita questo questo e quest'altro.
Se invece non puoi stabilire a priori la struttura della funzione da eseguire allora devi prenderla da qualche altra parte, magari insieme all'input della lista di proprietà da verificare.
Kralizek
16-05-2011, 16:06
letto nulla... uno specification pattern aiuterebbe? :P
Ragazzi, ho un problema concettuale più che legato ad un linguaggio in particolare, per cui mi va bene un esempio in qualsiasi linguaggio o pseudocodice.
Attualmente il mio programma ha un blocchetto di codice del tipo
if (haProprieta(A)== false && haProprieta(B)== false){
...
} else if (haProprieta(A)== false && haProprieta(B)== true){
...
} else if (haProprieta(A)== true && haProprieta(B)== false){
...
} else if (haProprieta(A)== true && haProprieta(B)== true){
...
}
A e B sono due proprietà del mio oggetto.
Ora però mi è stato chiesto di far si che possa avere un numero variabile di proprietà.
Il problema è come fare ad avere un numero parametrico di if then else nel mio software?
Ad esempio, nel caso abbia tre proprietà, dovrei avere:
if (haProprieta(A)== false && haProprieta(B)== false && haProprieta(C)== false){
...
} else if (haProprieta(A)== false && haProprieta(B)== false && haProprieta(C)== true){
...
} else if (haProprieta(A)== false && haProprieta(B)== true && haProprieta(C)== false){
...
} else if (haProprieta(A)== false && haProprieta(B)== true && haProprieta(C)== true){
...
} ...
...
Ciao
dopo aver letto piu' di una volta queste due pagine, ho ancora un bel dubbio: anche supposto che tu riesca a rendere "dinamici" gli if (con delle liste di proprieta' da verificare ad esempio), in che modo tu gestisci il caso generico ? In altre parole, per aggiungere il caso con 4 proprieta' (ad esempio) tu devi comunque aggiungere tutti i casi relativi no ?
A questo punto non so cosa ti porti di vantaggioso il generalizzare, semmai hai bisogno di un modo per scrivere in modo piu' limpido l'elenco di tutti i casi.
In python farei qualcosa del tipo
def has(stat):
return lambda item : item.hasStatRating(stat)
def hasNot(stat)
return lambda item : not item.hasStatRating(stat)
def hasAtLeast(stat,value)
return lambda item : item.hasStatRating(stat) >= value
...
rules = [
([has(HIT),hasNot(EXPERTISE),hasAtLeast(FORCE,10)], doSomething ),
([hasNot(HIT)], doSomethingElse )
]
def applyRules(item):
for rule, action in rules:
ruleApplies = all( prop(item) for prop in rule )
if ruleApplies:
action(item)
return # Apply only the first rule
Come vedi puoi anche specificare delle regole un po' piu' elaborate di un solo c'e'/non c'e', e mi sembra abbastanza pulito.
tieni presente che un approccio simile scorre linearmente la lista per cui se le performance sono un problema si puo' cambiare un po' l'approccio (lasciando sostanzialmente invariata la "presentazione")
Altra cosa che non mi e' chiara: devi gestire TUTTI i casi ?
tylerdurden83
17-05-2011, 14:11
...
Altra cosa che non mi e' chiara: devi gestire TUTTI i casi ?
Guarda questo post (http://www.hwupgrade.it/forum/showpost.php?p=35164649&postcount=28).
A questo punto la cosa migliore è partire dal codice vero e proprio perchè ho capito che con esempi / similitudini vi porto solo fuori strada.
Si nota un pattern per quanto riguarda il cosa fare una volta entrato in uno o l'altro if. Nei casi in cui c'è HIT oppure EXPERTISE, quindi 1 Stat, c'è un intero che viene usato come contatore corrente per decidere se segare o meno l'item corrente. Nel caso in cui ci siano entrambe, ci sono due interi, che vanno valutati/modificati all'unisono. Quindi, riuscendo a concatenare condizioni in IF, sia tipo
hasStat(a) && !hasStat(b) etc
che tipo
listaNumeri[0] > ... && listaNumeri[1] > ....
dovrei aver risolto anche il problema di cosa eseguire.
vBulletin® v3.6.4, Copyright ©2000-2025, Jelsoft Enterprises Ltd.