二進位制多欄位匹配
阿新 • • 發佈:2019-10-09
package util; /** * <pre> * 將多個int正整型合併為一個long型進行儲存,並通過xor運算計算兩組int是否匹配 * MultiEnumVal64 int正整數取值必須大於0,0值用於MultiVal64本身特殊計算使用,<=0表示不參與匹配計算。 * 如:業務中需要根據行人是否戴眼鏡、是否戴帽子、衣服顏色來進行查詢 * 是否戴眼鏡取值: 1 未知 ; 2 戴眼鏡 ; 3 不帶眼鏡 ; * 是否戴帽子取值: 1 未知 ; 2 戴帽子 ; 3 不帶帽子 ; * 衣服的顏色取值: 1 未知 ; 2 紅色 ; 3 綠色 ; 4 白色 ; * </br> * 假設某一個抓拍體型資料為:眼鏡=2; 帽子=1; 顏色=4 * 1、構建MultiVal64資料 * <code> * MultiEnumVal64 mv64 = new MultiEnumVal64(3,3,4); //建立MultiVal64物件,定義每一種屬性的最大取值 ,定義的順序為:眼鏡、帽子、顏色 * mv64.build(2,1,4); //構造資料 * long longVal = mv64.getLong(); //獲取long值,可儲存於資料庫 * </code> * 2、java編碼匹配MultiVal64資料 ,沿用1、的例子 * a、場景1查詢條件是:戴著帽子且戴著眼鏡 * <code> * MultiEnumVal64 mv642 = new MultiEnumVal64(3,3,4); //建立MultiVal64物件,定義每一種屬性的最大取值 ,定義的順序為:眼鏡、帽子、顏色 * mv642.build(2,2,-1); //構造資料,-1表示不參與匹配,原始資料不論取何值都可以匹配成功 * System.out.printl(mv642.xorTrue(mv64)); //匹配資料,該場景返回false,因為是否戴眼鏡項匹配不成功 * </code> * b、場景1查詢條件是:戴著眼鏡穿白色衣服 * <code> * MultiEnumVal64 mv643 = new MultiEnumVal64(3,3,4); //建立MultiVal64物件,定義每一種屬性的最大取值 ,定義的順序為:眼鏡、帽子、顏色 * mv643.build(2,-1,4); //構造資料,-1表示不參與匹配,原始資料不論取何值都可以匹配成功 * System.out.printl(mv643.xorTrue(mv64)); //匹配資料,該場景返回true * </code> * 3、資料庫sql寫法1,以場景2.->b為例 * <code> * String sql = ""; * if(mv643.isHasIgnoreVal()) { * sql = "select * from table where column_name ("; * for (int[] pos : mv643.getIgnorePos()) { * if (pos[0] > 0 || pos[1] > 0) { * for (int start = pos[1]; start <= pos[0]; start++) { * sql + "& ~(1 << " + start + ")"; * } * } * } * sql += ") ^ " + mv643.getLong() + " = 0;"; * } else { * sql = "select * from table where column_name ^ " + mv643.getLong() + " =0;"; * } * </code> * 4、資料庫sql寫法2,以場景2.->b為例 * <code> * String sql = ""; * if(mv643.isHasIgnoreVal()) { * sql = "select * from table where (column_name & ~"; * sql += mv643.getComparVal(); * sql += ") ^ " + mv643.getLong() + " = 0;"; * } else { * sql = "select * from table where column_name ^ " + mv643.getLong() + " =0;"; * } * </code> * </pre> * */ public class MultiEnumVal64 { /** * 所有屬性最大值二進位制的長度容器 */ private int[] config; /** * 忽略不參與匹配值的位置 */ private int[][] ignorePos; /** * 二進位制數值 */ private long longVal; /** * 所有屬性最大值二進位制的長度綜合 */ private int length; /** * 是否有不參與匹配標識 */ private boolean hasIgnoreVal = false; /** * 每一組int取值的最大值 * * @param maxValConfig */ public MultiEnumVal64(int... maxValConfig) { this.config = new int[maxValConfig.length]; this.ignorePos = new int[maxValConfig.length][2]; for (int index = 0; index < maxValConfig.length; index++) { int maxVal = maxValConfig[index]; if (maxVal < 0) { throw new IllegalArgumentException("value must be greater than 0"); } int tempLength = Integer.toBinaryString(maxVal).length(); this.config[index] = tempLength; length += tempLength; } if (length + 1 > 63) { throw new IllegalArgumentException(length + " over the maximum digit 62"); } } /** * 數值<=0 表示不參與計算 * * values要把所有值按順序傳入,比如說總共有10個屬性,只匹配一個屬性,要把剩下9個屬性補上,用不參與匹配-1或0補位 * * @param values * @return */ public MultiEnumVal64 build(int... values) { if (values.length != this.config.length) { throw new IllegalArgumentException("value array length and config mismatch, config length is " + this.config.length + " , but value array length is " + values.length); } /** * 符號位最左邊 */ StringBuilder binaryStr = new StringBuilder("1"); /** * 記錄不參與匹配屬性的下標 */ int preLength = 1; for (int i = 0; i < values.length; i++) { int binaryLength = this.config[i]; int maxConfigVal = (1 << binaryLength); int val = values[i]; /** * 當前屬性值不能大於初始所規定當前屬性的最大值 */ if (val > maxConfigVal) { throw new IllegalArgumentException("the " + i + " value should be less than or equal to " + maxConfigVal); } /** * 如果有不參與的屬性標記為true,用0把最大佔位補滿 */ if (val <= 0) { hasIgnoreVal = true; for (int j = 0; j < binaryLength; j++) { binaryStr.append("0"); } /** * 記錄不參與屬性的位置 */ ignorePos[i][0] = this.length - preLength; ignorePos[i][1] = this.length - preLength - (this.config[i] - 1); } else { /** * 以下全是參與的屬性,十進位制轉換二進位制 */ String binaryVal = Integer.toBinaryString(val); /** * 如果當前二進位制值長度比初始最大值小,那麼用0補位 */ for (int j = 0; j < binaryLength - binaryVal.length(); j++) { binaryStr.append("0"); } binaryStr.append(binaryVal); /** * 用-1表示該屬性不被忽略,所以不需要記錄被忽略的位置 */ ignorePos[i][0] = -1; ignorePos[i][1] = -1; } /** * 實時追加下標才能準確計算到每個屬性的在二進位制中的位置 */ preLength += binaryLength; } /** * 將拼接成的二進位制轉換為十進位制 */ this.longVal = Long.parseLong(binaryStr.toString(), 2); return this; } public MultiEnumVal64 build(long val) { this.longVal = val; build(getVals()); return this; } public long getLong() { return longVal; } /** * 將處理過的二進位制通過字元擷取還原成陣列 * @return */ public int[] getVals() { int[] values = new int[this.config.length]; String binary = Long.toBinaryString(getLong()); int binaryLength = binary.length(); int endIndex = binaryLength; for (int i = this.config.length - 1; i >= 0; i--) { int startIndex = endIndex - this.config[i]; if (startIndex < 1) { if (endIndex > 1) { startIndex = 1; values[i] = Integer.parseInt(binary.substring(startIndex, endIndex), 2); } else { values[i] = -1; } } else { values[i] = Integer.parseInt(binary.substring(startIndex, endIndex), 2); } if (values[i] == 0) { values[i] = -1; } endIndex = startIndex; } return values; } public int[][] getIgnorePos() { return ignorePos; } public int getLength() { return length; } public long getComparVal() { long m1 = 0L; if (hasIgnoreVal) { for (int[] pos : ignorePos) { if (pos[0] > 0 || pos[1] > 0) { for (int start = pos[1]; start <= pos[0]; start++) { m1 = m1 ^ (1L << start); } } } } return m1; } public long transform(long val) { return val &~ getComparVal(); } public long xor(long val) { long v1 = transform(val); return v1 ^ getLong(); } public long xor(MultiEnumVal64 mv) { return xor(mv.getLong()); } public boolean xorTrue(long val) { return xor(val) == 0; } public boolean xorTrue(MultiEnumVal64 mv) { return xor(mv) == 0; } public boolean isHasIgnoreVal() { return hasIgn