2012-07-10 18 views
7

Sto cercando di creare un programma che identi fi ca determinati modelli nei numeri. Non sono sicuro che questo abbia bisogno di un algoritmo o di una programmazione attentamente studiata. Non sto cercando qualcuno che fornisca il codice sorgente, solo alcune idee che stimolano il pensiero per mettermi nella giusta direzione.Programma Java per identificare gli schemi nei numeri

I numeri saranno di lunghezza fissa di 6 cifre da 000000 a 999999. Immagino che ogni numero venga memorizzato come parte di un array. Vorrei quindi testare il numero in base a un modello.

Per esempio diciamo che il 3 modelli sto usando sono

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 

immagino la parte che sono bloccato su è come allocare ogni parte dell'array intero in un valore come A o B

I miei pensieri iniziali sarebbero solo per assegnare ciascuna parte come una singola lettera. Quindi, se la matrice costituita da 1 3 5 4 6 8, quindi vorrei creare una mappa come

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

Poi in qualche modo prendere la prima modello,

AAAAAA 

e prova con qualcosa di simile, se (AAAAAA = ABCDEF) AAAAAAA allora abbiamo abbinato

se poi non provare (ABABAB = ABCDEF) ecc attraverso tutti i miei modelli

In questo scenario non v'è alcun motivo per cui il valore assegnato a C sopraelevazione essere uguale al valore assegna a F come nel numero 234874.

Non sono sicuro che questo abbia un senso per nessuno, ma suppongo di poter affinare la mia domanda sulla base del feedback.

In sintesi, sto cercando idee su come fare in modo che un programma accetti un numero di 6 cifre e restituisca a noi quale modello corrisponde.

SOLUZIONE

Dopo i commenti riportati mi ha messo su una buona pista sotto è quello che ho creato come soluzione finale.

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; 
} 


} 

l'elenco XML di modelli assomiglia a questo

<?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> 

e il mio modello di classe di eccezione trovato assomiglia a questo

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; 
} 

} 

Non sono sicuro se tutto questo vi aiuterà chiunque con un simile problema o se qualcuno ha commenti su come funziona sarebbe bello ascoltarli.

+2

Sembra regex per me. – Bill

+0

Bene, non vorrei hardcode una corrispondenza esatta (cioè, A = 1 situazioni di tipo). Probabilmente vorrai considerare ogni diverso personaggio incontrato per essere una cifra diversa. Le separazioni di spazio dovrebbero probabilmente essere numeri diversi (non cifre). –

+0

Questa è roba di IA. Douglas Hofstadter ha fatto la sua carriera proprio su questa scoperta di modelli. –

risposta

2

vorrei suggerire di costruire macchina statale:

A.Inizializzazione con modelli:

  1. Normalizza tutti i modelli
  2. Costruire un albero con profondità = 6 che rappresenta tutti i modelli a partire dalla radice e tutte le scelte possibili in ogni profondità.

B. Run macchina a stati


A.1. Normalizzazione del modello.

AAAAAA => A0 A0 A0 A0 A0 A0

CACACA => A0 B0 A0 B0 A0 B0 (inizia sempre con A, B e poi, C, D, ecc)

B B + 1 B + 2 A A + 1 A + 2 => A0 A1 A2 B0 B1 B2

Così, si ha sempre l'inizio del modello normalizzato con A0.

A.2. Costruire un albero

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. Run macchina a stati

Usa Depth-first search algorithm utilizzando la ricorsione per trovare modello abbinato.

Ha senso?

+0

Grazie Yuri, Sembra che mi abbia avviato nella giusta direzione. il metodo che ho preso è quello di creare una struttura ad albero di modelli. in modo tale che tutti gli schemi siano contenuti nell'albero e con la tecnica DFS per eliminare i rami al livello più alto, eliminando così più schemi. –

0

È possibile suddividere i numeri in una matrice di byte (o int, se si preferisce), uno per ciascun carattere. Ogni modello può essere definito in termini di confronto diretto tra gli elementi appropriati dell'array.

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

Questo è facile con la seguente funzione di corrispondenza molto veloce.

Dato i motivi sono matrici di PatternElement, dove PatternElement è costituito da una lettera e un numero intero.

Dato che i numeri sono matrici di cifre.

Ora chiama una funzione match() con ciascuna combinazione di Numero e cifra (nested for-loop).

La funzione di corrispondenza itera su modello e numero da sinistra a destra e sostituisce i numeri in modo che corrispondano alle lettere nel motivo. Se una cifra viene sostituita, sostituire anche tutte le stesse cifre a destra. Se raggiungi un indice che non è una cifra, poiché è già stato sostituito, controlla se questo elemento corrisponde al modello.

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 

Per il (n + 2) si potrebbe fare lo stesso, facendo qualche matematica extra durante la sostituzione o la corrispondenza.

NOTA: il numero non deve essere composto solo da cifre. Se ti piace sostituire qualsiasi carattere, puoi persino abbinare modelli simili! Quindi A B C A B C corrisponderebbe anche a D F G D F G nella forma generica.

0

Si può dedurre vincoli e quindi utilizzare backtracking algoritmi per scoprire se determinato numero corrisponde al modello (è a volte indicato come constraint satisfaction problem).

Ad esempio, denotiamo ognuna delle 6 cifre d1, d2, d3, d4, d5 e d6 rispettivamente.Quindi, il modello A (A+1) (A+2) B (B+1) (B+2) può essere riscritto per la seguente serie di regole/vincoli:

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

Nei tuoi esempi che posso vedere solo 2 tipi di regole dedurre - uno per l'uguaglianza di cifre (d1 = d2 se le loro posizioni in pattern hanno lo stesso carattere) e un altro per operazioni aritmetiche (non so se A e B dovrebbero essere numeri diversi, e in tal caso avrai bisogno di un ulteriore tipo di regole per la disuguaglianza). Tutti i tipi possono essere banalmente tradotti in vincoli.

L'albero delle possibili soluzioni può essere quindi compilato da questi vincoli. Può iniziare con qualcosa di simile:

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

e quindi contenere i vincoli su altri nodi.

Potrebbe essere difficile implementare correttamente l'algoritmo di backtracking da solo, quindi è logico trovare l'implementazione di Prolog per la propria piattaforma (vedere this per Java) e quindi solo tradurre i vincoli in regole Prolog.

0

Per i modelli specifici citati come esempi, è possibile scrivere programmi semplici per verificare se le stringhe di input corrispondono.

Se i motivi si complicano più di quelli menzionati, è possibile utilizzare Context-free grammar e le espressioni regolari per specificare le proprie regole. E ci sono strumenti come lex e yacc che elaboreranno le stringhe di input in base alle regole specificate e restituiranno se corrispondono o no.

Problemi correlati