sort a map that contains an array of objects - java

if i make a map like this:
Map<Object, ArrayList<Object>> multiMap = new HashMap<Object, ArrayList<Object>>();
is there a way for me to sort on the values in the ArrayList<Object>?
i was thinking of just looping through the multimap as such:
for (Entry<Object, ArrayList<Object>> entry : multiMap.entrySet()) {
for (int i = 0; i < entry.size(); i++) {
//retrieve all array items and place in new array to sort
}
so we have
object ---> arrayList (contains 2 elements)
object ---> arrayList (contains 2 elements)
object ---> arrayList (contains 2 elements)
object ---> arrayList (contains 2 elements)
i want to take all the elements in all of the arrayLists above and sort by those. it doesn't need to stay in the multimap.. i was just looking to see if there was a better way to do it..
EDIT:
the point here is to sort all the array elements in every arrayList against all the other array elements in every other arrayList.... so it's not as simple as just calling sort
but i'm wondering if there is a better/cleaner way of doing this? i'm not all that familiar with maps... any help would be appreciated..

Based on your edit, you seem to want to get all the Objects in your Map and sort them. There is not a direct way to sort the values in a map together so to sort all the items, the easiest would be to consolidate them into one list and Collections.sort() the whole thing.
public ArrayList<Object> sortAllValues() {
ArrayList<Object> allEntries = new ArrayList<Object>();
for (Entry<Object, ArrayList<Object>> entry : multiMap.entrySet())
allEntries.addAll(entry.getValue());
}
return Collections.sort(allEntries);
}
You will still need to implement Comparable to your Object if it does not have it. This is a good guide on how to do implement Comparable

Actually you should not care that the ArrayList is the value in a Map this does not matter. You would sort this ArrayList<Object> just the way you would sort any such list. Problem here is that you will have to implement some kind of Comparator that casts the Object to the needed type. In general I would personally make the ArrayList of more specific type than Object to make sorting easier.

Check out the MultiMap implementations of Apache Commons and Google Collections. They might have one that already supports sorting/ordering.

Related

Quick way to search through arrayList

I have an arraylist Arraylist<String[]> and I am trying to find a quick way of looking for a specific value on a specific index of the String[]. My ArrayList is always going to contain String[] of length 2. And what I want to do is look through the ArrayList for any String[] that has a specific value i.e. str[1]="value". I know that I can iterate through the ArrayList taking every single element (String[]) and then looking for the value using str[1].equals("value") but I was wondering if there is a quicker way of doing it by maybe using contains() of the ArrayList or something.
thanks
PS: I don't know the value of the first element of my array (str[0]) so I cannot construct a new String[] and check if the ArrayList contains that
If you look into ArrrayList#contains - you will see, that this method also iterates through all elements.
You could use a parallelStream - so that the ArrayList can be searched by more threads.
List<String[]> listToSearchIn = new ArrayList<String[]>();
List<String[]> matches = listToSearchIn.parallelStream()
.filter((element) -> element[1].equals("value"))
.collect(Collectors.toList());
LinkedHashMap
How about using a LinkedHashMap<String, String[]> instead of the ArrayList? The key would be the String[1] value. Linked because that gives you predictable iteration order.
An auxiliary Map
Or you could create a Map<String, Integer> where the key is the String[1] value and the value is the index of your String[] in the ArrayList.
ArrayList<String[]> al = new ArrayList<>();
Map<String, Integer> alIndexMap = new HashMap<>();
// ...
Integer nextIndex = al.size();
al.add(someStringArray);
alIndexMap.put(someStringArray[1], nextIndex);
If you keep al and alIndexMap in sync all the time, you'll always know where in al is the array that you're looking for.
Guava BiMap
Google's Guava has some classes that implement their BiMap interface. It's like a Map, but it works both ways, i.e. you can use the value as a key if you want.
Unless your ArrayList is sorted then O(n) efficiency is the best you can do. Unless by "quick way" you mean a method which does the iteration for you. Even in this scenario the answer is no since you're wanting to check data inside the String[] objects themselves.

Sorting collection in java

I have a HashMap which has keys as Date in Strings and value as an ArrayList of custom objects. I want to sort this hashmap on the basis of key. How can I do that?
HashMap<String,List<ClassName>> hashmap = new HashMap<String,List<ClassName>>();
When Hashmap is like this:
{"2015/07/15 : List("Object1","object2","object3")
"2015/07/14 :List("Object4" , "Object5")}
Please suggest.
You can use TreeMap instead of a HashMap . The TreeMap implements the Sorted Map interface.
As well as using a sorted map (as others have suggested) you can easily sort the keys when you use them rather than when you insert them.
For example, in Java 8:
treeMap.keySet().stream().sorted().forEach(System.out:println);
A nice thing about this is that it's easy to sort using different comparators without changing the collection.
For example, if you wanted to to sort by the number of items in the list value:
treeMap.keySet().stream().sorted(Comparator.comparingInt(k -> treeMap.get().size()))
This method is good for situations in which you insert and change values in the map often and then occasionally need the keys sorted for a particular operation. You get the performance of a HashMap but the flexibility to sort however you want on use.
You can use TreeMap, if you need the sorted map.
If you don't want to use TreeMap, then get the key and sort it as below.
HashMap<String, ArrayList<String>> map = new HashMap<String, ArrayList<String>>();
map.put("2015/07/15", list);
map.put("2015/07/17", list1);
map.put("2015/07/16", list1);
ArrayList<String> keyset = new ArrayList<String>(map.keySet());
Collections.sort(keyset);
First thing is you can use TreeMap when you need a sorted map. However you are storing date value as Strings. Then it become harder to compare each. So i recommend to use java.util.Date instead of String. You can use a date formatter when you adding to the map. Use following code.
TreeMap<Date, List> treeMap = new TreeMap<>();
You can specify the Comparator in the constructor of the TreeMap. So it's easy to sort up things according to your custom order.

What is the best way to merge similar objects in a java List?

Here is my problem (simplified):
Suppose we have a class:
public class MyClass{
String name;
Double amount;
String otherAttribute;
}
And a List<MyClass> myList
Suppose we have 2 elements from myList. Let's say object1 and object2
What I would like to do is:
if (object1.name.equals(object2.name){
//add amount of object2 to object1
//remove object 2 from the list
}
Considering I have a large list (maybe 100 elements) and I would like to find the best and less consuming way to do what I want.
What would you suggest ?
EDIT:
Yes 100 items is not large, but I would call this method (of merging similar objects) many times for many different sized lists. So that's way I would like to find the best practice for this.
I can't override equals or hashCode methods of MyClass, unfortunately (client requirement)
I'd add the objects to a HashMap where the name is the key and MyClass is the value being stored. Loop through each object in your list to add them to the map. If the name isn't in the map, just add the name, object pair. If it is already in the map, add the amount to the object already stored. When the loop completes, extract the objects from the map.
100 elements is a tiny size for a list, considering you're not going to repeat the operation some hundreds of thousands times. If it's the case, I'd consider creating a data structure indexing the list items by the search property (Map for instance), or ordering it if suitable and using an efficient search algorithm.
One approach (as suggested by Bill) would be to traverse the List adding every element to a Map, with the name property as key. You can take advantage of put's return to know if a name has been previously put into the map, and add the previosuly accumulated amounts in the current element. Finally, you could use values() to get the List without duplicates.
For instance:
List<MyClass> l;
Map<String, Myclass> m = new HashMap<MyClass>();
for (MyClass elem : l) {
MyClass oldElem = m.put(elem.getName(), elem);
if (oldElem != null) {
elem.setAmount(elem.getAmount() + oldElem.getAmount());
}
}
l = new ArrayList<MyClass>(m.values());
If you need to preserve order in the list, consider using a LinkedHashMap.
This is an O(n^2) problem unfortunately. You need to compare n elements to n-1 other elements. There is no way to do this but to brute force it.
If you used a HashMap however, you could check the map for an element before adding it to the Map which is an O(1) operation. It would look something like this:
HashMap<String, MyClass> map = new HashMap<String, MyClass>();
when you add an element:
if (map.get(obj1.name) != null) {
var obj2 = map.get(obj1.name);
obj2.amount = obj2.amount + obj1.amount;
map.put(obj1.name, obj2);
}
'Large' is relative, 100 items is definitely not large, imagine if you had to process a stream of 1.000.000 items/second. Then you would redefine large :D
In your example, what I think would be good to avoid would be to create a Set of your items' names. Searching a java HashSet takes O(1), so if an objects' name exists in the hash set, then update it on the list. An even better solution would be to create a HashMap, on which you could say e.g.
if(mymap.contains(thename)){
mymap.put(thename, newSum);
}
this being an example of how you could use it. Here's a link to get you started: http://java67.blogspot.gr/2013/02/10-examples-of-hashmap-in-java-programming-tutorial.html
I suggest to optimize (if possible) by not even doing the .add() to the list if an element with the same name exists. Using one of the hash based collections in combination with a proper equals() & hashCode() implementation based on MyClass.name should also give you somewhat good performance.
First, since you cannot override equals or hashCode, then you need to have the function that will do this functionality in the same package as your MyClass class, since no accessor methods are defined in MyClass
Second, try to have your items in a LinkedList, so that you can remove repeating elements from that list really quick without having to move around the other items.
Use a map to keep track of the amount that corresponds to a given name, while iterating the list, and removing repeating elements at the same time. In this way you don't have to create a new list.
List<MyClass> myClass_l;
Map<String, MyClass> nameMyClass_m = new HashMap<String, MyClass>();
for (Iterator<MyClass> iterator = myClass_l.iterator(); iterator.hasNext(){
MyClass m = iterator.next();
if (nameAmount_m.contains(m.name)){
MyClass firstClass = m.get(m.name);
firstClass.amount += m.amount;
iterator.remove();
}
else{
nameMyClass_m.put(m.name, m);
}
}
By the time you have finished the loop, you will have the items you want in your original list.

How to check whether a HashMap has all the elements of an ArrayList?

If I have a HashMap hashM, an ArrayList arrayL. If I would like to use an if statement to check whether hashM has all the elements in arrayL, how can I do that?
I cm currently using something like
if (hashM.values().containsAll(arrayL.getPreReqs()))
However it doesn't work properly.
Dear all thanks for the answers!
Actually containsAll works however the way I structure the my codes is wrong so that I got wrong outcomes. Now it has been fixed.
Cheers!
Given
Map<?,?> map = new HashMap<?,?>();
List<?> list = new ArrayList<?>();
The approach you tried (well, nearly, as pointed out by Marko Topolnik) is indeed correct:
if (map.values().containsAll(list)) { ... }
(Or map.keySet().containsAll(list) if you were interested in the map keys instead of values.)
For this to work as expected for custom types, you of course must have implemented equals() and hashcode() correctly for them. (See e.g. this question or better yet, read Item 9 in Effective Java.)
By the way, when working with Java Collections, it is good practice to define fields and variables using the interfaces (such as List, Set, Map), not implementation types (e.g. ArrayList, HashSet, HashMap). For example:
List<String> list = new ArrayList<String>();
Map<Integer, String> map = new HashMap<Integer, String>();
Similarly, a more "correct" or fluent title for your question would have been "How to check whether a Map has all the elements of a List?". Check out the Java Collections tutorial for more info.
Your code is correct except..
if (hashM.values().containsAll(arrayL)) {....}
[EDIT]
You can use HashMap.containsValue(Object value)
public boolean containsList(HashMap<K, V> map, List<V> list) {
for(V value : list) {
if(!map.containsValue(value)) {
return false;
}
}
return true;
}
Your code should work - but will not be particularly efficient. You need to compare every element in the list with every element in the map.
If (and only if) you can easily extract the key of the map from the elements then you would be better off looping through your List and for each element do map.containsKey(getKey(elem)), this will be much faster.
If you are doing this sort of comparison a lot and you cannot map from element to key then it may be worth keeping a HashSet of the values for this purpose.
I agree with JoniK. This can be done in a single line like this.
if(hashM.values().containsAll(arrayL)) {// put your code here that will be returned}

How to sort map inside of List in java

List<Map<String,String>> consolidErr = new LinkedList<Map<String,String>>();
Map m1= new HashMap<String,String>();
m1.put("id","1");
m1.put("value","value1");
Map m2= new HashMap<String,String>();
m2.put("id","2");
m2.put("value","value2");
Map m3= new HashMap<String,String>();
m3.put("id","3");
m3.put("value","value3");
add all m1,m3 and m2 in list
then sort maps based on ids in map now i want maps in list as m1,m2 and m3.
Now I want to sort based on the ids in the map, I did that using iteration of list and keep first id of map as checker and compare with next it works if there any other better way than that using built-in methods.?Please give your ideas.am using bubble sort for this now.
The simplest way to do this in java (or at least, with the least mess) is to use a custom comparator.
The idea is that if you have objects with a natural sort (anything that extends Comparable) you can just ask for the sorting , e.g.
Collections.sort(List<Integer> ..
otherwise you can just pass in a Comparator that describes how you want objects compared, with any custom logic you want, e.g. (roughly - this is off the top of my head and doesn't have error checking, but should be enough to give you the idea) -
List<Map<String,String>> consolidErr = ...
enter code here
Collections.sort(consolidErr, new Comparator<Map<String,String>>(){
public int compare(Map<String,String> a, Map<String,String> b){
return a.get("id").compareTo(b.get("id"));}
})
In Java 8, we can sort the list of maps in a single line.
list.sort(Comparator.comparing((Map<String,String> mp) -> mp.get("Id")));
I would use instead the PriorityQueue
as a wrapper for your list. By providing the Comparator to the constructor when creating it, would assure you that your list will remain sorted after each insertion of a new element to the list.

Categories

Resources