2013-03-20 68 views
2

我正在做一些文本分析,並且需要在String中記錄字符轉換的頻率。我有n字符類別:例如,isUpperCase()isNumber()isSpace()高效地比較字符串中的連續字符

鑑於有n類別,將有n^2過渡類別,例如, 「isUpperCase() - >isUpperCase()」, 「isUpperCase - >isLetter()」, 「isLetter() - >isUpperCase()」 等

給定的文本塊,我想記錄所發生的轉換數目。我會想象構建一個Map與過渡類型KeysInteger作爲每個Value

對於文本「TO」的塊中,Map看起來像[isUpper -> isUpper : 1, isUpper -> isSpace : 1]

的一部分,我想不通,不過,是如何構建一個Map這裏,從我所看到的,Key將包括的2 boolean方法。

回答

4

創建一個代表字符類型的enum - 您需要一種方法來獲取給定字符的字符類型enum。我確信有比下面做的更好的方法來做這件事,但這只是對讀者的一個練習。

接下來創建一個方法,它將前一個字符和當前字符連接起來,並將它們的類型連接成一個唯一的String

最後循環輸入字符串和嘿presto。

private static enum CharacterType { 

    UPPER { 
     @Override 
     boolean isA(final char c) { 
      return Character.isUpperCase(c); 
     } 
    }, 
    LOWER { 
     @Override 
     boolean isA(final char c) { 
      return Character.isLowerCase(c); 
     } 
    }, 
    SPACE { 
     @Override 
     boolean isA(final char c) { 
      return Character.isWhitespace(c); 
     } 
    }, 
    UNKOWN { 
     @Override 
     boolean isA(char c) { 
      return false; 
     } 
    }; 

    abstract boolean isA(final char c); 

    public static CharacterType toType(final char c) { 
     for (CharacterType type : values()) { 
      if (type.isA(c)) { 
       return type; 
      } 
     } 
     return UNKOWN; 
    } 
} 

private static String getTransitionType(final CharacterType prev, final CharacterType current) { 
    return prev + "_TO_" + current; 
} 

public static void main(String[] args) { 
    final String myString = "AAaaA Aaa AA"; 
    final Map<String, Integer> countMap = new TreeMap<String, Integer>() { 
     @Override 
     public Integer put(final String key, final Integer value) { 
      final Integer currentCount = get(key); 
      if (currentCount == null) { 
       return super.put(key, value); 
      } 
      return super.put(key, currentCount + value); 
     } 
    }; 
    final char[] myStringAsArray = myString.toCharArray(); 
    CharacterType prev = CharacterType.toType(myStringAsArray[0]); 
    for (int i = 1; i < myStringAsArray.length; ++i) { 
     final CharacterType current = CharacterType.toType(myStringAsArray[i]); 
     countMap.put(getTransitionType(prev, current), 1); 
     prev = current; 
    } 
    for (final Entry<String, Integer> entry : countMap.entrySet()) { 
     System.out.println(entry); 
    } 
} 

輸出:

LOWER_TO_LOWER=2 
LOWER_TO_SPACE=1 
LOWER_TO_UPPER=1 
SPACE_TO_SPACE=1 
SPACE_TO_UPPER=2 
UPPER_TO_LOWER=2 
UPPER_TO_SPACE=1 
UPPER_TO_UPPER=2 

運行在你的問題的內容(825個字符)的方法把9ms的。

+0

首先,我只想說謝謝。我不知道這是否會工作,因爲我需要更多地瞭解'enum',但它看起來很棒! – 2013-03-20 19:27:47

+0

這確實是一個非常優雅的解決方案。我喜歡! – loopkin 2013-03-21 17:35:00

0

如果你想大多數的過渡將存在,那麼二維數組將最好的工作:

int n = _categories.size(); 
int[][] _transitionFreq = new int[n][n]; 

如果你認爲這將是一個解析數組,然後地圖將在條件更有效的內存使用率,但性能方面效率較低。

這是一個權衡,你必須根據你的數據和字符類型的數量。