某一个商品可能有多个标签属性,比如A,B,C,D,E,F,G,H
每个属性分别有出现与不出现的情况。。所有是一个组合的关系 。用一个二进制的字符串或者数字来表示出现与不出现,但是这样要搜索包含某个标签 的时候,得枚举所有的情况,然后以OR的关系去搜索。这样肯定麻烦。。既然要为了存储与索引搜索方便,我暂时想用素数来解决。。
对每一个标签分配一个素数,比如A-》2,B->3,C->5,D->7
这样多个标签的组合就使用他们的乘积作为最终状态。。这样是一种编码的广式,
比如包含A,B,C
则对应的值是2*3*5=30
当然也需要解码,对于给定的一个值30
如果能整除对应的素数集合,则表示包含该标签
30的素数因子为:2,3,5 为相应的标签。简单的实现代码如下。。
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
/**
* @author genuine 房源标签 <br>
* 使用素数方式存储
*
*/
public enum Label {
/**
* 新推
*/
N(2),
/**
* 随时看房
*/
K(3),
/**
* 视频
*/
V(5);
/**
* 素数
*/
private final int primeV;
private Label(int v) {
this.primeV = v;
}
public int getPrimeV() {
return primeV;
}
/**
*
* 通过一个数字找到对应的所有特征
*
* @param v
* @return
*/
public static Label[] decodedLabel(int v) {
List<Label> list = new ArrayList<Label>();
Label[] labels = Label.values();
int temp = v;
for (int i = 0; i < labels.length; i++) {
if (temp % labels[i].getPrimeV() == 0) {
list.add(labels[i]);
temp = temp / labels[i].getPrimeV();
}
}
if (temp != 1) {
System.err.println("是非法值");
return null;
}
return list.toArray(new Label[list.size()]);
}
private final static Map<Integer,int[]> cacheIncludeByLabel=new HashMap<Integer,int[]>();
/**
* 查询包含某几个标签的时候的所有可能的组合值
*
* @param labels
* @return
*/
public static int[] includeByLabel(Label... labels) {
if (labels.length < 1) {
return null;
}
//查找缓存,这样可以减少运算
Integer key=encodedLabels(labels);
int[] cache = cacheIncludeByLabel.get(key);
if(cache!=null){
return cache;
}
Label[] allLabels = Label.values();
// 获得其它标签
List<Label> otherList = new ArrayList<Label>(allLabels.length);
for (int i = 0; i < allLabels.length; i++) {
boolean isExist = false;
for (int j = 0; j < labels.length; j++) {
if (allLabels[i].getPrimeV() == labels[j].getPrimeV()) {
isExist = true;
}
}
if (!isExist) {
otherList.add(allLabels[i]);
}
}
int sum = 1;
for (int i = 0; i < labels.length; i++) {
sum *= labels[i].getPrimeV();
}
final int otherSize = otherList.size();
final int size = otherSize * 2;
final int[] includeV = new int[size];
int pos = 0;
includeV[pos++] = sum;// 纯包含指定的label
// 计算不同的组合的值
for (int i = pos; i < size; i++) {
int[] compose = new int[otherSize];
toBinary(i, compose);
int tempSum = sum;
for (int j = 0; j < otherSize; j++) {
if (compose[j] == 1) {
tempSum *= otherList.get(j).getPrimeV();
}
}
includeV[i] = tempSum;
}
//缓存
cacheIncludeByLabel.put(key, includeV);
return includeV;
}
/**
* 通过多个标签返回最终数字
* 如果参数非法则会返回值1
* @param labels
* @return
*/
public static int encodedLabels(Label[] labels) {
if (labels == null) {
return 1;
}
int sum = 1;
for (int i = 0; i < labels.length; i++) {
sum *= labels[i].getPrimeV();
}
return sum;
}
public static int encodedLabel(Label label) {
if (label == null) {
return 1;
}
return label.getPrimeV();
}
/**
* 通过多个标签返回最终数字
* 如果参数非法则会返回值1
* @param labels
* @return
*/
public static int encodedLabels(Iterator<Label> labels) {
if (labels == null) {
return 1;
}
int sum = 1;
while (labels.hasNext()) {
sum *= labels.next().getPrimeV();
}
return sum;
}
/**
* 给定数字,返回该数字的二进制表示并存在一个int数组中
*/
private static void toBinary(int inputNum, int[] result) {
int pos = result.length;
do {
result[--pos] = inputNum & 1;
inputNum >>>= 1;
} while (inputNum != 0);
}
public static void main(String[] args) {
// int i = 15;
// Label[] label = Label.getLabel(i);
//
// for (int j = 0; j < label.length; j++) {
// System.out.println(label[j]);
// }
//
// System.out.println("------------------------------");
Label k = Label.K;
Label n = Label.N;
int a[] = Label.includeByLabel(n, k);
System.out.println(Arrays.toString(a));
}
}
这样查询多个状态组合的时候,