Permalink
Cannot retrieve contributors at this time
Name already in use
A tag already exists with the provided branch name. Many Git commands accept both tag and branch names, so creating this branch may cause unexpected behavior. Are you sure you want to create this branch?
HowToKB/src/kb/howtokb/utils/AutoMap.java
Go to fileThis commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
301 lines (264 sloc)
7.35 KB
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package kb.howtokb.utils; | |
import java.util.ArrayList; | |
import java.util.Collection; | |
import java.util.Comparator; | |
import java.util.HashMap; | |
import java.util.HashSet; | |
import java.util.LinkedHashMap; | |
import java.util.List; | |
import java.util.Map; | |
import java.util.Set; | |
import java.util.TreeMap; | |
/** | |
* @description this class is like C# AutoMap | |
* @date Dec 8, 2011 | |
* @version 1 | |
* @author ntandon | |
*/ | |
public class AutoMap<K, V> extends HashMap<K, V> { | |
private static final long serialVersionUID = 1L; | |
public AutoMap(int size) { | |
super(size); | |
} | |
public AutoMap(List<K> repeatedValues, V one) { | |
super(); | |
boolean isVInt = one.getClass().getCanonicalName().endsWith("Integer"); | |
for (K k : repeatedValues) { | |
if (isVInt) | |
addNumericValueInt(k, one); | |
else | |
addNumericValue(k, one); | |
} | |
} | |
public AutoMap(List<K> kv, V one, String sep) { | |
super(); | |
boolean isVInt = one.getClass().getCanonicalName().endsWith("Integer"); | |
for (K k : kv) { | |
// Treat as list of values if no sep is present in kv. | |
if (!k.toString().contains(sep)) { | |
if (isVInt) | |
addNumericValueInt(k, one); | |
else | |
addNumericValue(k, one); | |
continue; | |
} | |
String[] kAndv = k.toString().split(sep); | |
if (isVInt) | |
addNumericValueInt(k, (V) (new Integer(kAndv[1]))); | |
else | |
addNumericValueInt(k, (V) (new Double(kAndv[1]))); | |
} | |
} | |
/** | |
* @param m = {k1,20;k2,30} | |
* "this" map = {k1,20;k3,10} | |
* this map is updated = {k1,40;k2,30;k3,10} | |
*/ | |
public void merge(Map<K, V> m) { | |
for (Entry<K, V> e : m.entrySet()) | |
addNumericValue(e.getKey(), e.getValue()); | |
} | |
public AutoMap() { | |
super(); | |
} | |
public AutoMap(Map<K, V> existingMap) { | |
super(existingMap); | |
} | |
public void addNumericValueLong(K patternKey, V scoreOrFreq) { | |
V value = scoreOrFreq; | |
if (this.containsKey(patternKey)) { | |
Long temp = (Long) value + (Long) this.get(patternKey); | |
this.put(patternKey, (V) temp); | |
} else | |
this.put(patternKey, value); | |
} | |
public void addNumericValueInt(K patternKey, V scoreOrFreq) { | |
V value = scoreOrFreq; | |
if (this.containsKey(patternKey)) { | |
Integer temp = (Integer) value + (Integer) this.get(patternKey); | |
this.put(patternKey, (V) temp); | |
} else | |
this.put(patternKey, value); | |
} | |
public void addNumericValue(K patternKey, V scoreOrFreq) { | |
V value = scoreOrFreq; | |
if (scoreOrFreq instanceof Number && this.containsKey(patternKey)) { | |
Double temp = | |
((Number) scoreOrFreq).doubleValue() | |
+ ((Number) this.get(patternKey)).doubleValue(); | |
value = (V) temp; | |
} | |
this.put(patternKey, value); | |
} | |
/** | |
* Input: | |
* | |
* <PRE> | |
* p2,(s2,1) | |
* Existing map: | |
* p2,(s1,2; s3,5; s2,1) | |
* Output: | |
* p2 (s1,2; s3,5; s2,2) | |
* Constraints: | |
* this automap is (K, AutoMap< K2, V2 extends Number >) | |
* </PRE> | |
* | |
* @param p1 | |
* , (s1, 2) | |
* @return true: if adding was successful, false otherwise. | |
* | |
*/ | |
public <K2, V2 extends Number> boolean updateInternalMap(K key, | |
K2 keyInternal, V2 valInternal) { | |
AutoMap<K2, V2> valInternalUpdated = new AutoMap<>(); | |
try { | |
// Type check: the automap must be (K, AutoMap< K2, V2 extends | |
// Number >) | |
if (!this.values().getClass().getName().equals( | |
"java.util.HashMap$Values")) | |
return false; | |
// Fetch existing internal value and update it. | |
if (this.containsKey(key)) | |
valInternalUpdated = (AutoMap<K2, V2>) this.get(key); | |
// Add the (updated/ to add) internal value to the map. | |
valInternalUpdated.addNumericValue(keyInternal, valInternal); | |
this.put(key, (V) valInternalUpdated); | |
} catch (Exception e) { | |
// Not sucessful. | |
System.err.println("AutoMap.addMapToKey could not update: " | |
+ keyInternal + ", " + valInternal + "\n\t" + e.getMessage()); | |
return false; | |
} | |
return true; | |
} | |
/** | |
* Updates frequency of value's key in AutoMap (String, AutoMap (String, | |
* Double)) <BR> | |
* red,blue,yellow p1:20, p2:30, p3:5 | |
* | |
* @param key | |
* : e.g. red,blue,yellow | |
* @param value | |
* : e.g. p3:3 or p4:10 | |
* | |
*/ | |
public static void addKeyKeyNumericValue(String key, | |
AutoMap<String, AutoMap<String, Double>> map, String patternString, | |
double freqToAdd) { | |
AutoMap<String, Double> patternFreq = new AutoMap<String, Double>(); | |
if (map.containsKey(key)) | |
patternFreq = map.get(key); | |
patternFreq.addNumericValue(patternString, freqToAdd); // p3,100 | |
map.put(key, patternFreq); | |
} | |
/** | |
* Updates frequency of value's key in AutoMap (String, AutoMap (String, | |
* Double)) <BR> | |
* red,blue,yellow p1:20, p2:30, p3:5 | |
* | |
* @param key | |
* : e.g. red,blue,yellow | |
* @param value | |
* : e.g. p3:3 or p4:10 | |
* | |
*/ | |
public static <A, B> void addKeyKeyNumericValueGeneric(A key, | |
AutoMap<A, AutoMap<B, Double>> map, B patternString, double freqToAdd) { | |
AutoMap<B, Double> patternFreq = new AutoMap<>(); | |
if (map.containsKey(key)) | |
patternFreq = map.get(key); | |
patternFreq.addNumericValue(patternString, freqToAdd); // p3,100 | |
map.put(key, patternFreq); | |
} | |
public void addArrayValueNoRepeat(K key, Object value) { | |
if (value == null) | |
return; | |
V newList = (V) new ArrayList(); | |
if (this.containsKey(key)) | |
newList = this.get(key); | |
if (!((Collection) newList).contains(value)) | |
((Collection) newList).add(value); | |
this.put(key, newList); | |
} | |
public void addArrayValue(K key, Object value) { | |
if (value == null) | |
return; | |
V newList = (V) new ArrayList(); | |
if (this.containsKey(key)) | |
newList = this.get(key); | |
((Collection) newList).add(value); | |
this.put(key, newList); | |
} | |
public void addSetValue(K key, Object value) { | |
if (value == null) | |
return; | |
V newList = (V) new HashSet(); | |
if (this.containsKey(key)) { | |
newList = this.get(key); | |
} | |
((Collection) newList).add(value); | |
this.put(key, newList); | |
} | |
/* | |
* (non-Javadoc) | |
* | |
* @see java.util.AbstractMap#toString() | |
*/ | |
@Override | |
public String toString() { | |
return super.toString(); | |
} | |
public void put(String kv, String separator, int keyPosition) { | |
String[] parts = kv.split(separator); | |
if (parts.length == 2) | |
this.put((K) parts[keyPosition], (V) parts[parts.length - 1 | |
- keyPosition]); | |
} | |
public TreeMap<K, V> sortByValue() { | |
ValueComparator<K, V> sortByNumericVal = | |
new ValueComparator<K, V>(this); | |
TreeMap<K, V> sortedMap = new TreeMap<K, V>(sortByNumericVal); | |
sortedMap.putAll(this); | |
return sortedMap; | |
} | |
public Map<K, V> sortByValue(int topK) { | |
// A treemap would require another ValueComparator! | |
// thus, just add linkedhashmap that preserves order. | |
Map<K, V> topkM = new LinkedHashMap<>(); | |
for (java.util.Map.Entry<K, V> e : sortByValue().entrySet()) { | |
if (--topK >= 0) | |
topkM.put(e.getKey(), e.getValue()); | |
} | |
return topkM; | |
} | |
/** | |
* @description this method returns a cloned keyset so no changes are | |
* reflected in the original keyset e.g. in case of retainAll | |
* operation | |
* @return | |
* @date Dec 14, 2011 | |
* @author ntandon | |
*/ | |
public Set getClonedKeySet() { | |
Set clonedSet = new HashSet<K>(); | |
for (K key : this.keySet()) | |
clonedSet.add(key); | |
return clonedSet; | |
} | |
} | |
class ValueComparator<K, V> implements Comparator { | |
Map<K, V> base; | |
public ValueComparator(Map<K, V> base) { | |
this.base = base; | |
} | |
@Override | |
public int compare(Object a, Object b) { | |
// Imp Note: if you return 0 on compare, the map assumes this is | |
// duplicate key. | |
if (((Number) base.get(a)).doubleValue() <= ((Number) base.get(b)) | |
.doubleValue()) | |
return 1; | |
else | |
return -1; | |
} | |
} |