I am currently working on a project in which I am retrieving data about names from the Social Security website. Basically I'm given a number x, and years y and z. I have to return the top x names from each of the years y through z.
So the data returned from the website is a name, a rank, and a year. I have to enter each name returned into either a TreeMap, HashMap, or LinkedHashMap, but I'm not sure how to store them, because no matter what I use as the key, there might be duplicates. The year cannot be the key as I will have the top x names from each year, so they would all be from the same year. If there are multiple years, there would be several names of rank 1, etc, as there is one for each year, so that could not be the key. And the name itself could not be the key as the same name might have been in the top several names for multiple years.
I've managed to understand most of the complicated parts of this project, yet this--one of the simplest parts, I can't seem to understand!
I've heard of ways that I can use something like the year as the key and make the value a list of names or something similar, but I'm not sure how I would add values in implementations like that. I would greatly appreciate any recommendations!
Thanks so much.
Edit: Please note that I was specifically told I MUST use TreeMap, HashMap, or LinkedHashMap. I've heard of MultiMap but that's not one of my options.
I think using a hashmap with an List is what you're specifically asking for. An example of how to instantiate such an object would be:
HashMap<Integer, List<String>> myHashMap = new HashMap<Integer, List<String>>();
Note that we have to use Integer because Hashmaps only work with objects. To add values to this, you could do:
myHashMap.get([whatever year you wanted]).add("[whatever name you want]");
However, a look at this question shows this would not be quite as easy as this, as you must instantiate each List for all your key's (that question deals specifically with multidimensional hashmaps, but the premise is the same). However, it is doable, as the answer to that question demonstrates. You should have a look at it, as I think it will you help you understand what's going on with all this, but the code that might work for you could look like (taken almost directly from the answer to the linked question):
if (!myHashMap.containsKey(myYear)) {
myHashMap.put(myYear, new List<String>());
}
Edit: If you can't use the List inside either, I suppose you could put another hashmap inside, but I don't see that having much real use for this unless it's just an arbitrary requirement.
Related
Is nesting collections in Java something that I should be doing?
I'm currently working on a project where I want to have a bunch of hashmaps that would contain a String key and an arrayList value. That way when I create and add an object of another class to the collection, it would be able to use some piece of information that if it matched up with one of the keys of one of the hashmaps it would then be deposited in the associated arrayList value. That way the list can later on be accessed through the correct key for a specific hashmap.
Is this a good idea? Or is it too convoluted and if so is there a better way to do this?
There are times to nest, for sure. But in the humble opinion of this seasoned dev, you shouldn't do it unless you have a good reason. All too often you would be much better off with some class that represents the inner collection.
So if you find yourself with a Map<String,List<Foo>> ask yourself what that List<Foo really represents. If it's Map<String,List<Student>> then maybe you need Map<String, Roster> or Map<String, Team>. I find this yields faster time to market and fewer bugs. The fact you're asking the question means you think there's a chance that might be true too.
I had originally written an ArrayList and stored unique values (usernames, i.e. Strings) in it. I later needed to use the ArrayList to search if a user existed in it. That's O(n) for the search.
My tech lead wanted me to change that to a HashMap and store the usernames as keys in the array and values as empty Strings.
So, in Java -
hashmap.put("johndoe","");
I can see if this user exists later by running -
hashmap.containsKey("johndoe");
This is O(1) right?
My lead said this was a more efficient way to do this and it made sense to me, but it just seemed a bit off to put null/empty as values in the hashmap and store elements in it as keys.
My question is, is this a good approach? The efficiency beats ArrayList#contains or an array search in general. It works.
My worry is, I haven't seen anyone else do this after a search. I may be missing an obvious issue somewhere but I can't see it.
Since you have a set of unique values, a Set is the appropriate data structure. You can put your values inside HashSet, an implementation of the Set interface.
My lead said this was a more efficient way to do this and it made sense to me, but it just seemed a bit off to put null/empty as values in the hashmap and store elements in it as keys.
The advice of the lead is flawed. Map is not the right abstraction for this, Set is. A Map is appropriate for key-value pairs. But you don't have values, only keys.
Example usage:
Set<String> users = new HashSet<>(Arrays.asList("Alice", "Bob"));
System.out.println(users.contains("Alice"));
// -> prints true
System.out.println(users.contains("Jack"));
// -> prints false
Using a Map would be awkward, because what should be the type of the values? That question makes no sense in your use case,
as you have just keys, not key-value pairs.
With a Set, you don't need to ask that, the usage is perfectly natural.
This is O(1) right?
Yes, searching in a HashMap or a HashSet is O(1) amortized worst case, while searching in a List or an array is O(n) worst case.
Some comments point out that a HashSet is implemented in terms of HashMap.
That's fine, at that level of abstraction.
At the level of abstraction of the task at hand ---
to store a collection of unique usernames,
using a set is a natural choice, more natural than a map.
This is basically how HashSet is implemented, so I guess you can say it's a good approach. You might as well use HashSet instead of your HashMap with empty values.
For example :
HashSet's implementation of add is
public boolean add(E e) {
return map.put(e, PRESENT)==null;
}
where map is the backing HashMap and PRESENT is a dummy value.
My worry is, I haven't seen anyone else do this after a search. I may be missing an obvious issue somewhere but I can't see it.
As I mentioned, the developers of the JDK are using this same approach.
Before we start, I should mention that I'm trying to do this in Android, though I believe it is not relevant to what I am trying to resolve in this question specifically.
I should also mention that I have seen similar things asked already, though they did not exactly help me in what I am trying to do. While some of them have helped me get a general idea of how it should be done, in the end, I've been left helpless by the too-specific problems the other users had.
I believe it would also be useful to clarify that I am relatively new to programming in Java, with very little experience or knowledge of complex data structures.
What I am trying to do is as follows:
Say I have a class named WordThing, which contains two strings, called name and color, and an int called picture (which is used for retrieving the ID for an imagebutton). I also have a separate char called uno, whose value is a. There is an instance of WordThing called a, with its values properly assigned. I want to ask if it'd be possible to call one of the values of WordThing a using the value of uno, like this:
getValue(uno).picture
While I am aware that the above example is, in many ways, incorrect, nevertheless am I asking whether such a thing would be possible.
To clarify, in reality there are more chars than just uno, namely four, all with different letters, who are subject to randomization. My intention is to use these random letters to call upon four distinct WordThing instances, whose values will then be used in altering some elements of a given View, like this:
upperleftButton.setImageResource(getValue(uno).picture);
Any kind of help is appreciated.
What you are looking for is a Map, also know as an Associative Array or dictionary. Maps are used to store items in key/value pairs, where the key can be used to look up the value within a map. In java (and android) you can use a map like this.
Map<String, WordThing> wordThingMap = new HashMap<String, WordThing>();
// Add some items to the map
wordThingMap.put("a", new WordThing());
wordThingMap.put("b", new WordThing());
// Do some other stuff
someSuperSpecialMethod();
// Retrieve values from the map
WordThing a = map.get("a");
As a side note, you should probably think about re-naming some of your variables. WordThing isn't really that descriptive, and variable names like "a" and "b" will become very difficult to work with very quickly. For some tips on naming variables, see this question for a start.
I am learning Java and have a pretty basic problem.
I am indexing some sites with a BufferedReader and storing the data in a MySQL-base. I do this for 30 sources every 15 seconds, which generate a lot of data.
Now I want to analyze this data. I am thinking of storing the data simultaneously in a HashMap which I will clear at the end of the day, every day.
But can you give me an example on how to create an object for 30 different sources?
Do I need 30 different HashMap or can I build a key like 'pathName+randomNumber'?
In the end I want to be able to locate the first entry in the HashMap for each source and the two latest entries thereby enabling me to see what the difference between these three are.
Please help. I have tried to look on the web but with no luck as I think the HashMap examples are always focused towards storing Objects, but not on how to create the objects you store in them... (yeah I know - it's a rookie question) ;)
One possibility would be to use a Map on pathname in which you store Lists containing the data objects. This would allow you to retrieve them in the order you inserted them.
Instead of a List you could also store Maps from Long (timestamp of the fetch) to your data object.
What would be the best method depends on how you want to use the data structure.
Jobu, I would do exactly as you proposed. So in a sense you answered your question already. :) Whenever I had a similar situation, and had to use a Map, I use forward slashes to form a hierarchy of objects. So, say you want to distinguish data that come from 30 sources as you say. - Give those sources a unique name, and form your Map keys using this simple pattern: "/<root>/<source id>/<data id>" . Example of storing a link on some website: mymap.put("/myproject/www.example.com/link-0121", "http://www.kernel.org");
If, for some reason you want to get all Map entries that have keys equal to "/myproject/www.example.com", then I suggest you List objects only to your map! Here is a pseudo-code for that case:
ArrayList lst = new ArrayList();
lst.add("http://www.kernel.org");
mymap.put("/myproject/www.example.com", lst); // www.example.com has a link to www.kernel.org
This approach works only if your data can be uniquely identified by a number. Then you simply use List's get() method which has index as parameter.
However, if you need to have string keys for data, I am afraid you need to make Map of Maps (ie. use HashMap instead of the ArrayList).
Declare a map that has String as a key (source) and List<String> as its value (web page data).
Map<String, List<String>> map;
I want to store some objects and then be able to retrieve them later as efficiently as possible. I will also remove some of them under certain conditions. It seems a hash map would be the right choice.
But, from what I've seen, hash maps always associate a value with another? For example, "john" and "555-5555", his phone number.
Now, my situation. Suppose I have a bunch of people, and each person is connected to other people. So, I need each person to store its contacts.
What I'm doing is have each person have a hashmap, and then I'd add to the hash otherPerson, otherPerson. Basically, the key is the value. Am I doing it wrong?
EDIT I don't think the HashSet would solve my problem because I have to retrieve the value to update it and there is no get method. Remove returns a boolean, so I can't even remove it to put it back again, which would probably be a bad idea anyway.
If all you need is checking if A is one of B's contacts, then Set is choice. It has contains() for that purpose.
Otherwise, the most suitable might be Map, as you need efficient retrieval operation. You said currently you use same object as key and value, but I'm not sure how you get the the key in the first place. Say you'd like to get contact A from B's contacts, and you use something like 'B.contacts.get(A)', where do you get A from? If you already have A, what's for to get it from the map again? (maybe there are multiple instances of the same person?)
Unless there are multiple instances of the same person, I'd say for each Person, define a ID like unique attribute, and use that as the key for the contacts map. Also, do you define equal()/hashCode() for person class? Map/Set uses hashCode() and equal() for finding the match. Depending on your usage, you might need to consider rewrite them for efficiency.
I don't think the HashSet would solve my problem because I have to retrieve the value to update it and there is no get method.
This is a puzzling statement. Why would you want to retrieve a value using a get method to update it? Surely, if you know which object you need to retrieve from the set/map, you don't need to retrieve it.
For example:
HashSet<Person> relations = ...
Person p = ...
if (relations.remove(p)) {
// we removed an object such that p.equals(obj) is true.
}
Now if you are worried that the object that was removed was equal to, but not identical to p, it seems to me that something is wrong with your design. Either:
you should not be creating multiple Person instances that are equal, or
you should not be caring that Person instances are not identical, or
you should not have overridden equals(Object).
In short, the problem is that you are not managing object identity properly.
Well, the data structure you'd be looking for here, would be a HashSet (or some other kind of set), I think (if your framework/library offers it). A set just says "I have the following items" instead of "I have the following items mapped to the following values". Which would be what you're modeling here.
As for HashSet vs. other implementations (if present): That all depends on what you're doing. If you need fast lookup, i. e. "is this element in the set?" questions, then hashing is a good thing. Other underlying data structures are perhaps better optimized for other set operations, such as union, intersection, etc.
A hash table/map simply requires that you have a way to get the values you're interested in looking up later; that's what the key is for.
However, in your specific case, it sounds like you're looking for a way to store relationships between people, and what you're keeping track of is whether or not person A has a relationship with person B. A better representation for that sort of thing is an adjacency list.
Am I missing something or don't you simply need an ArrayList<Person>?
I would just store the contacts in a List<Person>. E.g.
public class Person {
private List<Person> contacts;
}
With regard to editing the individual contact, it is really not the parent Person's responsibility to do that. It should at highest add/remove contacts. You can perfectly do that by contacts.add(otherPerson) or contacts.remove(otherPerson).
When you want to edit an individual Person, which may be one of the contacts, just get a handle to it independently, e.g. personDAO.find(personId) and then update it accordingly. It's actually also the Person's own responsibility to edit own details. With a good ORM under the hood, the changes will be reflected in the contact list of other Persons.
If you need to iterate through the people, or require them to have ordering, consider TreeMap or TreeSet instead of hashing.