Maintain SortedMap by value - java

As we know that, SortedMap maintains the entries as sorted by keys. I read many threads in this forum and saw lots of example which sorts the SortedMap, by values. However, as you know when I put an item to default SortedMap it does not sort the Map again just put this new entry where it is supposed to be.
For example,
SortedMap<String,Person> sortedMap = new TreeMap();
Person p1 = new Person("John",38);
sortedMap.put(p1.getName(), p1);
Person p2 = new Person("Tom",34);
sortedMap.put(p2.getName(), p2); // does not sort, maintains sorted set by comparing the other values
Person p3 = new Person("Susan",21);
sortedMap.put(p3.getName(), p3); // does not sort, maintains sorted set by comparing the other values
In many threads in this forum, I saw many many code that sorts the SortedMap by values by calling a sort method like:
sortedMap.sort(sortedMap.entries());
This or something else method is being called to get values as sorted.
But, I need to a Map implementation which keeps the values as sorted without a calling sort method as I explained in above. For example, in above code I just can call the firstKey() method; but instead I need to call a firstValue() method.
Person minimumAgePerson = sortedMap.firstValue().
System.out.println(minimumAgePerson.getName()); // it should print "Susan"
SortedSet is not appropriate for my requiremenets because I can put some new Objects ( Person ) whose key values already in the map, these just added entries should override the existing objects ( so I need a map ):
Person p4 = new Person("Susan",39);
sortedMap.put(p4.getName(),p4);
Person newMinimumAgePerson = sortedMap.firstValue();
System.out.println(newMinimumAgePerson.getName()); // it should print "Tom"
Is there an implementation to accomplish this taks or do I need to implement SortedSet myself?

Often, the simplest and safest way of dealing with this type of problem is to write a class that uses two different standard collections. The class can offer exactly the methods you need, not necessarily conforming to any of the java.util interfaces.
Given the stated requirements, I would use a SortedMap to contain the values, combined with a HashMap mapping keys to values. To prevent duplicate keys, put the key-value pair in the HashMap, checking the put result. If the key was already present, remove the old value from the SortedMap before adding the new value.
If you have additional requirements, this particular design may not cover everything, but the concept of combining java.util structures is a generally useful one.

I think the best way for you is to create a custom type containing both a Map (for the key association), and a SortedSet (in order to sort values)
It is not clear to me if you want to be able to have the same value for two different keys. In this case, you'd need to use some kind of SortedMultiSet.

There is no implementation that contains a sort by both Key and Value. But really any implementation that did do this would need a separate datastructure for the sorting by value anyway, so you might as well create that datastructure yourself.
I would suggest either just implementing a sorted structure, using an existing one Like TreeMap or a PriorityQueue depending on your needs. Once that was done I would probably extend TreeMap with a custom structure and override the put,remove,addAll, etc methods to place it both in the super map, and also in your sort by keys structure.

Related

How to avoid duplicate strings in Java?

I want to be able to add specific words from a text into a vector. Now the problem is I want to avoid adding duplicate strings. The first thing that comes to my mind is to compare all strings before adding them, as the amount of entries grow, this becomes really inefficient solution. The only "time efficient" solution that I can think of is unordered_multimap container that has included in C++11. I couldn't find a Java equivalent of it. I was thinking to add strings to the map and at the end just copying all entries to the vector, in that way it would be a lot more efficient than the first solution. Now I wonder whether there is any Java library that does what I want? If not is there any C++ unordered_multimap container equivalent in Java that I couldn't find?
You can use a Set<String> Collection. It does not allow duplicates. You can choose then as implementantion:
1) HashSet if you do not care about the order of elements (Strings).
2) LinkedHashSet if you want to keep the elements in the inserting order.
3) TreeSet if you want the elements to be sorted.
For example:
Set<String> mySet = new TreeSet<String>();
mySet.add("a_String");
...
Vector is "old-fashioned" in Java. You had better avoid it.
You can use a set (java.util.Set):
Set<String> i_dont_allow_duplicates = new HashSet<String>();
i_dont_allow_duplicates.add(my_string);
i_dont_allow_duplicates.add(my_string); // wont add 'my_string' this time.
HashSet will do the job most effeciently and if you want to keep insertion order then you can use LinkedHashSet.
Use a Set. A HashSet will do fine if you do not need to preserve order. A LinkedHashSet works if you need that.
You should consider using a Set:
A collection that contains no duplicate elements. More formally, sets
contain no pair of elements e1 and e2 such that e1.equals(e2), and at
most one null element. As implied by its name, this interface models
the mathematical set abstraction.
HashSet should be good for your use:
HashSet class implements the Set interface, backed by a hash table
(actually a HashMap instance). It makes no guarantees as to the
iteration order of the set; in particular, it does not guarantee that
the order will remain constant over time. This class permits the null
element.
So simply define a Set like this and use it appropriately:
Set<String> myStringSet = new HashSet<String>();
Set<String> set = new HashSet<String>();
The general contract of hashCode is:
Whenever it is invoked on the same object more than once during an execution of a Java application, the hashCode method must consistently return the same integer, provided no information used in equals comparisons on the object is modified.
This integer need not remain consistent from one execution of an application to another execution of the same application.
If two objects are equal according to the equals(Object) method, then calling the hashCode method on each of the two objects must produce the same integer result.
It is not required that if two objects are unequal according to the equals(java.lang.Object) method, then calling the hashCode method on each of the two objects must produce distinct integer results. However, the programmer should be aware that producing distinct integer results for unequal objects may improve the performance of hashtables.

Are there any map implementations in Java that will give me a map where the entries are ordered in the same way I put them in?

What I would like to do is this:
for (Entry<Foo, Foo> myEntry : myMap.entryList())
{
if (someCondition(myEntry.getKey()))
{
doSomething(myEntry.getValue())
}
}
The order is important because myEntry.getValue() will point to a key that will be reached later on. Is there a Map implementation that guarantees the order of the entries and allows me to iterate over the entries in that order? I found SortedMap, but it looks like SortedMaps sort the keys. This isn't quite what I need. I simply want to get my entries out of my map in the same order that I put them in.
For those wondering what I'm trying to do, myMap represents a hierarchy of Foo objects. When the condition is met in 'someCondition', I mark the parent of the Foo (which happens to be the value of the entry). Later on when the parent becomes a key, I'll know that I've marked it before and will take action accordingly. Right now I've created a recursive 'markParent' call, but if I could iterate over the map in a known order, I wouldn't need to do that.
You mean like LinkedHashMap? ;-)
Hash table and linked list implementation of the Map interface, with predictable iteration order. This implementation differs from HashMap in that it maintains a doubly-linked list running through all of its entries. This linked list defines the iteration ordering, which is normally the order in which keys were inserted into the map (insertion-order). Note that insertion order is not affected if a key is re-inserted into the map. (A key k is reinserted into a map m if m.put(k, v) is invoked when m.containsKey(k) would return true immediately prior to the invocation.)
(My emphasis)
FWIW, how I got there, to help if you need to find similar information in the future: I had a vague recollection one of the JDK classes did that, so went to Map and read through the list of "Known Implementing Classes." In this case, I knew the name when I saw it, but I figure even if I hadn't known it, LinkedHashMap suggests order, so... :-)
LinkedHashMap will maintain the order of insertion which using LinkedList internally. And if you want to define any custom order, you can use SortedMap like TreeMap instead.

How do you declare a TreeMap - SortedMap or Map?

I have written some code that works fine but I am confused about the correct way to declare a TreeMap.
If SortedMap is a subinterface of Map then is it okay to just use Map if the code is working okay? Is SortedMap even necessary if TreeMap works fine with Map?
Should it be:
private Map<String, List <Bus>> map = new TreeMap<String, List <Bus>>();
or
private SortedMap<String, List <Bus>> map = new TreeMap<String, List <Bus>>();
Thanks.
Sorry this is so basic - I am new to Java.
I've used SortedMap to inform others that it is already sorted. Using Map is OK too.
private Map<String, List <Bus>> busTimetable = new TreeMap<String, List <Bus>>();
Unless you have a good reason, always use the highest level interface you can.
The answer to your question depends on your usage. By default, you should simply program to the data type's interface (i.e. Map). If SortedMap provides methods that you will be using that aren't declared in Map, then program to SortedMap.
If you need to use specific SortedMap methods (like firstKey()/lastKey()/whatever...), it is mandatory to declare your reference as SortedMap. Otherwise, Map is the one I'd choose, if I'm only planning on using it as a Map, so I'll be able so switch implementations without any other change in the code.
I agree with other commenters that you use SortedMap if you use methods that aren't in vanilla Map. Also use SortedMap if you have use in an iterator or a for-each loop if they implicitly rely on sorted input.
If neither of these cases are true, you should also think about if you only need a vanilla Map, a HashMap may be a better choice. HashMap has O(1) access; TreeMap does not.
It depends upon your requirement and design whenever possible use the highest level of abstraction that is Map. The reason is say you are creating a service and it consume list of data and produce an output in a Map.
some client may expect for sorted order of the data in the map and some other client may just need the data in the insertion order of the map if you use a specific interface SortedMap ; this kind of scenarion you can not handle using one service and you will end up creating two different api becuase one who is expecting sorted order you can just return an implementaion of TreeMap and one for insertion order you can use LinkedHashMap. So it's about how flexible is your program.

Built-In way to store Pre-Sorted Key-Value Pairs in Java?

I'm looking for a way to maintain the sorting on my key-value pairs. They are sorted by variables outside of the actual key-value pairs (for better UI). I am currently using a Hashtable, but that does not maintain the sorting =(
Hashtable<Integer, String> subscriptions = getUsersSubscriptions(user);
Is there some simple way that Java lets one store pairs? The best idea I can think of is using 2 associated ArrayLists (one of type Integer, another of type String). Can someone think of something better?
If your key-value pairs are already sorted, LinkedHashMap will maintain order of insertion.
In other words, the keys returned by map.keySet() will be in the exact order you put them into the map.
SortedMap<Integer, String> myMap = new TreeMap<Integer,String>();
If you have a custom sorting, pass a Comparator instance to the constructor of the TreeMap. But be careful doing so, as using a Comparator that does not go well with natural Integer order would make things impossible to understand and debug.
LinkedHashMap can be used here.
Is there some simple way that Java lets one store pairs?
Create a custom class that stores the two properties.
They are sorted by variables outside of the actual key-value pairs
Add a third property for the sort data.
Then your class can implement Comparable to sort the data as required based on this property.
Or you can use a custom Comparator to sort on the sort data field.
Now the class instances can be stored in an ArrayList.

Java Map question

I have one Map that contains some names and numbers
Map<String,Integer> abc = new HashMap<String,Integer>();
It works fine. I can put some values in it but when I call it in different class it gives me wrong order. For example:
I putted
abc.put("a",1);
abc.put("b",5);
abc.put("c",3);
Iterator<String> iter = abc.keySet().iterator();
while (iter.hasNext()) {
String name = iter.next();
System.out.println(name);
}
some time it returns the order (b,a,c) and some time (a,c,b).
What is wrong with it? Is there any step that I am missing when I call this map?
Edit:
I changed to HashMap and result is still same
The only thing that's wrong is your expectations. The Map interface makes no guarantees about iteration order, and the HashMap implementation is based on hash functions which means the iteration order is basically random, and will sometimes change completely when new elements are added.
If you want a specific iteration order, you have thee options:
The SortedMap interfaces with its TreeMap implementation - these guarantee an iteration order according to the natural ordering of the keys (or an ordering imposed by a Comparator instance)
The LinkedHashMap class iterates in the order the elements were added to the map.
Use a List instead of a Map - this has a well-defined iteration order that you can influence in detail.
I think you need LinkedHashMap.
A TreeMap will always have keys in their natural order (unless you provide a comparator) If you are seeing the order any differently it will be the way you are looking at the map and what you are doing with it. If in doubt, use a debugger and you will see the order is sorted.
If you wish to get map values in the same order you used to insert them use LinkedHashMap instead.

Categories

Resources