给定输入的规则匹配(算法)

时间:2012-01-12 20:39:23

标签: algorithm pattern-matching

假设我有以下类别(带有可能的值):

animal: any, cat, dog
color: any, white, black, gray
gender: any, male, female
[...]

或更一般地......

category: <array of values>

(1)假设我有一组可配置的规则,如:

when animal is any, color is gray, gender is male, call x
when animal is dog, color is gray, gender is male, call y
when animal is any, color is any, gender is any, call z
[...]

(2)和一些输入值。

Q值。是否有算法根据给定的输入解决了找到匹配规则(优先考虑找到最具体的规则)的问题?

例1:

input (animal:dog, color:gray, gender:male)

它会叫“y”

例2:

input (color:gray, gender:female)

它会调用“z”

更合适的方法是根据规则构建搜索树(树的每个级别是一个类别)吗?

像:

- any animal
  - any color
    - any gender => z
  - gray
     - male => x
- dog
  - gray
     - male => y

有更好的方法吗?

谢谢!

5 个答案:

答案 0 :(得分:2)

我会将规则哈希到地图中,然后用相同的哈希查找。

map[hash(animal, color, gender)] = function to call

call map[hash(inputanimal, inputcolor, inputgender)]

这将确保更快地创建规则并解析基于输入调用的正确函数。

如果规则必须完全匹配,或者落入通用any,any,any,那么它只需通过以下方式完成:

if map.contains(hash(inAnimal, inColour, inGender)) 
   x = map[hash(inAnimal, inColour, inGender)]
else
   x = map[hash(any, any, any)]

否则,如果它以输入开头并连续选择每个参数的任何规则,那么你可以这样做。

让哈希函数接受一组值。当您尝试匹配规则时,您从输入开始,然后连续切换到任何一个,直到找到匹配为止。

def key hash(array[])

...

决议程序......

input[] = {inAnimal, inColour, inGender}
function x
for(i = 0 to input.size) {
   if(map.contains(hash(input)) {
      x = map[hash(input)]
      break
   }
   input[i] = any
}
call x

答案 1 :(得分:1)

正确的答案取决于你想要得到的幻想。有像Rete algorithm之类的东西。谷歌“专家系统”。我曾在拥有规则评估系统的大公司工作,但他们不会在内部编写 - 他们会购买商业套餐。

如果您的需求很简单,那么每个级别都是一个类别的搜索树就可以了。如果应用程序只有特定项目和一个通用“任何”项目,这将工作正常。如果存在多种普遍性(“哺乳动物”,“脊椎动物”,“动物”),它就会变得更加强硬。

如果速度是一个问题,但内存使用不是,那么你也可以尝试hashtables-of-hashtables方法。哈希表中的每个条目都是键值对。在顶级哈希表中,键是顶级类别:“dog”,“cat”,“any”。该值是另一个哈希表。在二级哈希表中,键是颜色,值是另一个哈希表。等等。最深的哈希表的值包含函数指针,闭包或编程语言提供的任何动态调用方法。

答案 2 :(得分:1)

我首先给所有变量一个唯一值(数组位置)

  动物:任何= 0; cat = 1; dog = 2
  性别:任何= 0;男= 1;女= 2   颜色:任何= 0;白= 1;黑色= 2;灰色= 3;

然后我会给每个可能的组合赋予一个查找值。

             Animal-|        ANY        |       cat         |       dog         |       
                    ------------------------------------------------------------- 
             Gender-| any | male |female| any | male |female| any | male |female| 
                    ============================================================= 
      Color-any     |  0  |   1  |   2  |  3  |   4  |   5  |  6  |   7  |   8  |
                    ------------------------------------------------------------- 
            white   |  9  |  10  |  11  | 12  |  13  |  14  | 15  |  16  |  17  |
                    ------------------------------------------------------------- 
            black   | 18  |  19  |  20  | 21  |  22  |  23  | 24  |  25  |  26  |   
                    ------------------------------------------------------------- 
            gray    | 27  |  28  |  29  | 30  |  32  |  33  | 34  |  35  |  36  |
                    =============================================================

每个查找值可以通过以下方式计算:

(Animal * number of animals) + Gender + (Color * number of animals * number of sexes)

或在以下情况下:     动物是任何,(0)     颜色是灰色的,(3)     性别是男性,(1)

(Animal * number of animals) + Sex + (Color * number of animals * number of sexes)
(   0   *        3         ) +  1  + (  3   *        3          *        3       )  

(0 * 3) + 1 + (3 * 3 * 3)  
   0    + 1 +      27       = 28 (the lookup value from the grid above)

28表示调用X.

所以在你的程序中:

计算你的价值 将该值与已知案例进行比较

if Value in (1,2,8,13,14,15,21,28)    then X
if value in (3,4,5,23,24,26,34,35,36) then Y
if value in (0,9,12,16,17,22,25)      then Z

显然,这些值实际上可以存储在配置文件中,因此您可以在不重新编译的情况下更改逻辑。

答案 3 :(得分:1)

具有以下修改的决策树将起作用:

  1. 以正常方式创建决策树,使用所有规则将“any”作为边缘
  2. 在递归遍历时,遍历'value'和'any'并跟踪每个解决方案中的任何数字,返回最小的'any'的

    def遍历(values,level,tree,anyCount):     如果树是一片叶子:         return(appr_func,anyCount)

    v1 = None
    if values[level] in tree:
        v1 = traverse(values, level+1, tree[values[level]]], anyCount)
    
    v2 = None
    if 'any' in tree:
        v2 = traverse(values, level+1, tree['any'], anyCount+1)
    
    if v1!=None:
        if v2!=None:
            if v1[1]<v2[1]:
                return v1
            else:
                return v2
        else:
            return v1
    elif v2!=None:
        return v2
    else:
        return None
    

答案 4 :(得分:1)

您几乎可以直接将其转换为scala代码。

惯用法,你会使用动物,猫,狗 - 在scala中使用大写字母,但是为了符合你的例子,我在这里离开了惯例之路:

abstract sealed class animal () {}
 object cat extends animal () {}
 object dog extends animal {}

abstract sealed class color () {}
 object white extends color {}
 object black extends color {}
 object gray  extends color {}

abstract sealed case class gender () {}
 object male   extends gender {}
 object female extends gender {}

def input (a: Option[animal], c: Option[color], g: Option[gender]) = (a, c, g) match {
  case (Some (dog), Some (gray), Some (male)) => println ("y called without freedom")
  case (_,          Some (gray), Some (male)) => println ("x called with animal" + a)
  case (_,          _,           _          ) => println ("z called with anmimal: " + a + "\tcolor: " + c + "\tgender: " + g)
}

input (Some (dog), Some (gray), Some (male))
input (None,       Some (gray), Some (female))

结果:

y called without freedom
x called with animal: None

您必须注意“输入”方法中的排序。具体方法必须在非特定方法之前。

在某些情况下,根据您的描述,您无法做出决定该做什么,但您必须先决定哪个测试首先出现:

(a, c, _)
(_, c, g)
(a, _, g) 

所有人都有1个打开案例。如果没有别的,(a,c,g)可以匹配任何一个,但只匹配第一个。

您必须提供一般情况(_,_,_),但如果没有意义,可能会抛出错误。