Does anyone know a double entry table implementation in Java I can download ?
I need to do something like this
1 2 3
_______
a| x y z
b| h l m
c| o a k
table.get(a,1) would return x
Of course, it should use any Object as key, value, etc
There are two basic approaches, depending on your needs.
One is to make a Hashtable (or similar) of Hashtables.
Hashtable<Integer, Hashtable<String, String>> = ...;
Another approach is to build your own datatype that represents an (Integer, String) pair, so you can do:
Hashtable<YourFancyDatatype, String>
The answer to your question partially lies in a previous questions on SO:
Java generics Pair<String, String> stored in HashMap not retrieving key->value properly
import java.lang.*;
import java.util.*;
public class Pair<TYPEA, TYPEB> implements Comparable< Pair<TYPEA, TYPEB> > {
protected final TYPEA Key_;
protected final TYPEB Value_;
public Pair(TYPEA key, TYPEB value) {
Key_ = key;
Value_ = value;
}
public TYPEA getKey() {
return Key_;
}
public TYPEB getValue() {
return Value_;
}
public String toString() {
System.out.println("in toString()");
StringBuffer buff = new StringBuffer();
buff.append("Key: ");
buff.append(Key_);
buff.append("\tValue: ");
buff.append(Value_);
return(buff.toString() );
}
public int compareTo( Pair<TYPEA, TYPEB> p1 ) {
System.out.println("in compareTo()");
if ( null != p1 ) {
if ( p1.equals(this) ) {
return 0;
} else if ( p1.hashCode() > this.hashCode() ) {
return 1;
} else if ( p1.hashCode() < this.hashCode() ) {
return -1;
}
}
return(-1);
}
public int hashCode() {
int hashCode = Key_.hashCode() + (31 * Value_.hashCode());
System.out.println("in hashCode() [" + Integer.toString(hashCode) + "]");
return(hashCode);
}
#Override
public boolean equals(Object o) {
System.out.println("in equals()");
if (o instanceof Pair) {
Pair<?, ?> p1 = (Pair<?, ?>) o;
if ( p1.Key_.equals( this.Key_ ) && p1.Value_.equals( this.Value_ ) ) {
return(true);
}
}
return(false);
}
public static void main(String [] args) {
HashMap< Pair<String, int>, String> table = new HashMap<Pair<String,int>, String>();
table.put(new Pair<String, int>("a", 1), "x");
table.put(new Pair<String, int>("a", 2), "y");
table.put(new Pair<String, int>("a", 3), "z");
table.put(new Pair<String, int>("b", 1), "h");
table.put(new Pair<String, int>("b", 2), "l");
table.put(new Pair<String, int>("b", 3), "m");
table.put(new Pair<String, int>("c", 1), "o");
table.put(new Pair<String, int>("c", 2), "a");
table.put(new Pair<String, int>("c", 3), "k");
String val = table.get(new Pair<String, int>("a", 1)); //val is x for this input pair
}
}
I'm assuming you have an array of characters/objects and a quantity and want cross each other in your table. You could map each character to a number between 0 .. qtyOfCharacters and simply create a bidimensional array Object[][] table = new Object[A][B], where A is the quantity of characters/object just mapped, and B is the quantity of columns.
To map the characters/object to numbers you should use a HashMap/HashTable.
The idea is that if you access the element at "a,3" you should write table[ charmap.get("a")][ 3]
Related
I'm trying to sort a HashMap<String, Long>. I'm have the following code for sorting:
private static class ValueComparator implements Comparator<String>{
HashMap<String, Long> map = new HashMap<String, Long>();
public ValueComparator(HashMap<String, Long> map){
this.map.putAll(map);
}
#Override
public int compare(String s1, String s2) {
if(map.get(s1) > map.get(s2)){
System.out.println("s1: " + s1 + "; s2: " + s2);
return -1;
}
else if (map.get(s1).equals(map.get(s2))) {
return 0;
}
else{
return 1;
}
}
}
private static TreeMap<String, Long> sortMapByValue(HashMap<String, Long> map){
Comparator<String> comparator = new ValueComparator(map);
//TreeMap is a map sorted by its keys.
//The comparator is used to sort the TreeMap by keys.
TreeMap<String, Long> result = new TreeMap<String, Long>(comparator);
result.putAll(map);
System.out.println("DONE sort");
return result;
}
The problem is, when several different keys have the same values, only one of the key makes it into the final map:
EXAMPLE:
public class Test {
public static void main(String[] args) {
HashMap<String, Long> hashMap = new HashMap<>();
hashMap.put("Cat", (long) 4);
hashMap.put("Human", (long) 2);
hashMap.put("Dog", (long) 4);
hashMap.put("Fish", (long) 0);
hashMap.put("Tree", (long) 1);
hashMap.put("Three-legged-human", (long) 3);
hashMap.put("Monkey", (long) 2);
System.out.println(hashMap); //7 pairs
System.out.println(sortMapByValue(hashMap)); //5 pairs
}
}
How would I fix it?
I don't think it's fixable you are using the the maps in an unintended way and breaking contracts. Tree map is expecting to be sorted by the key and the key is expected to be unique so when the compare == 0 it will just override the node's value. You can always implement your own TreeMap and make it do whatever you want it to.
I'm not sure what you want to do with it but I think you need something like
TreeMap<Long,List<String>>
http://hg.openjdk.java.net/jdk8/jdk8/jdk/file/687fd7c7986d/src/share/classes/java/util/TreeMap.java
if (cpr != null) {
do {
parent = t;
cmp = cpr.compare(key, t.key);
if (cmp < 0)
t = t.left;
else if (cmp > 0)
t = t.right;
else
return t.setValue(value);
} while (t != null);
How to sort a hash map based on values and if the values are same then the sorting should be on the key.
I tried to use a comparator, but its not giving expected results.
I want the result to be like this
{Bajaj=8.0, Tata=7.99, Maruthi=6.34, Kmart=5.99, Honda=5.78,
Adidas=4.99, Ford=3.99, Nike=3.99, Sears=3.99, Suzuki=3.99,
Apple=2.99, Puma=1.99}
Here's the complete source code:
import java.util.*;
public class Test {
public static void main(String[] args) {
HashMap<String, Double> map = new HashMap<String, Double>();
ValueComparator bvc = new ValueComparator(map);
TreeMap<String, Double> sorted_map = new TreeMap<String, Double>(bvc);
map.put("Adidas", 4.99);
map.put("Nike", 3.99);
map.put("Puma", 1.99);
map.put("Ford", 3.99);
map.put("Apple", 2.99);
map.put("Sears", 3.99);
map.put("Kmart", 5.99);
map.put("Tata", 7.99);
map.put("Maruthi", 6.34);
map.put("Honda", 5.78);
map.put("Bajaj", 8.0);
map.put("Suzuki", 3.99);
System.out.println("unsorted map: " + map);
sorted_map.putAll(map);
System.out.println("results: " + sorted_map);
}
}
class ValueComparator implements Comparator<String> {
Map<String, Double> base;
public ValueComparator(Map<String, Double> base) {
this.base = base;
}
// Note: this comparator imposes orderings that are inconsistent with
// equals.
#Override
public int compare(String a, String b) {
if (base.get(a) > base.get(b)) {
return -1;
} else if (base.get(a) == base.get(b)) {
System.out.println();
if (a.compareTo(b) == -1) {
return -1;
} else if (a.compareTo(b) == 1) {
return 1;
} else {
return 0;
}
} else {
return 1;
} // returning 0 would merge keys
}
}
Here you have two problems in your compare implementation. First, you compare boxed Double values with ==:
else if(base.get(a) == base.get(b))
You should replace this with
else if(base.get(a).equals(base.get(b)))
Second, you check a.compareTo(b) for specific values like -1 and 1, but it may return any positive/negative numbers. It's better and simpler just to return the result of a.compareTo(b) instead. Here's the fixed compare method:
public int compare(String a, String b) {
if (base.get(a) > base.get(b)) {
return -1;
} else if (base.get(a).equals(base.get(b))) {
return a.compareTo(b);
} else {
return 1;
} // returning 0 would merge keys
}
If you want to sort the keys with the same value in case-insensitive manner, just use compareToIgnoreCase:
public int compare(String a, String b) {
if (base.get(a) > base.get(b)) {
return -1;
} else if (base.get(a).equals(base.get(b))) {
return a.compareToIgnoreCase(b);
} else {
return 1;
} // returning 0 would merge keys
}
As the sorting order relies on both value and key, use the Map.Entry<String, Double> entries:
List<Map.Entry<String, Double>> entries = new ArrayList<>(base.entrySet());
Collections.sort(entries, new Comparator<Map<String, Double>>() {
...
});
Just little bit twisted your compare method of ValueComparator class. This will first sort on values & if values are same then sorting on keys. Hope this helps.
Output would be something like below:
unsorted map: {Adidas=4.99, Bajaj=8.0, Apple=2.99, Ford=3.99, Puma=1.99, Tata=7.99, Nike=3.99, Suzuki=3.99, Honda=5.78, Kmart=5.99, Maruthi=6.34, Sears=3.99}
results: {Bajaj=8.0, Tata=7.99, Maruthi=6.34, Kmart=5.99, Honda=5.78, Adidas=4.99, Ford=3.99, Nike=3.99, Sears=3.99, Suzuki=3.99, Apple=2.99, Puma=1.99}
import java.util.*;
public class SortValueMap {
public static void main(String[] args) {
HashMap<String, Double> map = new HashMap<String, Double>();
ValueComparator bvc = new ValueComparator(map);
TreeMap<String, Double> sorted_map = new TreeMap<String, Double>(bvc);
map.put("Adidas", 4.99);
map.put("Nike", 3.99);
map.put("Puma", 1.99);
map.put("Ford", 3.99);
map.put("Apple", 2.99);
map.put("Sears", 3.99);
map.put("Kmart", 5.99);
map.put("Tata", 7.99);
map.put("Maruthi", 6.34);
map.put("Honda", 5.78);
map.put("Bajaj", 8.0);
map.put("Suzuki", 3.99);
System.out.println("unsorted map: " + map);
sorted_map.putAll(map);
System.out.println("results: " + sorted_map);
}
}
class ValueComparator implements Comparator<String> {
Map<String, Double> base;
public ValueComparator(Map<String, Double> base) {
this.base = base;
}
// Note: this comparator imposes orderings that are inconsistent with
// equals.
#Override
public int compare(String a, String b) {
if(base.get(a).compareTo(base.get(b)) != 0) {
if (base.get(a) > base.get(b)) {
return -1;
} else {
return 1;
}
}
return a.compareTo(b);
}
}
I have a TreeMap in which I have stored some values. The map is sorted using the values, from highest to lowest. Now I want print out the contents of the TreeMap with their various indices.
If I have the following pairs in the map :
("Andrew", 10),
("John", 5),
("Don",9),
("Rolex", 30),
("Jack", 10),
("Dan",9)
I want to print out:
Rolex, 30 , 1
Jack, 10, 2
Andrew, 10, 2
Dan, 9, 4
Don, 9, 4
John, 5, 6.
This is what I've been trying but it doesn't seem to work well:
/**
*
* #author Andrew
*/
import java.util.*;
public class SortArray {
static <K,V extends Comparable<? super V>> SortedSet<Map.Entry<K,V>>entriesSortedByValues(Map<K,V> map) {
SortedSet<Map.Entry<K,V>> sortedEntries = new TreeSet<Map.Entry<K,V>>(
new Comparator<Map.Entry<K,V>>() {
#Override public int compare(Map.Entry<K,V> e1, Map.Entry<K,V> e2) {
int res = e1.getValue().compareTo(e2.getValue());
return res!= 0 ? res : 1;
//return e1.getValue().compareTo(e2.getValue());
}
});
sortedEntries.addAll(map.entrySet());
return sortedEntries;
}
public void test(){
Map mm = new TreeMap();
mm.put("Andrew", 11);
mm.put("Mbata", 21);
mm.put("Chinedu", 14);
mm.put("Bol", 14);
mm.put("Don", 51);
mm.put("Rolex", 16);
mm.put("Son", 41);
SortedSet newMap = entriesSortedByValues(mm);
Iterator iter = newMap.iterator();
int x = newMap.size();
List names = new ArrayList();
List scores = new ArrayList();
while(iter.hasNext()){
String details = iter.next().toString();
StringTokenizer st = new StringTokenizer(details, "=");
String name = st.nextToken();
names.add(name);
String score = st.nextToken();
scores.add(score);
//System.out.println(name + " Score:" +score + " Position:" + x);
x--;
}
Collections.reverse(names);
Collections.reverse(scores);
int pos = 1;
for(int i = 0; i<names.size();){
try{
int y = i+1;
if(scores.get(i).equals(scores.get(y))){
System.out.print("Name: "+ names.get(i)+"\t");
System.out.print("Score: "+ scores.get(i)+"\t");
System.out.println("Position: "+ String.valueOf(pos));
//pos++;
i++;
continue;
} else{
System.out.print("Name: "+ names.get(i)+"\t");
System.out.print("Score: "+ scores.get(i)+"\t");
System.out.println("Position: "+ String.valueOf(pos++));
}
i++;
} catch(IndexOutOfBoundsException e) {}
}
}
public SortArray(){
test();
}
public static void main(String [] args){
new SortArray();
}
}
First of all, Why are you catching that IndexOutOfBoundsException and doing nothing with it? if you run that you'll get that exception thrown (and I thing you already know it) the problem is in your algorithm inside the last "for" loop. I shouldn't give you the solution, but wth... at least you did some effort to make it run, so this is a more less working version:
import java.util.*;
public class SortArray {
static <K,V extends Comparable<? super V>> SortedSet<Map.Entry<K,V>>entriesSortedByValues(Map<K,V> map) {
SortedSet<Map.Entry<K,V>> sortedEntries = new TreeSet<Map.Entry<K,V>>(
new Comparator<Map.Entry<K,V>>() {
#Override public int compare(Map.Entry<K,V> e1, Map.Entry<K,V> e2) {
int res = e1.getValue().compareTo(e2.getValue());
return res != 0 ? res : 1;
//return e1.getValue().compareTo(e2.getValue());
}
});
sortedEntries.addAll(map.entrySet());
return sortedEntries;
}
public void test(){
Map mm = new TreeMap();
mm.put("Andrew", 11);
mm.put("Mbata", 21);
mm.put("Chinedu", 14);
mm.put("Bol", 14);
mm.put("Don", 51);
mm.put("Rolex", 16);
mm.put("Son", 41);
SortedSet newMap = entriesSortedByValues(mm);
Iterator iter = newMap.iterator();
int x = newMap.size();
List names = new ArrayList();
List scores = new ArrayList();
while(iter.hasNext()){
String details = iter.next().toString();
StringTokenizer st = new StringTokenizer(details, "=");
String name = st.nextToken();
names.add(name);
String score = st.nextToken();
scores.add(score);
//System.out.println(name + " Score:" +score + " Position:" + x);
x--;
}
Collections.reverse(names);
Collections.reverse(scores);
int pos;
int posBis = 0;
String lastScore = "";
for(int i = 0; i<names.size(); i++){
System.out.print("Name: "+ names.get(i)+"\t");
System.out.print("Score: "+ scores.get(i)+"\t");
if(i == 0 || !lastScore.equals(scores.get(i))) {
pos = i + 1;
posBis = pos;
} else {
pos = posBis;
}
System.out.println("Position: "+ String.valueOf(pos));
lastScore = (String)scores.get(i);
}
}
public SortArray(){
test();
}
public static void main(String [] args){
new SortArray();
}
}
Your SortedSet is the wrong way to go about this. You can see in your Comparator that it gets a bit messy when both values have to be looked up by the same key then you've got this messy (and incorrect) return res != 0 ? res : 1 (the 1 should really be e1.getKey().compareTo(e2.getKey()) rather than always returning 1).
A better way to go about this would be to just sort the keys yourself in a List, rather than creating a separate SortedSet. This way you don't have to worry about duplicate sorting values.
You can also abstract out the Comparator stuff a little, to make it more reusable in other code later, if you need it.
import java.util.*;
public class PrintSomething {
public static <T extends Comparable<T>> Comparator<T> reverseComparator(final Comparator<T> oldComparator) {
return new Comparator<T>() {
#Override
public int compare(T o1, T o2) {
return oldComparator.compare(o2, o1);
}
};
}
public static <K,V extends Comparable<V>> Comparator<K> keyedComparator(final Map<K,V> lookup) {
return new Comparator<K>() {
#Override
public int compare(K o1, K o2) {
return lookup.get(o1).compareTo(lookup.get(o2));
}
};
}
public static void main(String[] args) {
Map<String, Integer> mm = new HashMap<>();
mm.put("Andrew", 10);
mm.put("John", 5);
mm.put("Don", 9);
mm.put("Rolex", 30);
mm.put("Jack", 10);
mm.put("Dan", 9);
Comparator<String> comparator = reverseComparator(keyedComparator(mm));
List<String> keys = Arrays.asList(mm.keySet().toArray(new String[mm.size()]));
//Collections.sort(keys); // optional, if you want the names to be alphabetical
Collections.sort(keys, comparator);
int rank = 1, count = 0;
Integer lastVal = null;
for (String key : keys) {
if (mm.get(key).equals(lastVal)) {
count++;
} else {
rank += count;
count = 1;
}
lastVal = mm.get(key);
System.out.println(key + ", " + mm.get(key) + ", " + rank);
}
}
}
In general things like SortedSet make more sense when you need to keep the data itself sorted. When you just need to process something in a sorted manner one time they're usually more trouble than they're worth. (Also: is there any reason why you're using a TreeMap? TreeMaps sort their keys, but not by value, so in this case you're not taking advantage of that sorting. Using a HashMap is more common in that case.)
You do a lot of work with the iterator, calling toString(), then splitting the results. And your Comparator is extra work too. Stay with a Map on both sides - you can use keys() and values() more directly, and let Java do the sorting for you. Most of your above code can be replaced with: (for clarity, I changed your name "mm" to "originalMap")
Map<Integer, String> inverseMap = new TreeMap<Integer, String>();
for (Map.Entry<String, Integer> entry : originalMap.entrySet()) {
inverseMap.put(entry.getValue(), entry.getKey());
}
Now, iterate over inverseMap to print the results. Note that if a count does exist twice in originalMap, only one will be printed, which is what you want. But which one gets printed left as an exercise for the reader :-). You might want to be more specific on that.
EDIT ADDED: If you do want to print out duplicate scores, this is not what you want. The original post I read said to skip if they were the same, but I don't see that after the edits, so I'm not sure if this is what OP wants.
import java.util.*;
public class Sort {
static class ValueComparator implements Comparator<String> {
Map<String, Integer> base;
ValueComparator(Map<String, Integer> base) {
this.base = base;
}
#Override
public int compare(String a, String b) {
if (base.get(a) >= base.get(b)) {
return 1;
} else {
return -1;
}
}
}
public static void main(String[] args) {
HashMap<String, Integer> map = new HashMap<String, Integer>();
ValueComparator vc = new ValueComparator(map);
TreeMap<String, Integer> sorted = new TreeMap<String, Integer>(vc);
map.put("A", 1);
map.put("B", 2);
sorted.putAll(map);
for (String key : sorted.keySet()) {
System.out.println(key + " : " + sorted.get(key)); // why null values here?
}
System.out.println(sorted.values()); // But we do have non-null values here!
}
}
Output:
A : null
B : null
[1, 2]
BUILD SUCCESSFUL (total time: 0 seconds)
I wonder why we get null values at the first commented line while we do have non-null values as demonstrated by the second commented line.
Edit: #null's version seems not working. I've changed my code as follows:
public int compare(String a, String b) {
if (a.equals(b)) return 0;
if (base.get(a) >= base.get(b)) {
return 1;
} else return -1;
}
It seems to work but I'm not sure.
My guess is that your ValueComparator.compare() method never returns 0, indicating equality, causing the Map.get() method to not find matches.
Change your compare to in this way
public int compare(String a, String b) {
if (base.get(a) > base.get(b)) {
return 1;
}else if(base.get(a) == base.get(b)){
return 0;
}
return -1;
}
Even with your Comparator which is definitely broken the program will work if you change it as
for (Map.Entry e : sorted.entrySet()) {
System.out.println(e.getKey() + " : " + e.getValue());
}
I have a hashmap of objects. Each object has two attributes (let say int length and int weight).
I want to remove k elements with the smallest length.
What is the efficient way of doing this?
Map<K, V> map = new HashMap<>();
...
Set<K> keys = map.keySet();
TreeSet<K> smallest = new TreeSet<>(new Comparator<K>(){
public int compare(K o1, K o2) {
return o1.getLength() - o2.getLength();
}
});
smallest.addAll(keys);
for(int x = 0; x < num; x++) {
keys.remove(smallest.pollFirst());
}
Where K is your key type, V is your value type, and num is the number of elements you wish to remove.
If you are doing this frequently, it might be a good idea to use a TreeMap in the first place.
The easiest, but certainly not the most efficient is to create an instance of a TreeMap with provided Comparator for your type, putAll() elements from your map to the map you just created and remove k-elements with help of keySet(). In the end a TreeMap will not contain k-smallest elements.
You didn't mention if the attribute you discriminate on is part of the key or the value, if it's the key then teh treemap discussed above is applicbale.
Otherwise If you need to do this often I'd be inclined to implement my own map, delegating everything in the map interface to a hashmap (or appropriate structure0. Override the add/remove and if necessary iterator, then use the add/remove to maintain a sorted list of the values.
This obviously assumes the values don't change and is highly coupled to your problem.
Keep in mind that TreeMap sorts by the natural ordering of its keys. Hence you can create a key with comparable based on the length of it's value. For example (Since I am on Lunch the code isn't perfect but should get you to what you need):
package com.trip.test;
import java.util.SortedMap;
import java.util.TreeMap;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class ComparisonTest {
private static Logger logger = LoggerFactory.getLogger(ComparisonTest.class);
private static String[] a = {"1","2","3","4"};
private static String[] b = {"A","B","D"};
private static String[] c = {"1","B","D","1","B","D"};
/**
* #param args
*/
static SortedMap<KeyWithLength, String[]> myMap = new TreeMap<KeyWithLength, String[]>();
static {
myMap.put(new KeyWithLength("a", a.length), a);
myMap.put(new KeyWithLength("b", b.length), b);
myMap.put(new KeyWithLength("c", c.length), c);
}
public static void main(String[] args) {
// print Map
logger.info("Original Map:");
int i = 0;
for (String[] strArray: myMap.values() ){
logger.info(String.format("*** Entry %s: ", i++));
printStrings(strArray);
}
// chop off 2 shortest
chopNShortest(myMap, 2);
// print Map
logger.info("ShortenedMap:");
i = 0;
for (String[] strArray: myMap.values() ){
logger.info(String.format("*** Entry %s: ", i++));
printStrings(strArray);
}
}
static void printStrings(String[] strArray){
StringBuffer buf = new StringBuffer();
for (String str: strArray){
buf.append(String.format("%s, ", str));
}
logger.info(buf.toString());
}
static void chopNShortest(SortedMap<KeyWithLength, String[]> sortedMap, int n) {
// Assuming map is not unmodifiable
if (n <= sortedMap.size()-1){
for (int i = 0; i< n;i++){
sortedMap.remove(sortedMap.firstKey());
}
}
}
}
class KeyWithLength implements Comparable<KeyWithLength> {
private String key;
private Integer length;
public KeyWithLength(String key, int length) {
super();
this.key = key;
this.length = length;
}
public String getKey() {
return key;
}
public int getLength() {
return length;
}
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((key == null) ? 0 : key.hashCode());
return result;
}
#Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
KeyWithLength other = (KeyWithLength) obj;
if (key == null) {
if (other.key != null)
return false;
} else if (!key.equals(other.key))
return false;
return true;
}
#Override
public int compareTo(KeyWithLength another) {
// TODO Auto-generated method stub
return compare(this.length, another.length);
}
public static int compare(int x, int y) {
return (x < y) ? -1 : ((x == y) ? 0 : 1);
}
}
The output:
Original Map:
*** Entry 0:
A, B, D,
*** Entry 1:
1, 2, 3, 4,
*** Entry 2:
1, B, D, 1, B, D,
ShortenedMap:
*** Entry 0:
1, B, D, 1, B, D,