2011-12-03 92 views
7

Estoy buscando una mejor manera de implementar un árbol de decisión en JavaScript. Siendo muy nuevo en programación, tengo una cantidad muy limitada de herramientas en mi caja de herramientas. Las únicas formas que conozco para hacer esto son: .con una gran fea difícil de mantener y síguelo si la declaración . Yo podría usar una instrucción de interruptor/caja y hacer una cosa de tipo de máquina de estado.Cómo implementar un árbol de decisión en JavaScript. Buscando una mejor solución que mis feos

Sugerencias y teorías son apreciadas. Además, pequeños ejemplos de código serían muy útiles. Gracias por echar un vistazo.

Dale

+0

es un árbol de decisión que se acaba un diagrama de flujo específicamente estructurado? – Dale

Respuesta

10

Si es un árbol muy grande, y especialmente si se genera a partir de datos, podría tratar las funciones de decisión como datos, utilizando un enfoque funcional. Por ejemplo:

var decisionTree = 
    new Case(true, Array(
        new Case (function(n){ return n < 0; }, Math.sin), 
        new Case (function(n){ return n < 2; }, "0<= n < 2"), 
        new Case (true, "Greater than two "))); 

decisionTree.evaluate(1); // evaluates to string "0<= n < 2" 
decisionTree.evaluate(-Math.PI/2); // evaluates to -1 
decisionTree.evaluate(5); // evaluates to string "Greater than two" 

Utilizando esta aplicación, se puede arbitrariamente nido de su árbol:

// Represents a predicate and corresponding action to take if predicate is a 
// match. 
// 
// predicate : true or Function(object) returning a boolean. 
// 
// action : One of Function, Case, Array of Cases or other value (see 
//   Case.evaluate as to how each is applied) 
// 
// 
Case = function (predicate, action) { 
    this.predicate = predicate; 
    this.action = action; 
}; 


Case.prototype = { 
    nomatch : { match : false }, 
    match : function (v) { return { match : true, result :v }; }, 


    // Recursively test Cases and applies corresponding action on 
    // `object`. 
    // 
    // The action applied depends on the datatype of `action`: 
    // 
    // - Function : evaluates to `action(object)` 
    // 
    // - Case : A subsequent test is performed. Evaluates to whatever 
    //   the Cases action evaluates to. 
    //   
    // - Array of Cases : Subsequent tests are performed. Evaluates to whatever 
    //   the action of the first matching Case evaluates to. 
    // 
    // - Any other Value : Evaluates to itself 
    // 
    // returns object containing fields: 
    // 
    //  match: boolean, indicates if Case was a match 
    // 
    //  result: result of action applied 
    // 
    evaluate : function(object) { 
     var match = this.predicate; 

     if (match instanceof Function) 
      match = match(object); 

     if (match) { 

      if (this.action instanceof Function) 
       return this.match(this.action(object)); 

      if (this.action instanceof Case) 
       return this.action.evaluate(object); 

      if (this.action instanceof Array) { 
       var decision; 
       var result; 
       for (var c = 0; c < this.action.length; c++) { 
        decision = this.action[c]; 
        if (decision instanceof Case) { 
         result = decision.evaluate(object); 
         if (result.match) 
          return result; 
        } else throw("Array of Case expected"); 
       } 

       return this.nomatch; 
      } 

      return this.match(this.action); 
     } 
     return this.nomatch; 
    } 
}; 
+0

¡Esto es asombroso! Gracias. ¿Tiene algún comentario sobre esto desde el punto de vista del rendimiento? – Dale

+0

Increíble :) También me llama la atención cómo y hasta qué punto el intérprete lo optimizaría. – Andrei

0

La mejor práctica para este tipo de cosas es para anidar si-entonces declaraciones de una manera significativa, y luego ponerlos en sus propios cuerpos de las funciones. Una función nunca debe tener más de 2 if anidados; después de eso, es aceptable poner más if anidados en funciones que se nombran e implementan bien, abstrayendo así la complejidad del programa y conservando su significado para el programador que leerá su código una vez que se haya ido. :)

+0

Me gusta esa respuesta. Mi problema no está anidado declaraciones if-then. No tengo ningún if anidado. Tengo una declaración if (else if) para cada hoja del árbol que hace algo. Así que he puesto toda mi complejidad en el cálculo del condicional. ¿Es más conveniente anidarlos y abstraer las funciones dentro de la anidación como sugirió? Gracias. – Dale

+1

Lo más frecuente es desear abstraer las cadenas de anidación o largas si entonces no está claro qué hace o si es difícil de leer. Esto le da mucha más legibilidad a su programa (en cualquier idioma) cuando se utilizan pequeñas funciones para abstraer cosas difíciles de entender, como cadenas largas si-entonces. Como regla general, si tiene que escribir un comentario sobre lo que hace una declaración if-then particular o por qué está allí, es mejor ponerla en su propia función bien nombrada en lugar de comentarla. Sus compañeros de trabajo se lo agradecerán. – djhaskin987

Cuestiones relacionadas