How to sort a key of a map - java

How to sort (any kind of sorting) a key of a map(treemap or hashmap)
i have a problem and it goes like this.
i have a map that has a key of
27527-683,
27525-1179,
27525-1571,
27525-1813,
27525-4911,
27526-1303,
27526-3641,
27525-3989,
27525-4083,
27525-4670,
27526-4102,
27526-558,
27527-2411,
27527-4342
this is the list of keys and the value for each of the key is a list.
now, how can i sort this key in ascending order by number.
ex. if i want to sort : 1,2,11,20,31,3,10
i want to have as output is : 1,2,3,10,11,20,31
but when i use the autosort of treemap the output goes : 1,10,11,2,20,3,31
how can i sort it in ascending order by numeric?
please help me. i can't think of anymore ways because this is my first time handling map and list

Your keys are Strings. The natural ordering of strings is lexicographical. You either need to specify a custom comparator in the constructor of the TreeMap, or use an Integer key.
Furthermore, you can better represent a Map<Key, List<Value>> as a Google Guava Multimap, see for example SortedSetMultimap.
Continuing with the Guava example:
Multimap<Integer, Person> multimap = SortedSetMultimap.create(Ordering.natural(), Ordering.arbitrary());
multimap.put(1, x);
multimap.put(1, y);
multimap.put(2, z);
multimap.put(1, a);
Then
multimap.get(1) will return a set containing [x, y, a] in some arbitrary order.
multimap.keys() will return a sorted set of [1, 2].

Your keys are currently Strings, that you would appear to rather handle like Integers. You will need to reformulate how you handle the map object, as many people here have suggested (it may be the correct method). An easier method involves using that list of keys you have copied us in on.
I see there is a way to output the list of keys. Sort that however you like. Arrays and lists are easily sorted by built in commands from your runtime environment. You might have to first split those elements at the hyphen.
I'd recommend a book on Data Structures.

Use SortedMap, for example, java.util.TreeMap.

keyword : SortedMap
SortedMap<Integer, Integer> s = new TreeMap<Integer, Integer>();
s.put(1, 1);
s.put(4, 2);
s.put(2, 3);
System.out.println(s); //{1=1, 2=3, 4=2}
also look at this example

Related

Java TreeSet<Pair<Integer, Integer>> sorted by the value of the Pair element, how to insert a new pair that has the same value as an existing pair?

I currently have a TreeSet that contains elements of type Pair, and I'm sorting them by their value in descending order.
Here is the link to the original Pair class documentation: https://docs.oracle.com/javase/9/docs/api/javafx/util/Pair.html
This is the declaration:
TreeSet<Pair<Integer, Integer>> sortedSet = new TreeSet<Pair<Integer, Integer>>((a,b) -> b.getValue() - a.getValue());
My issue is that if I try to insert a few pairs into the set, for example: Pair(4, 51), Pair(8, 85), Pair(1, 16), Pair(2,51), the Pair(2,51) doesn't get inserted.
Code for inserting the pairs:
sortedSet.add(new Pair<Integer, Integer>(4, 51));
sortedSet.add(new Pair<Integer, Integer>(8, 85));
sortedSet.add(new Pair<Integer, Integer>(1, 16));
sortedSet.add(new Pair<Integer, Integer>(2, 51));
I managed to figure out that the reason is because there already exists a pair element with the same value - P(4,51), however, they have different keys so they are different elements, and I expected the Pair(2,51) to be inserted before or after P(4,51).
Is there a way I can solve this issue?
The issue is caused by the definition of the Comparator:
(a,b) -> b.getValue() - a.getValue()
According to this Comparator, two Pairs with the same value are "equal". As to the contract of Set, this means that an add(...) adds an element to the Set if and only if no element that is "equal" (with respect to the Comparator) exists in the Set.
If we want to store two Pairs with the same value, but different keys, we need to extend the Comparator, such that it returns a non-0 value for Pairs with equal value, but different keys.
One possibility is to:
first sort by value (descending - as in the original code), and
then by key (either ascending or descending)
The following code accomplishes exactly this. The .reversed() is for the descending sort order for value, and I chose an ascending sort order for key:
final TreeSet<Pair<Integer, Integer>> sortedSet = new TreeSet<>(Comparator
.comparingInt(Pair<Integer, Integer>::getValue).reversed()
.thenComparing(Pair::getKey));
Ideone demo
A Set can not contain duplicates. Instead, you may want to use a List and use Collections.sort() on it after you're done inserting.

Anyway to have two of the same keys, but different values in Java HashMap?

I'm using a HashMap to contain a misspelled word, and a int array that contains its offset in the document, the line number it is on, and the length of that misspelled word. By default, HashMap replaces the old values if the key is already contained. I would like to keep those values, and have duplicate keys.
Is there anyway to accomplish this?
You CANNOT have duplicate keys in Map but you can create a MultiMap i.e A map to associate a single key with multiple values. Something like this:
Map<String,ArrayList<String>> myMap = new HashMap<String,ArrayList<String>>();
or you can use readymade multi-map implementations such as:
Apache MultiMap
Guava MultiMap
No, a HashMap is always uniquely keyed. If you need aap that a key can have multiple values, look at Guava's MultiMap

Google Guava TreeMultimap -- retrieve values based on sorted ordering?

I'm trying to implement something that requires sorting of values of a <Destination -> Quantity> map, such as:
<San Francisco -> 10, Seattle -> 20, LA -> 10}
The values are not necessarily distinct. I want to be able to retrieve the key/value pair with the largest and smallest value, similar to what a TreeMap is able to do with keys.
I found Google Guava's TreeMultimap, which is an implementation of Multimap whose keys and values are ordered by their natural ordering or by supplied comparators. The thing is, TreeMultimap doesn't seem to have any methods that let me retrieve key/value pairs based on the ordering of the keys or values, (like what pollFirstEntry(), for instance, does in TreeMap).
To this extent, I'm a little confused on how to make a TreeMultimap obtain this functionality. I feel like it should work, maybe it's just a matter of how I instantiate the object?
TreeMultimap isn't going to support this in quite the way you're looking for, I'm fairly certain.
What you could do is a TreeMultimap<Integer, String> -- swapping the role of the keys and the values -- and then TreeMultimap.asMap().lastEntry() would get you a Map.Entry<Integer, Collection<String>>, corresponding to the greatest Integer and all the Strings associated with it.
The one thing definitely not supported by TreeMultimap is looking at the combined values for all keys as a single sorted collection. (You can look at them as an unsorted collection with values(), of course.)
It's true that TreeMultimap does order values according to a value comparator, but that ordering is only relevant in relation to other values mapped to the same key. So, for example, if you had
a => 3
a => 1
b => 4
b => 2
And you iterated through the entries(), you should get [(a, 1), (a, 3), (b, 2), (b, 4)]. Similarly if you iterated through the values(), you should get [1, 3, 2, 4] as it returns the values of a in order, then the values of b in order.
Getting the first or last key is simple though, as keySet() returns a NavigableSet, meaning you can call first() and last() on it.

How to iterate over Multimap in insertion order?

Using the new collections from Google's Guava, http://code.google.com/p/guava-libraries/wiki/NewCollectionTypesExplained
How do I loop over a MultiMap for each key in the order of insertion?
For example
multimap = new HashMultiMap<String,String>();
multimap.put("1", "value1");
multimap.put("1", "value2");
multimap.put("1", "value3");
multimap.put("2", "value11");
multimap.put("2", "value22");
multimap.put("2", "value33");
multimap.put("3", "value111");
multimap.put("3", "value222");
multimap.put("3", "value333");
On each loop I need
"value1", "value11", "value111";
then the next loop
"value2", "value22", "value222";
and so on:
"value3", "value33", "value333";
I'm not quite sure what are your needs (or concrete use case), but I'll try to guess. Other answers suggest using Linked*Multimap or Immutable one, but to get desired output (shown in question) with Multimap you will have to create some fancy Map (I'll discuss this later) or for example create three temporary collections holding first, second and third values for each key (they will be in insertion order, if you use one of suggested Multimap implementations). Preferably it would be one of ListMultimaps as you can iterate over multimap.keySet() to get lists with values available by index:
final ListMultimap<String,String> multimap = LinkedListMultimap.create();
// put values from question here
final List<Object> firstValues = Lists.newArrayList();
for (final String key: multimap.keySet()) {
firstValues.add(multimap.get(key).get(0));
}
System.out.println(firstValues);
// prints [value1, value11, value111]
// similar for multimap.get(key).get(1) and so on
but the downside is that you'll have to create three Lists for you example what makes this solution rather unflexible. So maybe it'll be better to put {first,second,third}Values collection to Map>, what brings me to the point:
Maybe you should use Table instead?
Table is designed as A collection that associates an ordered pair of keys, called a row key and a column key, with a single value and, what's more important here, has row and column views. I'll use ArrayTable here:
final ArrayTable<String, Integer, Object> table = ArrayTable.create(
ImmutableList.of("1", "2", "3"), ImmutableList.of(0, 1, 2));
table.put("1", 0, "value1");
table.put("1", 1, "value2");
table.put("1", 2, "value3");
table.put("2", 0, "value11");
table.put("2", 1, "value22");
table.put("2", 2, "value33");
table.put("3", 0, "value111");
table.put("3", 1, "value222");
table.put("3", 2, "value333");
for (final Integer columnKey : table.columnKeyList()) {
System.out.println(table.column(columnKey).values());
}
// prints:
// [value1, value11, value111]
// [value2, value22, value222]
// [value3, value33, value333]
I deliberately used String for row keys which are [1, 2, 3, ...] Integers in fact (like you did in the question) and Integers for column keys starting with 0 ([0, 1, 2, ...]) to show similarity to previous example using List's get(int) on multimaps values' collection.
Hope this will be helpful, mostly in determining what you want ;)
P.S. I use ArrayTable here, because it has neater way of creating fixed set (universe) of rows / keys values than ImmutableTable, but if mutability isn't required you should use it instead with one change - ImmutableTable (and any other Table implementation) doesn't have columnKeyList() method, but only columnKeySet() which does the same thing, but is slower for ArrayTable. And of course ImmutableTable.Builder or ImmutableTable.copyOf(Table) should be used.
You can use either LinkedListMultimap or LinkedHashMultimap.
The two have very similar behavior; one major difference is that LinkedListMultimap allows multiple copies of the same key-value pair to be inserted, whereas LinkedHashMultimap allows only one.
See the above-linked Javadoc for much more information.
I'm not entirely clear what iteration order you mean, OP...
Set<K> keySet() just returns the keys.
Map<K, Collection<V>> asMap() returns the keys and their associated entries, so you might do for (Map.Entry<K, Collection<V>> entry : asMap().entrySet()) to iterate over keys and their associated collections.
Collection<Map.Entry<K, V>> entries() lets you iterate over the entries, but without necessarily grouping them by key.
If you want things in insertion order, use one of the insertion-ordered Multimap implementations -- LinkedHashMultimap, possibly LinkedListMultimap, ImmutableMultimap.
For looping over multiple keys:
for (Object key : multimap.keys()) { ... }
You can also loop over the entries:
for (Map.Entry entry : multimap.entries()) { ... }

nth item of hashmap

HashMap selections = new HashMap<Integer, Float>();
How can i get the Integer key of the 3rd smaller value of Float in all HashMap?
Edit
im using the HashMap for this
for (InflatedRunner runner : prices.getRunners()) {
for (InflatedMarketPrices.InflatedPrice price : runner.getLayPrices()) {
if (price.getDepth() == 1) {
selections.put(new Integer(runner.getSelectionId()), new Float(price.getPrice()));
}
}
}
i need the runner of the 3rd smaller price with depth 1
maybe i should implement this in another way?
Michael Mrozek nails it with his question if you're using HashMap right: this is highly atypical scenario for HashMap. That said, you can do something like this:
get the Set<Map.Entry<K,V>> from the HashMap<K,V>.entrySet().
addAll to List<Map.Entry<K,V>>
Collections.sort the list with a custom Comparator<Map.Entry<K,V>> that sorts based on V.
If you just need the 3rd Map.Entry<K,V> only, then a O(N) selection algorithm may suffice.
//after edit
It looks like selection should really be a SortedMap<Float, InflatedRunner>. You should look at java.util.TreeMap.
Here's an example of how TreeMap can be used to get the 3rd lowest key:
TreeMap<Integer,String> map = new TreeMap<Integer,String>();
map.put(33, "Three");
map.put(44, "Four");
map.put(11, "One");
map.put(22, "Two");
int thirdKey = map.higherKey(map.higherKey(map.firstKey()));
System.out.println(thirdKey); // prints "33"
Also note how I take advantage of Java's auto-boxing/unboxing feature between int and Integer. I noticed that you used new Integer and new Float in your original code; this is unnecessary.
//another edit
It should be noted that if you have multiple InflatedRunner with the same price, only one will be kept. If this is a problem, and you want to keep all runners, then you can do one of a few things:
If you really need a multi-map (one key can map to multiple values), then you can:
have TreeMap<Float,Set<InflatedRunner>>
Use MultiMap from Google Collections
If you don't need the map functionality, then just have a List<RunnerPricePair> (sorry, I'm not familiar with the domain to name it appropriately), where RunnerPricePair implements Comparable<RunnerPricePair> that compares on prices. You can just add all the pairs to the list, then either:
Collections.sort the list and get the 3rd pair
Use O(N) selection algorithm
Are you sure you're using hashmaps right? They're used to quickly lookup a value given a key; it's highly unusual to sort the values and then try to find a corresponding key. If anything, you should be mapping the float to the int, so you could at least sort the float keys and get the integer value of the third smallest that way
You have to do it in steps:
Get the Collection<V> of values from the Map
Sort the values
Choose the index of the nth smallest
Think about how you want to handle ties.
You could do it with the google collections BiMap, assuming that the Floats are unique.
If you regularly need to get the key of the nth item, consider:
using a TreeMap, which efficiently keeps keys in sorted order
then using a double map (i.e. one TreeMap mapping integer > float, the other mapping float > integer)
You have to weigh up the inelegance and potential risk of bugs from needing to maintain two maps with the scalability benefit of having a structure that efficiently keeps the keys in order.
You may need to think about two keys mapping to the same float...
P.S. Forgot to mention: if this is an occasional function, and you just need to find the nth largest item of a large number of items, you could consider implementing a selection algorithm (effectively, you do a sort, but don't actually bother sorting subparts of the list that you realise you don't need to sort because their order makes no difference to the position of the item you're looking for).

Categories

Resources