Java - Iteration over HashMap replacing ArrayList - java

Previously I set up an ArrayList to contain objects of records. I have since replaced the ArrayList with a HashMap where the objects are stored and use the username string of an individual as the key.
The class of this directory implemented Iterable through implements Iterable<Object> (just a one off question, but why is <Object> required?).
The previous code used to iterate over the ArrayList was:
public Iterator iterator() {
return records.iterator();
}
I then used this iterator for all objects in that class as follows:
for (Object o : directory) {
TelephoneRecords temp = (TelephoneRecords) o;
System.out.println(temp.toString());
}
Unfortunately, the HashMapName.iterable(); seems to raise issues, so how do I go about this behaviour with a HashMap?

If you're only interested in the keys, you can iterate through the keySet() of the map:
Map<String, Object> map = ...;
for (String key : map.keySet()) {
// ...
}
If you only need the values, use values():
for (Object value : map.values()) {
// ...
}
Finally, if you want both the key and value, use entrySet():
for (Map.Entry<String, Object> entry : map.entrySet()) {
String key = entry.getKey();
Object value = entry.getValue();
// ...
}
Hope this helps you.

You can iterate over the entrySet of the HashMap. The entrySet contains the sets of keys and values. The keys and values are then accessible through getKey() and getValue(). This can be done by the following code:
for (Map.Entry<String, Object> entry : map.entrySet()) {
String username = entry.getKey();
TelephoneRecord record = (TelephoneRecord)entry.getValue();
// Do something with username and record ...
}
Your off-question:
Object is a type parameter for the HashMap, which says that the Iterable contains Objects. If your HashMap is only supposed to contain TelephoneRecords objects, replace
implements Iterable<Object>
with
implements Iterable<TelephoneRecords>
That way you're saying that your Iterable contains TelephoneRecords, which in turn lets you avoid casting and get compile errors instead of runtime errors if you're doing something wrong (which is prefered!). That would improve the above code to:
for (Map.Entry<String, TelephoneRecord> entry : map.entrySet()) {
String username = entry.getKey();
TelephoneRecord record = entry.getValue();
// Do something with username and record ...
}

What does "seems to raise issues" mean? In a HashMap, you can iterate over keys (map.keySet()), values (map.values()) or key-value pairs (map.entrySet()).

I solved my issue with replacing records.iterator(); (which didn't work) with records.values().iterator();. It seems you cannot iterate directly over a HashMap but you can iterate over the values (objects) within it.
Furthermore, the issue of getting and printing the contents of the HashMap, I solved through the following code. It iterates over the TelephoneRecords objects within the directory, as specified by TelephoneRecords o : directory and the Iterator method within the directory class. Then a temporary object is assigned to the TelephoneRecords object being iterated over, and the [custom] toString() method used to print out the string of that specific TelephoneRecords object.
for (TelephoneRecords o : directory) {
TelephoneRecords temp = (TelephoneRecords) o;
System.out.println(temp.toString());
}
And I ended up solving my little side question by following the help provided, using Iterator<TelephoneRecords> (rather than simply using Object) to iterate over the TelephoneRecords objects contained within the directory object.

You can use the entryset from the hashmap, then iterate over that in the same manner as you do already e.g.
for (Object o : Directory.getEntrySet()) {
}
Also, if you type your hashmap it will remove the need for the cast -
Map<String, TelephoneRecords>

Related

How can I iterate through a hashset within a hashmap?

I am trying to iterate through a hashmap which contains 8 entries. However one of these entries is a hashset 'balloon' with 2 objects within it. I want to add this to an array list so i can then iterate through it in a for loop/
First part of the code below works, I loop through the hashmap and look for the key I require which is 'balloon'. I need help to add the hashset to an array list.
I am getting a casting error when using Collectors.list and stream
//This is the hashmap I am looping through to find the balloon key
Map<String, Object> types = System.getPartyItems();
for (Map.Entry<String, Object> entry : types.entrySet()) {
if (StringUtils.contains(entry.getKey().toString(), "balloon")) {
//This is where I need to add the balloon hashset to a list to access the entries and values from within.
List<PartyItem> myPartyList = new ArrayList<>();
myPartyList.add (hash set of balloon objects)
Do i need to assign the hash set to a variable before i can set it to the list? Anything I've tried I am getting a casting error eg "class java.util.stream.ReferencePipeline$Head cannot be cast to class java.util.ArrayList"
Any help appreciated.
Thanks
Test if a value is a Set and if it is, add all items to your list.
if (StringUtils.contains(entry.getKey().toString(), "balloon")
&& entry.getValue() instanceof Set) {
myPartyList.addAll((Set)entry.getValue());
}
You can iterate like this:
for(String key: Map.keySet()){
if(StringUtils.contains(key, "balloon")){
Iterator<String> it = hashMap.get("balloon").iterator();
while(it.hasNext()){
// your code here
}
}
}
Instead of iterating through entry just iterate through keys and when you find the balloon get the hashset to iterate through it.
for(String key: types.keySet()){
if(StringUtils.contains(key, "balloon")){
for(Object object: types.get(key)){
//do what you need with object
}
}
}
After your edit it should be like this
for(String key: types.keySet()){
if(StringUtils.contains(key, "balloon")){
ArrayList<Set<PartyItem>> myList = new ArrayList();
myList.add(types.get(key));
}
}
Usually you structure your hashmap as <key, value> and you access your values via their corresponding keys. But they have to match exactly.
In your case your hashmap would look like this:
Map<String, Object> partyItems = myPartyList.getPartyItems();
// or maybe even
Map<String, PartyItem> partyItems = myPartyList.getPartyItems();
And getting the value is as easy as:
Object partyItem = partyItems.get("baloon");
If you are not sure if your paryItems contain a value for your key baloon you can check that first:
if (partyItems.contains("baloon")) {
Object partyItem = partyItems.get("baloon");
}
If you are looking for a part of the key matching baloon:
List<PartyItem> myFilteredPartyItems = partyItems.entrySet().stream()
.filter(e -> e.getKey().contains("baloon"))
.collect(Collectors.toList()))
This is called stream oriented programming (take a look at the Java Stream API), and if your run at least Java 8 you can use those.
And what it does, is turn the entries of the List to a stream, then remove everything which does not contain baloon in the key, and turn the resulting stream, which was not removed back to a list.
Here you also find a very informative tutorial on how to use streams in Java.

What is better to iterate over an EnumMap in java?

Suppose I have declared an enum and corresponding emummap as:
enum MyEnum {
CONSTANT1, CONSTANT2, CONSTANT3;
}
EnumMap<MyEnum, String> MyEnumMap = new EnumMap<MyEnum, String>(MyEnum.class);
I want to iterate over MyEnumMap, for example, just to print each Entry one by one.
What is the best approach(fastest) to iterate over keys in the following cases:
When it is ensured that each constant in MyEnum is a key in MyEnumMap
When each constant in MyEnum may or may not be a key in MyEnumMap
I want to choose between foreach loop using MyEnumMap.keySet() or MyEnum.values(). Any other approach is most welcomed.
It does not matter. Internally, EnumMap is implemented with a pair of arrays of the same length as the number of enum entries. One array has enum elements, while the second array has objects mapped to them, or NULL placeholders. Any iteration over EnumMap is therefore equivalent to a for loop on an integer index that traverses the entire range of enum ordinals, so you should pick the approach that makes your code most readable to you.
If you take a look at code of EnumMap#keySet()
381 public Set<K> keySet() {382 Set<K> ks = keySet;383 if (ks != null)384 return ks;385 else386 return keySet = new KeySet();387 }
you will notice that it returns keySet used internally by EnumMap to store keys.
Now each time we call MyEnum.values() we are getting different array filled with all enum elements. This means that first empty array is created which later needs to be filled with all enums which requires some iteration.
So in first approach you are skipping iterating over enums already stored by map, while insecond approach we simply creating some temporary array which involves additional iteration over all MyEnum elements.
Perhaps, you just want another way of writing the code....
Since keys are always unique
for(MyEnum myEnum: MyEnum.values()){
String value = map.get(myEnum);
If(value != null){
//use the value here
}
}
Just another way to write it.
Or you could also try
for (Map.Entry<MyEnum, String> entry : map.entrySet()) {
System.out.println(entry.getKey() + "/" + entry.getValue());
}
It depend on your application logic, but here are some hints:
for 1)
// it is a bit faster to iterate over plain array, than over Set
// And you can also get here information about entries that are in enum, but not in hashMap, so you can have logic for those cases.
for (MyEnum e: MyEnum.values()) {
// you can get here information what is contained and not contained in your map
}
for 2) But it is still better to use 1) because you can have there information of enum values not contained in Map.
for (MyEnum e: MyEnumMap.keySet()) {
// you can check here all that is in your map, but you cant tell what is in enum but not in your map
}

How to return keys of a map according to a condition?

I'm learning Java using BlueJ, I have made a class that has a HashMap of (Integer, String) that contains an ID number of somebody and their name.
I want a method to return a collection of all the keys that satisfy a condition, like if their ID number begins with 3 for example. I can't figure out how to do this.
And then another method that returns a collection of the values if they satisfy a condition, I was thinking it would be very similar to the previous method.
I know I need to loop through the map but I am not sure how to write the condition to populate the new map.
Here's an example that returns all the odd keys, in a Collection. Lists and Sets are Collections, in the same way that ArrayLists are Lists. You could change Collection to List (or even ArrayList) in this example and it would do the same thing.
public Collection<Integer> getOddKeys() {
// keySet is a method of Map that returns a Set containing all the keys (and no values).
Collection<Integer> result = new ArrayList<Integer>();
for(Integer key : map.keySet()) {
if((key % 2) == 0) // if the key is odd...
result.add(key); // ... then add it to the result
}
return result;
}
You should be able to modify this example to check the values instead - I won't just give you that code, because it's very similar, and easy to figure out if you understand how this example works.
You need to use the values method, which returns a collection of the values, in the same way that keySet returns a collection (more specifically, a set) of the keys. If you're wondering about why keySet returns a set and values doesn't, it's because you can use the same value twice in a map, but you can't use the same key twice.
You could do the following:
Create a holder list
Iterator over your map keys using map.keySet().iterator();
Check if the key start with 3, if yes add it to the key list.
return the keys list.
In your case (if the map is not too big), I'll get all keys of the map, then process them one by one to math my criteria:
Map<Integer, String> myMap=getFromSomeWhere();
for(Integer i : myMap.keySet() {
String k=String.valueOf(i);
if(k.startsWith("3")) {
//do what you want
}
}
public void CountryAbbriviationMap(String input)
{
map<string ,string> countrymap =new map<string ,string>{'Australia'=>'AUS','Argentina'=>'ARG', 'India'=>'IND'};
for(string key : countrymap.keySet())
{
if(key.startsWithIgnoreCase('A') && input.startsWithIgnoreCase('A'))
{
system.debug(key); //TO GET KEYS
system.debug(countrymap.get(key)); //TO GET VALUES
}
}
}

Double nested for loop iteration (ArrayList)

I have a system that involves loading 'PlayerValue' Objects. The objects are formatted as such: [Header] value. I have these saved in a text file and whenever I save or read from the file, I want to remove duplicate headers. So I did this:
first, I load all of the PlayerValues from the file into an ArrayList called 'array', then:
for (PlayerValue v : array) {
for (PlayerValue v1 : array) {
if (v1.header.equals(v.header)) {
array.remove(v1);
}
}
}
Here you can see, it goes through each item of the array, then for each item, it searches the array again for the same header.
This would effectively remove duplicate headers, except for the fact that it throws a ConcurrentModificationException.
Any help for a work around?
Even if this worked, it would be a bad way to remove duplicates. A better option would be to have a Map<Header, PlayerValue>:
Map<String, PlayerValue> map = new HashMap<>();
for (PlayerValue v : array)
map.put(v.header, v);
Now you can iterate through this map's entries, which will not contain duplicate keys (headers):
array.clear();
for (Entry<?, PlayerValue> e : map.entrySet())
array.add(e.getValue());

How to get attributes for HashMap value?

"my" code:
public void iterateHashmap2() {
HashMap hashmap = this.media;
Iterator it = hashmap.keySet().iterator();
while (it.hasNext())
{
Object key = it.next();
Object val = hashmap.get(key);
// doesn't work..
System.out.println(val.getAttribute);
}
}
So my question is, how do I get the attributes that the value contains. The value is a class I made myself, which contains 4 Strings and another class I made, as attributes.
(What I want to do is iterate through a hashmap and compare the String of an attribute that is stored in the value with input data.. so I need to be able to access the attributes in the values of the hashmap..hope that makes sense..)
You access values in a map by providing a key:
// create a map
Map<String, MyObject> map = new HashMap<String, MyObject>();
// store a value
map.put("key", someObject);
// retrieve a value
MyObject someObject2 = map.get("key");
You can also use
map.keySet() to retrieve all keys
map.values() to retrieve all values, without keys
map.entrySet() to retrieve all Mappings. Each Entry represents one key mapped to one value.
a) In my code I use Java Generics, because that has been the standard way to do it for at least 5 years now.
b) You should consider reading The Map Interface from the Java Tutorial.
a): If you are using JDK1.5 or higher, please use generic and enhanced loop. The code will much simpler and safer:
for(Map.Entry<Key, YourObj> entry: this.media.entrySet()){
System.out.println(entry.getValue().getAttribute());
}
b): If you have to use JDK1.4 or lower, you have to cast your object: ((YourObj)val).getAttribute();
Object val = hashmap.get(key);
// doesn't work..
System.out.println(val.getAttribute());
The problem here is that Java is statically typed, which means you would need to cast val in order to access non-Object methods. You need to cast val as the type actually in the hashmap, as you're not using generics.
MyClass val = (MyClass) hashmap.get(key);
Try changing this line:
Object val = hashmap.get(key);
to this line:
YourClass val = (YourClass) hashmap.get(key);
Since you are getting an Object type you cannot just call your class's method without first casting it correctly.
Btw you should seriously consider using Java Generics
You will need a cast to a your target object's type. Like:
YourObject val = (YourObject) hashmap.get(key);
But ...
Your Map should be generic like Map<KeyClass, ValueClass>
There is better way to iterate over a Map:
Example:
for (Map.Entry<KeyClass, ValueClass> entry : map.entrySet()) {
KeyClass key = entry.getKey();
ValueClass val = entry.getValue());
}
If your question is how to cast the value mapped to the key in the HashMap why not use generics to achieve that:
public void iterateHashmap2() {
HashMap<Object,YourClass> hashmap = this.media;
Iterator<YourClass> it = hashmap.keySet().iterator();
while (it.hasNext())
{
Object key = it.next();
YourClass val = hashmap.get(key);
// if YourClass has a getAttribute() method then this will work
System.out.println(val.getAttribute());
}
}
Also note that it's always good practice to work at interface level -- so this line:
HashMap<Object,YourClass> hashmap = this.media;
should be
Map<Object,YourClass> hashmap = this.media;

Categories