I'm new to Java (and not too comfortable with strong typing) and I have a method that takes in a HashMap. A key in this hashmap contains a key, which has a hashmap for value, which also points to a hashmap, etc, until we reach a string:y
HashMap1->HashMap2->HashMap3->HashMap4->String
I am trying to access it as follows:
HashMap1
.get("aKey")
.get("anotherKey")
.get("yetAnotherKey")
.get("MyString");
But then I get an error,
Object does not have a method "get(String)
Here is the method, simplified:
public HashMap<String, HashMap> getMyString(Map<String, HashMap> hashMap1) {
String myString = hashMap1
.get("aKey")
.get("anotherKey")
.get("yetAnotherKey")
.get("MyString");
// do something with myString.
return hashMap1;
}
How would someone properly define the method and the parameters to access nested elements easily?
Thank you,
Simple as that
HashMap1.get("aKey") -- > return hashMap2
.get("anotherKey") --> return hashMap3
.get("yetAnotherKey") --> return hashMap4
.get("MyString"); --> return String
There is something wrong with the adding part.
Now you have structure like below.
hashmap1 --> hashmap2 --> String
String myString = hashMap1.get("aKey").get("MyString");
That is how it should be.
You made too many .get calls. Probably the last one is not needed.
Can you just create class CompoundKey with arbitrary number of String fields and use it as a key? It would simplify your design.
To use it properly in Java you need to override hashCode and equals methods.
You should first of all use interfaces not implementation, therefore use Map (and not HashMap) where possible.
And second, you should repair your Generics and use all levels. Now the compiler can help you and possible show your error.
// i suppose you want to return a String, at least the method name tells it
public String getMyString(Map<String, Map<String, Map<String, Map<String, String>>>> hashMap1) {
String myString = hashMap1
.get("aKey")
.get("anotherKey")
.get("yetAnotherKey")
.get("MyString");
return myString;
}
Yet i suggest that you use a different data structure.
Related
I have a collection of objects that look something like
class Widget {
String name;
int id;
// Intuitive constructor omitted
}
Sometimes I want to look up an item by name, and sometime I want to look it up by id. I can obviously do this by
Map<String, Widget> mapByName;
Map<Integer, Widget> mapById;
However, that requires maintaining two maps, and at some point, I will (or another user who is unfamiliar with the double map) will make a change to the code and only update one of the maps.
The obvious solution is to make a class to manage the two maps. Does such a class already exist, probably in a third party package?
I am looking for something that lets me do something along the lines of
DoubleMap<String, Integer, Widget> map = new DoubleMap<>();
Widget w = new Widget(3, "foo");
map.put(w.id, w.name, w);
map.get1(3); // returns w
map.get2("foo"); // returns w
A simple solution could be, to write your own key class that includes both keys.
class WidgetKey {
String id;
String name;
boolean equals() {...}
boolean hashCode() {...}
}
Map<WidgetKey, Widget> yourMap;
Beware that you have to implement equals and hashCode in the WidgetKey class. Otherwise put/get and other map methods wouldn't work properly.
I'm trying to optimize some code, and when I do this I usually end up getting that helping hand from Hash structures.
What I want to do is divide objects into multiples sets based on some attributes in a very fast way. Basically like SQL GROUP BY statement but for Java.
The thing is that I want to use HashMap<Object, ArrayList<Object>> to do this. I want to use multiple grouping ways but an Object can only have one hashCode().
Is there a way to have multiple hashCodes() in order to be able to group by multiple methods? Are there other structures made to solve this kind of issues? Can I use Java 8 lambda expressions to send a hashCode() in the HashMap parameters? Am I silly and there is a super fast way that isn't this complicated?
Note: The hashCodes I want use multiple attributes that are not constant. So for example, creating a String that represents those attributes uniquely won't work because I'd have to refresh the string every time.
Let's say you have a collection of objects and you want to produce different groupings analogous to SQL GROUP BY. Each group-by is defined by a set of common values. Create a group-by-key class for each distinct grouping type, each with an appropriate hashCode() and equals() method (as required by the Map contract).
For the following pseudocode I assume the existence of a MultiMap class that encapsulates the management of your map's List<Object> values. You could use Guava's MultiMap implementation.
// One group key
public class GroupKey1 {
...
public GroupKey1(MyObject o) {
// populate key from object
}
public GroupKey1(...) {
// populate from individual values so we can create lookup keys
}
public int hashCode() { ... }
public boolean equals() { ... }
}
// A second, different group key
public class GroupKey2 {
...
public GroupKey2(MyObject o) {
// populate key from object
}
public GroupKey2(...) {
// populate from individual values so we can create lookup keys
}
...
}
...
MultiMap<GroupKey1,MyObject> group1 = new HashMultiMap<>();
MultiMap<GroupKey2,MyObject> group2 = new HashMultiMap<>();
for (MyObject m : objectCollection)
{
group1.put(new GroupKey1(m), m);
group2.put(new GroupKey2(m), m);
}
...
// Retrieve the list of objects having a certain group-by key
GroupKey2 lookupKey = new Groupkey2(...);
Collection<MyObject> group = group2.get(lookupKey);
What you're describing sounds like a rather convoluted pattern, and possibly a premature optimization. You might have better luck asking a question about how to efficiently replicate GROUP BY-style queries in Java.
That said the easiest way to have multiple hash codes is to have multiple classes. Here's a trivial example:
public class Person {
String firstName;
String lastName;
/** the "real" hashCode() */
public int hashCode() {
return firstName.hashCode() + 1234 * lastName.hashCode();
}
}
public class PersonWrapper1 {
Person person;
public int hashCode() {
return person.firstName.hashCode();
}
}
public class PersonWrapper2 {
Person person;
public int hashCode() {
return person.lastName.hashCode();
}
}
By using wrapper classes you can redefine the notion of equality in a type-safe way. Just be careful about how exactly you let these types interact; you can only compare instances of Person, PersonWrapper1, or PersonWrapper2 with other instances of the same type; each class' .equals() method should return false if a different type is passed in.
You might also look at the hashing utilities in Guava, they provide several different hashing functions, along with a BloomFilter implementation, which is a data structure that relies on being able to use multiple hashing functions.
This is done by abstracting the hashing function into a Funnel class. Funnel-able classes simply pipe the values they use for equality into the Funnel, and callers (like BloomFilter) then actually compute the hash codes.
Your last paragraph is confusing; you cannot hope to store objects in a hash-based data structure and then change the values used to compute the hash code. If you do so, the object will no longer be discoverable in the data structure.
Taking your thoughts into account:
What I want to do is divide objects into multiples sets based on some attributes in a very fast way. Basically like SQL GROUP BY statement but for Java.
Map<City, Set<String>> lastNamesByCity
= people.stream().collect(groupingBy(Person::getCity,
mapping(Person::getLastName, toSet())));
so I have been able to put objects into my hash map successfully, but I'm having trouble returning an object. When I used an arrayList for this same project, I simply displayed it with the following method:
public void displayDetails(int currentItem) {
accountIDTextField.setText(table.get(currentItem).getAccountID()+"");
accountNumberTextField.setText(table.get(currentItem).getAccountNumber());
surnameTextField.setText(table.get(currentItem).getSurname());
accountTypeTextField.setText(table.get(currentItem).getAccountType());
}
And pressing the 'first' button would go to the number 1 in the list.
first.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
currentItem = 1;
displayDetails(currentItem);
}
});
As for my hashing, I have used the accountNumber as the key, (hashed by using the % modulo function)
Working backwards, I can get the accountID when I pass in the accountNumber as a parameter in the get() method.
hashMap.get(12345678).getAccountID();
But how do I return the accountID if I just want to get the first object stored in the hash map(i.e get accountID without knowing accountNumber)?
(AccountID is an integer unique to a particular account and will be automatically generated when a new account record is created)
Sorry if this isn't worded very well, I'm still trying to get my head around Java and OOP in general. Any help would be greatly appreciated. Thanks
hope I understood you right. getting only the first item of a HashMap would be something like:
Map<String, String> myhashmap = new HashMap<String, String>();
myhashmap.entrySet().iterator().next();
You can get the contents of the Map by using Map.values().
I would't access the value based on it's order in the map because ordering is not guaranteed. You should give each one a defined number. Then you can access them like:
Object o = map.values().get(id);
to get the first:
Object o = map.values().get(0);
So I have three important factors, filenames which there are many, there will also be duplicates, violation types which there are 6 of, and the data relating to them.
I was thinking of using a Map for this but it only accepts two types, so I want to sort the data by the filename and for every entry under that filename, i want to retrieve the violation type, from what i want it to retrieve all the matches from the data, so say it's a map I could of said map.get(filename, violation) and it will retrieve all the results that match that.
Is there a data structure that can allow me to do this? or am I being lazy and should just sort the data myself when it comes to outputting it.
One other way to approach this would be to use a custom Class for holding the needed data. Essentially 'building' your own node that you can iterate over.
For example! you could create the following class object: (Node.java)
import java.util.*;
public class Node
{
private String violationType;
private String dataInside;
public Node()
{
this("", "");
}
public Node(String violationType)
{
this(violationType, "");
}
public Node(String violationType, String dataInside)
{
this.violationType = violationType;
this.dataInside = dataInside;
}
public void setViolationType(String violationType)
{
this.violationType = violationType;
}
public void setDataInside(String dataInside)
{
this.dataInside = dataInside;
}
public String getViolationType()
{
return violationType;
}
public String getDataInside()
{
return dataInside;
}
}
ok, great, so we have this 'node' thing with some setters, some getters, and some constructors for ease of use. Cool. Now lets see how to use it:
import java.util.*;
public class main{
public static void main(String[] args){
Map<String, Node> customMap = new HashMap<String, Node>();
customMap.put("MyFilename", new Node("Violation 1", "Some Data"));
System.out.println("This is a test of the custom Node: " + customMap.get("MyFilename").getViolationType());
}
}
Now we have a map that relates all of the data you need it to. Now, you'll get a lot of people saying 'Don't reinvent the wheel" when it comes to things like this, because built in libraries are far more optimized. That is true! If you can find a data structure that is built into java that suits your needs, USE IT. That's always a good policy to follow. That being said, if you have a pretty custom situation, sometimes it calls for a custom approach. Don't be afraid to make your own objects like this, it's easy to do in Java, and it could save you a lot of time and headache!
EDIT
So, after re-reading the OP's question, I realize you want an entire list of associated data for the given violation of a given filename. In which case, you would switch the private String dataInside to something like private ArrayList<String> dataInside; which would allow you to associate as much data as you wanted, still inside that node, just inside of an arraylist. Also note, you'd have to switch up the getters/setters a little to accomodate a list, but that's not too bad.
You could use a custom class for a mapkey which contains the two fields filename and violation type. When doing so you need to implement equals() and hashCode() methods do ensure instances of that class can be used as key for map.
You can use TreeMap. TreeMap is sorted according to the natural ordering of its keys.
TreeMap<String, List<String>> map = new TreeMap<String, List<String>>();
I'm building a Java library for a customer, and one of the things they want is a data representation of a particular set of standards they work with. I don't want to reveal my customer's interests, but if he were an alchemist, he might want the following:
Elements
Fire
Name="Fire"
Physical
Temperature=451
Color="Orange"
Magical
Domain="Strength"
Water
Name="Water"
Physical
Color="Blue"
Earth
Name="Earth"
Magical
Domain="Stability"
Ordinality=1
I need to be able to access various data elements by name, such as:
Elements.Earth.Name
Elements.Water.Physical.Color
I also need to be able to iterate through attributes, as:
for (MagicalType attrib : Elements.Fire.Magical)
{
...
}
I have actually been able to create this data structure, and I can do everything I've asked for above -- though I had to create separate arrays for the iteration, so really what I do looks more like:
for (MagicalType attrib : Elements.Fire.MagicalAuxArray)
Unfortunately I haven't been able to meet my last requirement: the entire data structure must be immutable. I have tried repeatedly, and scoured the web looking for examples, but so far I haven't been able to accomplish this in any reasonable manner. Note that the final data structure will be quite large; I'm really hoping to avoid a solution that is too repetitious or creates too many public symbols.
I am a very experienced programmer, less experienced with Java. Can anyone suggest how I might represent the above data to meet all my requirements?
A few ways that come to mind immediately:
Don't provide setter methods for your object. You users can only create the object via a constructor and once created, it cannot be modified. This goes for other state-modification methods as well. If you want to avoid a very large parameter-list in your constructor, you can use the Builder pattern (described in Effective Java by Joshua Bloch (2nd Ed))
When returning collections, make defensive copies. In this case use a List instead of an array. That way you can do return new ArrayList<MagicalType>(MagicalAuxList) instead of return MagicalAuxList. This way people who use the class won't be able to modify the collection. One caveat here. If your array contains complex objects, they must be immutable as well.
For immutable collections, you can also try using the unmodifiableCollection static method (there are similar static-methods for lists, sets, etc. - use whichever one is appropriate for you) to convert your collection when you return it. This is an alternative to defensive copying.
Why do you use arrays? Wouldn't immutable collections (e.g. from Google Guava) do a better job?
You can use Iterable in your public API. Cleaner than Collections with all the mutators that you have to suppress. (unfortunately Iterator has a remove() method(?!) but that's just one)
public final Iterable<MagicalType> magics;
for(MagicalType magic : magics) ...
you could try the code below that uses final, enums and unmodifiable maps. but that does not let you access by name since you need to do a get from the map. you could probably do that in groovy.
import java.util.*;
enum Color {
red, green, blue;
}
class Physical {
Physical(final Double temperature, final Color color) {
this.temperature = temperature;
this.color = color;
final Map<String, Object> map=new LinkedHashMap<String, Object>();
map.put("temperature", temperature);
map.put("color", color);
this.map=Collections.unmodifiableMap(map);
}
final Double temperature;
final Color color;
final Map<String, Object> map;
}
class Magical {
Magical(final String domain, final Integer ordinality) {
this.domain = domain;
this.ordinality = ordinality;
final Map<String, Object> map=new LinkedHashMap<String, Object>();
map.put("domain", domain);
map.put("ordinality", ordinality);
this.map=Collections.unmodifiableMap(map);
}
final String domain;
final Integer ordinality;
final Map<String, Object> map;
}
public enum Elements {
earth("Earth", new Magical("Stability", 1), null), air("Air", null, null), fire("Fire", new Magical("Strength", null), new Physical(451., Color.red)), water(
"Water", null, new Physical(null, Color.blue));
Elements(final String name, final Magical magical, final Physical physical) {
this.name = name;
this.magical = magical;
this.physical = physical;
}
public static void main(String[] arguments) {
System.out.println(Elements.earth.name);
System.out.println(Elements.water.physical.color);
for (Map.Entry<String, Object> entry : Elements.water.physical.map.entrySet())
System.out.println(entry.getKey() + '=' + entry.getValue());
for (Map.Entry<String, Object> entry : Elements.earth.magical.map.entrySet())
System.out.println(entry.getKey() + '=' + entry.getValue());
}
final String name;
final Magical magical;
final Physical physical;
}