2012-07-10 1 views
7

数字の特定のパターンを識別するプログラムを作成したいと考えています。私はこれがアルゴリズムを必要としているのか、ちょうど慎重にプログラミングを考えているのか分かりません。私はソースコードを提供する人を探しているわけではなく、ちょうど正しい方向に私を始める考えを呼び起こすいくつかの考え方があります。数字のパターンを識別するJavaプログラム

数字は000000から999999までの6桁の固定長です。各数字は配列の一部として保存されると思います。私はそのパターンに対して数字をテストしたいと思っています。例えば

は私が使用してい3つのパターン

A A A A A A - would match such examples as 111111 , 222222, 333333 etc where 
A B A B A B - would match such examples as 121212 , 454545, 919191 etc 
A (A+1) (A+2) B (B+1) (B+2) - would match such examples as 123345, 789123, 456234 

あると言うことができ、私が上に貼り付けられてい部分は、A又はB

などの値の整数のアレイの各部分を割り当てる方法だと思い

私の最初の考えは、個々の文字として各部分を割り当てることだけです。だから、配列が、私はいくつかの方法(AAAAAAかのようなもので

AAAAAA 

とテスト、第一のパターンを取るその後

A=1 
B=3 
C=5 
D=4 
E=6 
F=8 

のようなマップを作成し、1 3 5 4 6 8から構成されている場合= ABCDEF)、値がCカントに割り当てられない理由はありません。このシナリオでは

すべての私のパターンを通過など(ABABAB = ABCDEF)をしようとしないならば、我々はAAAAAAA

と一致しました これが誰にも意味をなさすかどうかわかりませんが、私はフィードバックに基づいて私の質問を洗練することができますね。

要約すると、プログラムに6桁の数字を受け入れ、それがどのパターンに一致したかを返す方法に関するアイデアを探しています。

SOLUTION

与えられたコメントは以下の良いトラックに私を入れた後、私は最終的な解決策として作成されたものです。

package com.doyleisgod.number.pattern.finder; 

import java.io.File; 
import java.util.ArrayList; 
import java.util.HashMap; 
import java.util.Iterator; 
import java.util.Map; 
import javax.xml.parsers.DocumentBuilder; 
import javax.xml.parsers.DocumentBuilderFactory; 
import org.w3c.dom.Document; 
import org.w3c.dom.Element; 
import org.w3c.dom.Node; 
import org.w3c.dom.NodeList; 


public class FindPattern { 
private final int[] numberArray; //Array that we will match patterns against. 
private final Document patternTree = buildPatternTree(); //patternTree containing all the patterns 
private final Map<String, Integer> patternisedNumberMap; //Map used to allocate ints in the array to a letter for pattern analysis 
private int depth = 0; //current depth of the pattern tree 

// take the int array passed to the constructor and store it in out numberArray variable then build the patternised map 
public FindPattern (int[] numberArray){ 
    this.numberArray = numberArray; 
    this.patternisedNumberMap = createPatternisedNumberMap(); 
} 

//builds a map allocating numbers to letters. map is built from left to right of array and only if the number does not exist in the map does it get added 
//with the next available letter. This enforces that the number assigned to A can never be the same as the number assigned to B etc 
private Map<String, Integer> createPatternisedNumberMap() { 
    Map<String, Integer> numberPatternMap = new HashMap<String, Integer>(); 

    ArrayList<String> patternisedListAllocations = new ArrayList<String>(); 
    patternisedListAllocations.add("A"); 
    patternisedListAllocations.add("B"); 
    patternisedListAllocations.add("C"); 
    patternisedListAllocations.add("D"); 
    Iterator<String> patternisedKeyIterator = patternisedListAllocations.iterator(); 

    for (int i = 0; i<numberArray.length; i++){ 
     if (!numberPatternMap.containsValue(numberArray[i])) { 
      numberPatternMap.put(patternisedKeyIterator.next(), numberArray[i]); 
     } 
    } 
    return numberPatternMap; 
} 

//Loads an xml file containing all the patterns. 
private Document buildPatternTree(){ 
    Document document = null; 
    try { 
    File patternsXML = new File("c:\\Users\\echrdoy\\Desktop\\ALGO.xml"); 
    DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); 
    DocumentBuilder db = dbf.newDocumentBuilder(); 
    document = db.parse(patternsXML); 

    } catch (Exception e){ 
     e.printStackTrace(); 
     System.out.println("Error building tree pattern"); 
    } 
    return document; 
} 

//gets the rootnode of the xml pattern list then called the dfsnodesearch method to analyse the pattern against the int array. If a pattern is found a 
//patternfound exception is thorwn. if the dfsNodeSearch method returns without the exception thrown then the int array didnt match any pattern 
public void patternFinder() { 
    Node rootnode= patternTree.getFirstChild(); 
    try { 
     dfsNodeSearch(rootnode); 
     System.out.println("Pattern not found"); 
    } catch (PatternFoundException p) { 
     System.out.println(p.getPattern()); 
    } 
} 

//takes a node of the xml. the node is checked to see if it matches a pattern (this would only be true if we reached the lowest depth so must have 
//matched a pattern. if no pattern then analyse the node for an expression. if expression is found then test for a match. the int from the array to be tested 
//will be based on the current depth of the pattern tree. as each depth represent an int such as depth 0 (i.e root) represent position 0 in the int array 
//depth 1 represents position 1 in the int array etc. 
private void dfsNodeSearch (Node node) throws PatternFoundException { 
    if (node instanceof Element){ 
     Element nodeElement = (Element) node; 
     String nodeName = nodeElement.getNodeName(); 

     //As this method calls its self for each child node in the pattern tree we need a mechanism to break out when we finally reach the bottom 
     // of the tree and identify a pattern. For this reason we throw pattern found exception allowing the process to stop and no further patterns. 
     // to be checked. 
     if (nodeName.equalsIgnoreCase("pattern")){ 
      throw new PatternFoundException(nodeElement.getTextContent()); 
     } else { 
      String logic = nodeElement.getAttribute("LOGIC"); 
      String difference = nodeElement.getAttribute("DIFFERENCE"); 

      if (!logic.equalsIgnoreCase("")&&!difference.equalsIgnoreCase("")){ 
       if (matchPattern(nodeName, logic, difference)){ 
        if (node.hasChildNodes()){ 
         depth++; 
         NodeList childnodes = node.getChildNodes(); 
         for (int i = 0; i<childnodes.getLength(); i++){ 
          dfsNodeSearch(childnodes.item(i)); 
         } 
         depth--; 
        } 
       } 
      } 
     } 


    } 
} 

//for each node at a current depth a test will be performed against the pattern, logic and difference to identify if we have a match. 
private boolean matchPattern(String pattern, String logic, String difference) { 
    boolean matched = false; 
    int patternValue = patternisedNumberMap.get(pattern); 

    if (logic.equalsIgnoreCase("+")){ 
     patternValue += Integer.parseInt(difference); 
    } else if (logic.equalsIgnoreCase("-")){ 
     patternValue -= Integer.parseInt(difference); 
    } 

    if(patternValue == numberArray[depth]){ 
     matched=true; 
    } 

    return matched; 
} 


} 

は、パターンのXMLリストは次のようになります。この

<?xml version="1.0"?> 
<A LOGIC="=" DIFFERENCE="0"> 
    <A LOGIC="=" DIFFERENCE="0"> 
     <A LOGIC="=" DIFFERENCE="0"> 
      <A LOGIC="=" DIFFERENCE="0"> 
       <pattern>(A)(A)(A)(A)</pattern> 
      </A> 
      <B LOGIC="=" DIFFERENCE="0"> 
       <pattern>(A)(A)(B)(A)</pattern> 
      </B> 
     </A> 
     <B LOGIC="=" DIFFERENCE="0"> 
      <A LOGIC="=" DIFFERENCE="0"> 
       <pattern>(A)(A)(B)(A)</pattern> 
      </A> 
      <B LOGIC="=" DIFFERENCE="0"> 
       <pattern>(A)(A)(B)(B)</pattern> 
      </B> 
     </B> 
    </A> 
    <A LOGIC="+" DIFFERENCE="2"> 
     <A LOGIC="+" DIFFERENCE="4"> 
      <A LOGIC="+" DIFFERENCE="6"> 
       <pattern>(A)(A+2)(A+4)(A+6)</pattern> 
      </A> 
     </A> 
    </A> 
    <B LOGIC="=" DIFFERENCE="0"> 
     <A LOGIC="+" DIFFERENCE="1"> 
      <B LOGIC="+" DIFFERENCE="1"> 
       <pattern>(A)(B)(A+1)(B+1)</pattern> 
      </B> 
     </A> 
     <A LOGIC="=" DIFFERENCE="0"> 
      <A LOGIC="=" DIFFERENCE="0"> 
       <pattern>(A)(B)(A)(A)</pattern> 
      </A> 
      <B LOGIC="+" DIFFERENCE="1"> 
       <pattern>(A)(B)(A)(B+1)</pattern> 
      </B> 
      <B LOGIC="=" DIFFERENCE="0"> 
       <pattern>(A)(B)(A)(B)</pattern> 
      </B> 
     </A> 
     <B LOGIC="=" DIFFERENCE="0"> 
      <A LOGIC="=" DIFFERENCE="0"> 
       <pattern>(A)(B)(B)(A)</pattern> 
      </A> 
      <B LOGIC="=" DIFFERENCE="0"> 
       <pattern>(A)(B)(B)(B)</pattern> 
      </B> 
     </B> 
     <A LOGIC="-" DIFFERENCE="1"> 
      <B LOGIC="-" DIFFERENCE="1"> 
       <pattern>(A)(B)(A-1)(B-1)</pattern> 
      </B> 
     </A> 
    </B> 
    <A LOGIC="+" DIFFERENCE="1"> 
     <A LOGIC="+" DIFFERENCE="2"> 
      <A LOGIC="+" DIFFERENCE="3"> 
       <pattern>(A)(A+1)(A+2)(A+3)</pattern> 
      </A> 
     </A> 
    </A> 
    <A LOGIC="-" DIFFERENCE="1"> 
     <A LOGIC="-" DIFFERENCE="2"> 
      <A LOGIC="-" DIFFERENCE="3"> 
       <pattern>(A)(A-1)(A-2)(A-3)</pattern> 
      </A> 
     </A> 
    </A> 
</A> 

と私のパターン見つかった例外クラスは、このいずれかが同様に誰を支援するかどうかわからないこの

package com.doyleisgod.number.pattern.finder; 

public class PatternFoundException extends Exception { 
private static final long serialVersionUID = 1L; 
private final String pattern; 

public PatternFoundException(String pattern) { 
    this.pattern = pattern; 
} 

public String getPattern() { 
    return pattern; 
} 

} 

のように見えますまたは誰かがこれがどのように働いているかについてのコメントがあれば、それを聞くのはすばらしいことでしょう。

+2

私に正規表現のように見えます。 – Bill

+0

まあ、私は完全一致をハードコードしません(つまり、A = 1のタイプの状況)。遭遇したそれぞれの異なる文字を別の数字にすることを検討したいと思うでしょう。スペースの区切りは、おそらく異なる数字(数字ではない)でなければなりません。 –

+0

これはAIのものです。 Douglas Hofstadterは、そのようなパターン発見だけでキャリアを作った。 –

答えて

2

私は、ステートマシンを構築することをお勧め:

A.をパターンで初期化:

  1. ノーマライズすべてのパターン
  2. すべての深さのルートから始まるすべてのパターンと、すべての可能な選択肢を表し深さ= 6でツリーを構築します。

B.実行ステートマシン


A.1。パターン正規化。

AAAAAA => A0 A0 A0 A0 A0 A0

CACACA => A0 B0 A0 B0 A0 B0(常にAで始まり、そして等次いでB、C、D、)

BのB +したがって、常にA0で正規化されたパターン開始があります。

A.2。マッチしたパターンを見つけるために、再帰を使用して

1.  A0 
    /| \ 
2. A0 B0 A1 
     | | | 
3. A0 A0 A2 
     | | | 
4. A0 B0 B0 
     | | | 
5. A0 A0 B1 
     | | | 
6. A0 B0 B2 
     | | | 
    p1 p2 p3 

B.実行ステートマシン

使用Depth-first search algorithmにツリーを構築します。

意味がありますか?

+0

ありがとうゆり、これは正しい方向に私を始めたようです。私が取った方法は、パターンのツリー構造を作ることです。全てのパターンが樹木に含まれ、DFS技術により、最高レベルの枝を抽出し、複数のパターンを排除するようにする。 –

0

数字をバイトの配列(または必要に応じてint)に分割することができます。各文字に1つずつ割り当てられます。各パターンは、アレイの適切な要素間の直接比較の観点から定義することができる。

ababab=a[0]==a[2] && a[2]==a[4] && a[1]==a[3] && a[3]==a[5] && a[0]!=a[1] 
aaabbb=a[0]==a[1] && a[1]==a[2] && a[3]==a[4] && a[4]==a[5] && a[0]!=a[3] 
fedcba=(a[0]-a[1])==1 && (a[1]-a[2])==1 && (a[2]-a[3])==1 && (a[3]-a[4])==1 && (a[4]-a[5]==1) 
0

これは、以下の非常に速いマッチ機能では簡単です。

PatternがPatternElementの配列であり、PatternElementがLetterと整数で構成されているとします。

数字は、数字の配列です。

NumberとDigit(入れ子のfor-loop)の組み合わせごとにmatch()関数を呼び出します。

match関数は、パターンと数値を左から右に繰り返し、パターンの文字に一致する数字を置き換えます。数字が置き換えられた場合は、同じ数字をすべて同じものに置き換えてください。すでに置換されているため、桁ではないインデックスに達した場合、この要素がパターンと一致するかどうかを確認します。

Example 1 iterations. Pattern: A B A C Number 3 2 3 5 
          ^    ^
        1.       A 2 A 5 replace 3 by A. 
           ^    ^
        2.       A B A 5 replace 2 by B 
           ^    ^ 
        3.       A B A 5 Existing A matches pattern. Good 
            ^    ^
        4.       A B A C replace 5 by C. SUCCESS 

(n + 2)の場合は、置換またはマッチングの際に余分な計算を行うことで同じことができます。

注:数字は数字だけで構成する必要はありません。任意の文字を置き換えたい場合は、同様のパターンに一致させることもできます。したがって、A B C A B CはD F G D F Gにも一般的な形で一致します。

0

あなたは制約を推論した後(それは時々constraint satisfaction problemとも呼ばれる)は、特定の数のパターンに一致するかどうかを調べるためにバックトラックアルゴリズムを使用することができます。

たとえば、それぞれ6桁のd1、d2、d3、d4、d5およびd6をそれぞれ示します。 - 桁の平等のための1(D1 = D2であれば、それらの位置、私が推測されたルールの唯一の2種類を見ることができ、あなたの例では

dx = 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 
d2 = d1 + 1 
d2 = d1 + 2 
d4 = d3 + 1 
d5 = d3 + 2 

:次に、パターンA (A+1) (A+2) B (B+1) (B+2)は、ルール/制約の次のセットに書き換えることができます。パターンは同じ文字を持っている)と算術演算のための別のもの(私はAとBが異なる数でなければならないかどうか、もしそうならばあなたは不等式のための追加の種類のルールを必要とするでしょう)。すべての種類が些細なことに制約に変換される可能性があります。

これらの制約から、可能な解のツリーをコンパイルすることができます。

[A = ?] 
|-- 1 
|-- 2 
|-- 3 
| |-- [B = ?] 
|  |-- 1 
...  ... 

などで始まり、他のノードに制約が含まれている可能性があります。

自分でバックトラックアルゴリズムを正しく実装するのは難しいかもしれません。そのため、お使いのプラットフォーム用のProlog実装を見つけて(this Javaに関する質問を参照)、制約をPrologルールに変換するだけです。

0

例として挙げた特定のパターンについては、入力文字列が一致するかどうかを確認するための簡単なプログラムを書くことができます。

あなたが言及したパターンよりパターンが複雑になる場合は、Context-free grammarと正規表現を使用してルールを指定できます。また、指定されたルールに従って入力文字列を処理し、一致するかどうかを返すlexやyaccのようなツールがあります。

関連する問題