given the following code?
final Map<String, List<E>> map = new HashMap<String, List<E>>();
List<E> list = map.get(mapKey);
if (list == null) {
list = new ArrayList<E>();
map.put(mapKey, list);
}
list.add(value);
If there any way I can avoid the null check? But let the Map automatically create the List for me for my first time insertion?
I remember I once saw a specialized Map which is able to do this. However, I forget where I saw already :(
You are looking for Guava's* MultiMap. You may have previously heard about it when it was called "Google Collections".
This blog post talks a little about the MultiMap.
You could use Multimap from Guava... that's what I'd do :) (And in particular, an ArrayListMultimap.)
If you could, it might save a nanosecond and is probably not worth spending a lot of time figuring out. If however you are trying to optimize for performance and you have so many or such big maps that this is causing performance issues, you might consider Javolution. They have a fast map and fast list that perform much better than Java's default map and list.
There is a MultiValueMap in apache's commons-collections
If you have a small number of items an array might actually be faster. The overhead of more complex data types is not needed when you have a few items and a linear search helps the JVM load the items faster.
Related
What is the fastest way to get the selected objects from an array?
MyObject[] objects = new MyObject[]{new MyObject(true), new MyObject(false)};
MyObject[] selectedObjects = ???
Is there a faster way than:
ArrayList<MyObject> selObjectsList = new ArrayList<MyObject>();
for(MyObject obj : objects){
if(obj.isSelected()){
selObjectsList.add(obj);
}
}
selectedObjects = selObjectsList.toArray(new MyObject[0]);
This are many lines for a simple operation, is there a shorter operation to do the same?
With the standard libraries, there is no (fundamentaly) neater way to do it. But there are numerous third-party libraries that have filter or predicate support. Google Collections comes to mind. And I have also heard good things about LambdaJ. Hopefully, things will improve with Java 8!
With LambdaJ it could look something like this:
select(myList, having(on(MyObject.class).isSelected()));
Edit I interpreted "fastest" as shortest number of lines. If it was performance you was thinking of, this answer might not be appropriate.
Unfortunately, no. If you are using an ArrayList, which is a linear list, then your are effectively forcing a linear search.
If you want to improve lookup, then you can use something like a Map that will allow quicker lookups, but you will have to use an intelligent method for setting the keys. For instance, if you were lookup up orders, you might use the order number as the key.
Use a Map.
Map<Boolean, List<MyObject>> someMap;
Then you can do the following to retrieve the List of 'MyObjects' that are selected.
someMap.get(true);
And to populate...
someMap.put(myObjectInstance.isSelected(), myObjectInstance);
This API call returns a potentially large List<String>, which is not sorted. I need to sort it, search it, and access random elements. Currently the List is implemented by an ArrayList (I checked the source), but at some unknown point in the future the API developers may choose to switch to a LinkedList implementation (without changing the interface).
Sorting, searching, accessing a potentially large LinkedList would be extremely slow and unacceptable for my program. Therefore I need to convert the List to an ArrayList to ensure the practical efficiency of my program. However, since the List is most likely an ArrayList already, it would be inefficient to needlessly create a new ArrayList copy of the List.
Given these constraints, I have come up with the following method to convert a List into an ArrayList:
private static <T> ArrayList<T> asArrayList(List<T> list) {
if (list instanceof ArrayList) {
return (ArrayList<T>) (list);
} else {
return new ArrayList<T>(list);
}
}
My question is this: Is this the most efficient way to work with a List with an unknown implementation? Is there a better way to convert a List to an ArrayList? Is there a better option than converting the List into an ArrayList?
You can't really get much simpler than what you've got - looks about as efficient as it could possibly be to me.
That said, this sounds very much like premature optimisation - you should only really need to worry about this if and when the author of the API you're using changes to a LinkedList. If you worry about it now, you are likely to spend a lot of time and effort planning for a future scenario that may not even come to pass - this is time that might be better spent finding other issues to fix. Presumably the only time you'll be changing versions of the API is between versions of your own application - handle the issue at that point, if at all.
As you can see yourself, the code is simple and it is efficient inasmuch as it only creates a copy if it is necessary.
So the answer is that there is no significantly better option, save for a completely different type of solution, something that sorts your list as well, for example.
(Bear in mind that this level of optimisation is rarely required, so it's not a very frequent problem.)
Update: Just an afterthoughtL as a general rule, well-written APIs don't return data types that are inappropriate for the amount of data they are likely to contain. That is not to say you should trust them blindly, but it's not a completely unreasonable assumption.
Sorting, searching, accessing a potentially large LinkedList would be extremely slow and unacceptable for my program.
Actually, it is not as bad as that. IIRC, the Collections.sort methods copy the list to a temporary array, sort the array, clear() the original list and copy the array back to it. For large enough lists, the O(NlogN) sorting phase will dominate the O(N) copying phases.
Java collections that support efficient random access implement the RandomAccess marker interface. For such a list you could just run Collections.sort on the list directly. For lists without random access you should probably dump the list to an array using one of its toArray methods, sort that array, then wrap it into a random-access List.
T[] array = (T[])list.toArray(); // just suppress the warning if the compiler worries about unsafe cast
Arrays.sort(array);
List<T> sortedList = Arrays.asList(array);
I think Arrays.asList actually creates an ArrayList, so you could try casting its result, if you like.
Collections.sort is efficient for all List implementations, as long as they provide an efficient ListIterator. The method dumps the list into an array, sorts that, then uses the ListIterator to copy the values back into the list in O(n).
I just finished the main part of the current data structures project, and am working on collecting the statistics. One requirement is that a count of all the references within the TreeMap be recorded.
This Map contains a 31,000+ nodes where a String is mapped to a TreeSet of indeterminate size.
I need to traverse the map and keep a running count of the number of items in the set.
Originally my idea was this:
Set<String> keySet= lyricWords.keySet();
Iterator<String> iter= keySet.iterator();
String current= iter.next();
while (iter.hasNext){
runCount+= lyricWords.get(current).size();
}
The runtime for this is far too long to be acceptable. Is there a more efficient way to do this on the final structure? I could keep a count as the map is built, but the professor wants the numbers to be based on the final structure itself.
I'm not sure. But, probably, you have infinitive loop. Try:
runCount+= iter.next().size();
for (Map.Entry<String, TreeSet> e: lyricWords.entrySet()) {
runCount+= e.getValue().size();
}
I dont see a problem with keeping a count as the map is built.
The count will be correct at the end, and you wont have to incur the cost of iterating through the entire thing again.
I think that the tree can and should keep track of its size
This isn't of much use to you since this is an assignment you're working on, but this is an example where a data structure specifically designed for mapping keys to multiple values shows how much better it is than a Map<T, Collection<V>>.
Guava's Multimap collection type keeps track of the total number of entries it contains, so if you were using a TreeMultimap<String, Foo> rather than a TreeMap<String, TreeSet<Foo>> you could just call multimap.size() to get the number you're looking for.
By the way, the Multimap implementations store a running total of the number of entries which is updated when entries are added to or removed from it. You might be able to do this by doing some fancy stuff with subclassing the TreeMap and wrapping the TreeSets that are added to it, but it would be quite challenging to make it all work properly I think.
What's the quickest way to remove an element from a Map by value in Java?
Currently I'm using:
DomainObj valueToRemove = new DomainObj();
String removalKey = null;
for (Map.Entry<String, DomainObj> entry : map.entrySet()) {
if (valueToRemove.equals(entry.getValue())) {
removalKey = entry.getKey();
break;
}
}
if (removalKey != null) {
map.remove(removalKey);
}
The correct and fast one-liner would actually be:
while (map.values().remove(valueObject));
Kind of strange that most examples above assume the valueObject to be unique.
Here's the one-line solution:
map.values().remove(valueToRemove);
That's probably faster than defining your own iterator, since the JDK collection code has been significantly optimized.
As others have mentioned, a bimap will have faster value removes, though it requires more memory and takes longer to populate. Also, a bimap only works when the values are unique, which may or may not be the case in your code.
Without using a Bi-directional map (commons-collections and google collections have them), you're stuck with iterating the Map
map.values().removeAll(Collections.singleton(null));
reference to How to filter "Null" values from HashMap<String, String>?, we can do following for java 8:
map.values().removeIf(valueToRemove::equals);
If you don't have a reverse map, I'd go for an iterator.
DomainObj valueToRemove = new DomainObj();
for (
Iterator<Map.Entry<String, DomainObj>> iter = map.entrySet().iterator();
iter.hasNext();
) {
Map.Entry<String, DomainObj> entry = iter.next();
if (valueToRemove.equals(entry.getValue())) {
iter.remove();
break; // if only want to remove first match.
}
}
You could always use the values collection, since any changes made to that collection will result in the change being reflected in the map. So if you were to call Map.values().remove(valueToRemove) that should work - though I'm not sure if you'll see performance better than what you have with that loop. One idea would be to extend or override the map class such that the backing collection then is always sorted by value - that would enable you to do a binary search on the value which may be faster.
Edit: This is essentially the same as Alcon's answer except I don't think his will work since the entrySet is still going to be ordered by key - in which case you can't call .remove() with the value.
This is also assuming that the value is supposed to be unique or that you would want to remove any duplicates from the Map as well.
i would use this
Map x = new HashMap();
x.put(1, "value1");
x.put(2, "value2");
x.put(3, "value3");
x.put(4, "value4");
x.put(5, "value5");
x.put(6, "value6");
x.values().remove("value4");
edit:
because objects are referenced by "pointer" not by value.
N
If you have no way to figure out the key from the DomainObj, then I don't see how you can improve on that. There's no built in method to get the key from the value, so you have to iterate through the map.
If this is something you're doing all the time, you might maintain two maps (string->DomainObj and DomainObj->Key).
Like most of the other posters have said, it's generally an O(N) operation because you're going to have to look through the whole list of hashtable values regardless. #tackline has the right solution for keeping the memory usage at O(1) (I gave him an up-vote for that).
Your other option is to sacrifice memory space for the sake of speed. If your map is reasonably sized, you could store two maps in parallel.
If you have a Map then maintain a Map in parallel to it. When you insert/remove on one map, do it on the other also. Granted this is uglier because you're wasting space and you'll have to make sure the "hashCode" method of DomainObj is written properly, but your removal time drops from O(N) to O(1) because you can lookup the key/object mapping in constant time either direction.
Not generally the best solution, but if your number one concern is speed, I think this is probably as fast as you're gonna get.
====================
Addendum: This essentially what #msaeed suggested just sans the third party library.
A shorter usage of iterator is to use a values() iterator.
DomainObj valueToRemove = new DomainObj();
for (Iterator<DomainObj> it = map.values().iterator(); it.hasNext();)) {
if (valueToRemove.equals(it.next())) {
it.remove();
break;
}
}
We know this situation arise rarely but is extremely helpful. I'll prefer BidiMap from org.apache.commons.collections .
I don't think this will happen only once in the lifetime of your app.
So what I would do, is to delegate to another object the responsability to maintain a reference to the objects added to that map.
So the next time you need to remove it, you use that "reverse map" ...
class MapHolder {
private Map<String, DomainObj> originalMap;
private Map<DomainObj,String> reverseMap;
public void remove( DomainObj value ) {
if ( reverseMap.contains( value ) ) {
originalMap.remove( reverseMap.get( value ) );
reverseMap.remove( value );
}
}
}
This is much much faster than iterating.
Obviously you need to keep them synchronized. But it should not be that hard if you refector your code to have one object being responsible for the state of the map.
Remember that in OOP we have objects that have an state and behavior. If your data is passing around variables all over the place, you are creating unnecessary dependencies between objects
Yes, It will take you some time to correct the code, but the time spent correcting it, will save you a lot of headaches in the future. Think about it.
Often, I have a list of objects. Each object has properties. I want to extract a subset of the list where a specific property has a predefined value.
Example:
I have a list of User objects. A User has a homeTown. I want to extract all users from my list with "Springfield" as their homeTown.
I normally see this accomplished as follows:
List users = getTheUsers();
List returnList = new ArrayList();
for (User user: users) {
if ("springfield".equalsIgnoreCase(user.getHomeTown())
returnList.add(user);
}
I am not particularly satisfied with this solution. Yes, it works, but it seems so slow. There must be a non-linear solution.
Suggestions?
Well, this operation is linear in nature unless you do something extreme like index the collection based on properties you expect to examine in this way. Short of that, you're just going to have to look at each object in the collection.
But there may be some things you can do to improve readability. For example, Groovy provides an each() method for collections. It would allow you to do something like this...
def returnList = new ArrayList();
users.each() {
if ("springfield".equalsIgnoreCase(it.getHomeTown())
returnList.add(user);
};
You will need a custom solution for this. Create a custom collection such that it implements List interface and add all elements from original list into this list.
Internally in this custom List class you need to maintain some collections of Map of all attributes which can help you lookup values as you need. To populate this Map you will have to use introspection to find list of all fields and their values.
This custom object will have to implement some methods as List findAllBy(String propertyName, String propertyValue); that will use above hash map to look up those values.
This is not an easy straightforward solution. Further more you will need to consider nested attributes like "user.address.city". Making this custom List immutable will help a lot.
However even if you are iterating list of 1000's of objects in List, still it will be faster so you are better off iterating List for what you need.
As I have found out, if you are using a list, you have to iterate. Whether its a for-each, lambda, or a FindAll - it is still being iterated. No matter how you dress up a duck, it's still a duck. As far as I know there are HashTables, Dictionaries, and DataTables that do not require iteration to find a value. I am not sure what the Java equivalent implementations are, but maybe this will give you some other ideas.
If you are really interested in performance here, I would also suggest a custom solution. My suggestion would be to create a Tree of Lists in which you can sort the elements.
If you are not interested about the ordering of the elements inside your list (and most people are usually not), you could also use a TreeMap (or HashMap) and use the homeTown as key and a List of all entries as value. If you add new elements, just look up the belonging list in the Map and append it (if it is the first element of course you need to create the list first). If you want to delete an element simply do the same.
In the case you want a list of all users with a given homeTown you just need to look up that list in the Map and return it (no copying of elements needed), I am not 100% sure about the Map implementations in Java, but the complete method should be in constant time (worst case logarithmic, depending on the Map implementation).
I ended up using Predicates. Its readability looks similar to Drew's suggestion.
As far as performance is concerned, I found negligible speed improvements for small (< 100 items) lists. For larger lists (5k-10k), I found 20-30% improvements. Medium lists had benefits but not quite as large as bigger lists. I did not test super large lists, but my testing made it seem the large the list the better the results in comparison to the foreach process.