最近在分析資料表時需要filter相似的資料,並且留下兩筆之中以時間為最新的一筆。
關於相似的定義是在於:
假設一資料表的定義為
Pair1, Pair2, UpdateTime (Pair1, Pair2為primary key)
實際資料可能為
X1234, C1456, 2012/09/23
C1456, X1234, 2010/08/11
.....
在第一筆及第二筆之X1234, C1456與C1456, X1234及視為同一種情況,依據time來捨棄其一。
當然還有很多組,又或者有些不會有這種請況,則就不用捨棄囉!
本來是先利用SQL語法撈取所有的資料,再利用SQL語法去過濾!如下:
select * from table where Pair1 = '"+pair2+"' and Pair2 = '"+paor1+"';
利用取出的一筆再去查詢資料表該筆是否有此一請況!
雖然是寫的出來,但是方法不太妥!
因此就想到說A -> B, B->A兩者若利用其hashcode相加的話不就會一樣?
不過利用這個方法需要注意的是,假設X1234, C1456之hashcode總和為234123412
難免會有其他組之hashcode總和會跟他一樣的,但兩組是八竿子沒相關的,事實是真的有!
因此,我就定義了Map
Map<Integer, Map<String, String>> pairFilter = new HashMap<Integer, Map<String, String>>();
Integer是存放hashcode為key值,對映的是另一個Map,另一個Map是存放key是pair
如:"X1234, C1456",其value為time!!
如此若碰到hashcode總和一樣的pair,如"X1234, C1456" and "C5434, D3456"
就可以一起存放至Map<String, String>,以同一hashcode之key與之對映!
作法上會稍微複雜一點,比起再去查詢SQL如此直觀的想法,但少用到database來操作
總是比較快,更何況資料不是百筆,而可能是數萬筆!
上述為建立pairfilter variable的程式,一開始之while(rs.next())為run該資料表下所有的資料,
首先先檢查if(!pairFilter.containsKey(hashcodePair)) 此key是否已存在了,沒有的話就建立它
所對映value,即另一Map。再來若該key值已存在,則很有可能碰到兩種情況:
一、B->A出現了
利用check.containsKey(pair2+","+pair1)判斷
若是B->A則接下來是判斷它們的time來決定要留誰
二、剛好hashcode加總相等
若是加總相等的,則將Map check = pairFilter.get(hashcodePair);之check再put進一組資料即可!
如此一來就大功告成!接下來就不列出print pairFilter的過程!
方法二:
後來在無意中又要比較A->B, B->A則一的問題,發現我上面的方法是利用
Map<Integer, Map<String, String>> pairFilter = new HashMap<Integer, Map<String, String>>();
來filter,現在我改成了宣告兩個變數來處理這一個問題。
Set<Integer> hashcodeSet = new HashSet<Integer>(); //紀錄pair的hashcode
Map<String, String> pairsFilter = new HashMap<String, String>(); //pairs -> key, updatetime->value
修改後的程式如下:
修改後的程式變的比較單純,利用hashcodeSet幫忙把關,若碰到加總一樣的hashcode,
有兩種可能,一個是B->A出現了,若非B->A則就是新的一對pair,因此就加到pairsFilter內,
想法變得比較單純一點。
方法三:
近期在這個問題上找到比較簡單的判斷法(學妹提供),只要保留一個HashMap即可
相關程式碼如下:
方方的put,當真正的B->A出現時,就會與之前的A->B碰撞,此時只要彼此比較更新時間
就可以取得誰才有生存權!
由於不清楚A->B, B->A那個會先出現,因此設了一個Set來存Hashcode,其實只要先顛倒
自己的順序就可以清楚知道另一個配對是否出現了,只能說想太多了orz...
總結來說,當初將問題想的過於複雜,導致之前的作法有多餘的檢查!
關於相似的定義是在於:
假設一資料表的定義為
Pair1, Pair2, UpdateTime (Pair1, Pair2為primary key)
實際資料可能為
X1234, C1456, 2012/09/23
C1456, X1234, 2010/08/11
.....
在第一筆及第二筆之X1234, C1456與C1456, X1234及視為同一種情況,依據time來捨棄其一。
當然還有很多組,又或者有些不會有這種請況,則就不用捨棄囉!
本來是先利用SQL語法撈取所有的資料,再利用SQL語法去過濾!如下:
select * from table where Pair1 = '"+pair2+"' and Pair2 = '"+paor1+"';
利用取出的一筆再去查詢資料表該筆是否有此一請況!
雖然是寫的出來,但是方法不太妥!
因此就想到說A -> B, B->A兩者若利用其hashcode相加的話不就會一樣?
不過利用這個方法需要注意的是,假設X1234, C1456之hashcode總和為234123412
難免會有其他組之hashcode總和會跟他一樣的,但兩組是八竿子沒相關的,事實是真的有!
因此,我就定義了Map
Map<Integer, Map<String, String>> pairFilter = new HashMap<Integer, Map<String, String>>();
Integer是存放hashcode為key值,對映的是另一個Map,另一個Map是存放key是pair
如:"X1234, C1456",其value為time!!
如此若碰到hashcode總和一樣的pair,如"X1234, C1456" and "C5434, D3456"
就可以一起存放至Map<String, String>,以同一hashcode之key與之對映!
作法上會稍微複雜一點,比起再去查詢SQL如此直觀的想法,但少用到database來操作
總是比較快,更何況資料不是百筆,而可能是數萬筆!
while(rs.next()){
pair1 = rs.getString("Pair1");
pair2 = rs.getString("Pair2");
updateTime = rs.getString("Updatetime");
int hashcodePair = pair1.hashCode()+pair2.hashCode();
if(!pairFilter.containsKey(hashcodePair)){
Map data = new HashMap();
data.put(pair1+","+pair2, updateTime);
pairFilter.put(hashcodePair, data);
}else{
//hashcode total same. ex: A->B, B->A or just total same
Map check = pairFilter.get(hashcodePair);
if(check.containsKey(pair2+","+pair1)){
SimpleDateFormat dateformat = new SimpleDateFormat("yyyy/MM/dd");
java.util.Date date1 = dateformat.parse(check.get(pair2+","+pair1));
java.util.Date date2 = dateformat.parse(updateTime);
if(date1.before(date2)){
check.remove(pair2+","+pair1);
check.put(pair1+","+pair2, updateTime);
pairFilter.put(hashcodePair, check);
}
}else{
check.put(pair1+","+pair2, updateTime);
pairFilter.put(hashcodePair, check);
}
}
}
上述為建立pairfilter variable的程式,一開始之while(rs.next())為run該資料表下所有的資料,
首先先檢查if(!pairFilter.containsKey(hashcodePair)) 此key是否已存在了,沒有的話就建立它
所對映value,即另一Map。再來若該key值已存在,則很有可能碰到兩種情況:
一、B->A出現了
利用check.containsKey(pair2+","+pair1)判斷
若是B->A則接下來是判斷它們的time來決定要留誰
二、剛好hashcode加總相等
若是加總相等的,則將Map
方法二:
後來在無意中又要比較A->B, B->A則一的問題,發現我上面的方法是利用
Map<Integer, Map<String, String>> pairFilter = new HashMap<Integer, Map<String, String>>();
來filter,現在我改成了宣告兩個變數來處理這一個問題。
Set<Integer> hashcodeSet = new HashSet<Integer>(); //紀錄pair的hashcode
Map<String, String> pairsFilter = new HashMap<String, String>(); //pairs -> key, updatetime->value
修改後的程式如下:
while(rs.next()){
pair1 = rs.getString("Pair1");
pair2 = rs.getString("Pair2");
updateTime = rs.getString("Updatetime");
if(!hashcodeSet.contains(pair1.hashCode()+pair2.hashCode())){
hashcodeSet.add(pair1.hashCode()+pair2.hashCode());
pairsFilter.put(pair1+","+pair2, updateTime);
}else{
if(pairsFilter.containsKey(pair2+","+pair1)){
SimpleDateFormat dateformat = new SimpleDateFormat("yyyy/MM/dd");
java.util.Date date1 = dateformat.parse(pairsFilter.get(pair2+","+pair1)); java.util.Date date2 = dateformat.parse(updateTime);
if(date1.before(date2)){
pairsFilter.remove(pair2+","+pair1);
}
pairsFilter.put(protein1+","+protein2, updateTime);
}
}
}
修改後的程式變的比較單純,利用hashcodeSet幫忙把關,若碰到加總一樣的hashcode,
有兩種可能,一個是B->A出現了,若非B->A則就是新的一對pair,因此就加到pairsFilter內,
想法變得比較單純一點。
方法三:
近期在這個問題上找到比較簡單的判斷法(學妹提供),只要保留一個HashMap即可
相關程式碼如下:
while(rs.next()){
protein1 = rs.getString("Protein1");
protein2 = rs.getString("Protein2");
updateTime = rs.getString("Updatetime");
if(!pairsFilter.containsKey(protein2+","+protein1)){
pairsFilter.put(protein1+","+protein2, updateTime);
}else{
SimpleDateFormat dateformat = new SimpleDateFormat("yyyy/MM/dd");
java.util.Date date1 = dateformat.parse(pairsFilter.get(protein2+","+protein1));
java.util.Date date2 = dateformat.parse(updateTime);
if(date1.before(date2)){
pairsFilter.remove(protein2+","+protein1);
pairsFilter.put(protein1+","+protein2, updateTime);
}
}
}
首先,當第一筆資料進入檢查時,找尋B -> A是否存在,若不存在則A->B例子就可大大方方的put,當真正的B->A出現時,就會與之前的A->B碰撞,此時只要彼此比較更新時間
就可以取得誰才有生存權!
由於不清楚A->B, B->A那個會先出現,因此設了一個Set來存Hashcode,其實只要先顛倒
自己的順序就可以清楚知道另一個配對是否出現了,只能說想太多了orz...
總結來說,當初將問題想的過於複雜,導致之前的作法有多餘的檢查!
留言
張貼留言