Which Map provides moving objects to different index? - java

I need a Map that takes Key-Value pair (probably HashMap<String, Object>) whereas the Key will be a property of the Object itself, like:
class Person {
String name; //I know a string is not a good unique key, but ok to illustrate my example
}
Person person = new Person("John");
map.put(person.getName(), person);
Further, the map must provide an accessor similar to ArrayList.add(idx, object). It should thereby also be possible to reorder an object to a different position and adjust the rest accordingly.
Which Map/List is suitable for this?
(by the way: I should be runable with GWT, so external libs might be problematic).

There's no single standard container that does all of this.
However, a combination of a map and an ArrayList would satisfy all of your requirements.

Related

Is there a data structure in Java that can hold 4 or more values

Is there a data structure in Java which can hold more than 4 values?
So something along the lines of
Map<String, String, String, String>;
This is needed to be able to reduce the number of if else statements I have. I would like to be able to do the following.
check if the data structure contains an element which matches a certain value, if it does then it assigns a link(which is string) to a variable and then adds a code and message to another variable which is related to that link.
if not is there a good workout around to achieve this?
Is there a data structure in Java which can hold more than 4 values?
There are lots of them.
The simplest is probably String[] which can hold 4 strings if you instantiate it like this:
new String[4]
And other Answers give other data structures that might meet your actual (i.e. unstated) requirements.
However, it is probably possible ... let alone sensible ... for us to enumerate all of the possible data structures that can meet your stated requirement.
Hint: you should try to explain how this data structure needs to work.
Hint 2: "the lines of Map<String, String, String, String>" does not help us understand your real requirement because we don't know what you mean by that.
UPDATE - Your explanation is still extremely vague, but I think you need something like this:
Map<String, MyRecord>;
public class MyRecord {
private String link;
private String code;
private String message;
// add constructor, getters, setters as required
}
There is nothing in the standard libraries, but Guava has a nice implementation; called
Multimap
If Guava is not an option in your environment, you will have to re-invent the wheel though.
Use can use MultiMap on Apache,
A MultiMap is a Map with slightly different semantics. Putting a value into the map will add the value to a Collection at that key. Getting a value will return a Collection, holding all the values put to that key
MultiMap mhm = new MultiValueMap();
mhm.put(key, "A");
mhm.put(key, "B");
mhm.put(key, "C");
Collection coll = (Collection) mhm.get(key);
Use Map of map:
Map<String, Map<String, Map<String, String>>>
Reading your question, It seams like you simply need a 'key-value' pair. Key being a 'String', which you have referred as 'a certain value' in your question. Value is a kind of wrapper object wrapping three Strings which you have referred as 'link, code and message'.
I suggest you can simply use
HashMap < String, Wrapper > map;
You can create a class ' Wrapper.java' which can contain three Strings, as instance fields
String link,code,message;
You can instantiate these fields in constructor and later can retrieve them using getter methods or also can have setters to set the values you need. You can provide a better contextual name to the class 'Wrapper.java'.

Java - store name field by using hashmap vs using seperate class

If I need to capture the name (first, middle and last) of a Person, I thought of the following possibilities:
Use a Map<String, String> name;
Use a separate Name class.
If I use a Map, I can store the names like this:
name.put("first", "xyz")
name.put("middle", "abc")
name.put("last", "nhf");
Then in the Person class:
class Person
{
Map<String, String> name;
//below write setter and getter for it.
}
If I use a Name class, I can store like this:
class Name
{
String first;
String middle;
String last;
//Below write setters and getters for them.
}
Then in the Person class:
class Person
{
Name name;
//below write setter and getter for it.
}
I wanted to know which one is a better way of doing and why. Also if there is any other better way of doing this.
Maps are great for flexibility. I.e., if you don't know exactly what keys you're going to have. E.g., if one person will have a Christian name, another will have a nickname and a third will have a paternal and maternal surnames, a Map may make sense. In your example, everybody has a first, middle and last name (although some of them may possibly be null?), so a map just adds redundant complication (as as noted here on the thread, memory consumption). Frankly, unless you have some special use for the entire Name as an object (e.g., using it as a key in a map), I'd just place three string members directly in the Person class.
This is entirely up to you -- there is no "best" answer here. It depends on how you are using the class.
Generally you do not want to hide things in a map like that. It makes more work to ensure things are correct. What if you accidentally add an incorrect key to the map? Your data structures could get out of whack easily with that method.
Personally, I would most likely just have the 3 values on the Person class directly and not bother with a Name class or a Map.
Once again, I am using words like "most likely" and "generally" because I do not know how the class is being used.
Creating a map is quite memory consuming, compared to creating a name class.
It's better to create the name class, (for one thing, less lines of code :P), mainly because it's less prone to be changed mid-run, unlike the map.
The entries in a map might be accidentally changed during runtime, which could cause problems. If the Name class doesn't have setters, then this can't happen.

Java Map with container object keys, lookup by container object field value?

Let's say I have a simple Java object, let's call it DefinedData. It will contain a number of final fields of varying types, such as strings, integers, enums, and even perhaps a set or two of strings. All in all, it's just a relatively simple data container. There will be potentially 1k to 2k of these, all static final objects. Most of these fields will be unique in that no other DefinedData object will have the same value for that field.
These will be placed into a Map of (DefinedData, Object). Now, you could easily get that Object out of the Map if you have the DefinedData object, but what if you only have one of the unique field values? You can't just pass that to the Map. You'd have to iterate over the keys and check, and that would mean wrapping the map with a lookup method for each field in DefinedData. Doable, but not the prettiest thing out there, especially if there are a lot of values in the Map and a lot of lookups, which is possible. Either that or there would need to be a lookup for DefinedData objects, which would again be a bunch of Maps...
This almost sounds like a job for a database (look up based on any column), but that's not a good solution for this particular problem. I'd also rather avoid having a dozen different Maps, each mapping a single field from DefinedData to the Object. The multikey maps I've seen wouldn't be applicable as they require all key values, not just one. Is there a Map, Collections, or other implementation that can handle this particular problem?
The only way to avoid having multiple maps is by iterating through all your DefinedData objects in some way. Reason being, you have no way of knowing how to divide them out or sort them until the request is made.
An example could be made if you had a bucket of apples. At any moment someone may come up and request a certain color, a certain kind, or a certain size. You have to choose to sort by one of those categories, and the other categories have to be searched through all the apples.
If only you could have three identical sets of apples; one for each category.
Having multiple maps would be a faster solution, though take up more memory, while iterating would be easier to achieve, slower, and use less memory.
I hesitate to propose this, but you could encapsulate your lookups behind some sort of Indexer class that auto-generates a single map via reflection using the fields of supplied objects.
By single map, I mean just one single map for the whole indexer which creates a key based on both the field name and data (say concatenating the string representing the field name with a string representation of the data).
Lookups against the indexer would supply both a field name and data value, which would then be looked up in the single map encapsulated by the indexer.
I do not think this necessarily has any advantage over a similar solution where the indexer is instead backed by a map of maps (map of field name to map of data to object).
The indexer could also be designed to use annotations so that not all fields are indexed, only those suitably annotated (or vice-versa, with annotations to exclude fields).
Overall, a map of map solutions strikes me as easier since it cuts out the step of complicated key assembly (which could be complicated for certain field data types). In either case, encapsulating it all in an Indexer that auto-generates its maps seems to be the way to go.
Update:
Made a quick non-generified proof of concept for an Indexer type class (using the map of maps approach). This is in no way a finished work, but illustrates the concept above. One major deficiency being the reliance on beans, so both public and private fields without accessor methods are invisible to this indexer.
public class Indexer
{
private Map<String,Map<Object,Set<Object>>> index = new HashMap<String,Map<Object,Set<Object>>>();
// Add an object to the index, all properties are indexed.
public void add(Object object) throws Exception
{
BeanInfo info = Introspector.getBeanInfo(object.getClass());
PropertyDescriptor[] propertyDescriptors = info.getPropertyDescriptors();
for (PropertyDescriptor descriptor : propertyDescriptors)
{
String fieldName = descriptor.getName();
Map<Object,Set<Object>> map = index.get(fieldName);
if (map == null)
{
map = new HashMap<Object,Set<Object>>();
index.put(fieldName, map);
}
Method method = descriptor.getReadMethod();
Object data = method.invoke(object);
Set<Object> set = map.get(data);
if (set == null)
{
set = new HashSet<Object>();
map.put(data, set);
}
set.add(object);
}
}
// Retrieve the set of all objects from the index whose property matches the supplied.
public Set<Object> get(String fieldName, Object value)
{
Map<Object,Set<Object>> map = index.get(fieldName);
if (map != null)
{
Set<Object> set = map.get(value);
if (set != null)
{
return Collections.unmodifiableSet(set);
}
}
return null;
}
}

How to structure data that can be both indexed and sorted on different keys?

I'd like to maintain a set of data that has two main attributes: 1. I can quickly look up the existence of an object by a numerical ID, and 2. I want to sort the data, but avoid needlessly sorting it since it can be slow. For a more concrete example, I have a set of user data, where each user has a unique ID (an int) and a unique username (a String). I'll be adding and removing users, and occasionally I want to generate a human-readable, alphabetically-sorted list to the user, but as my number of users increases, so does the time needed to sort the data.
How would you structure this? The only reasonable approach I can think of involves creating two separate data structures, and redundantly add/remove items to BOTH structures at the same time. As my data grows, it will be using more data than a single structure would. I might also introduce more bugs this way, as I have to remind myself to duplicate the operations to both structures when I come back to add to the code later. In other words, I could have:
TreeMap<String,Integer> nameSortedMap = new TreeMap<String,Integer>(String.CASE_INSENSITIVE_ORDER);
and
Map<Integer,String> idMap = new HashMap<Integer,String>();
Whenever I add or remove data, I do it on both maps. If I am retrieving a username by ID, I'd call idMap.get(id) or idMap.contains(id) (to see if a user exists). On the other hand, if I need to display a sorted list, I would use nameSortedMap.keySet(), which I gather should already be in name order, avoiding the need for additional work each time a sorted list is needed.
How's my thought process? Is there a better or simpler way to accomplish this? Thank you!
There are two ways I can think of:
Use a database and index both columns. Databases are fast, and can be very small (see: SQLite), but they're probably overkill if you don't need to save the data, or if this is the only thing you would use it for.
Create a class containing both of your maps above, which handles all inserting and deleting. That way, you only have one place where you have to remember to do operations on both. This is one of the major selling points for object oriented programming.
If you dont call the ordered list very often I dont think would be necessary to keep two maps, but if you prefer to do that. I would suggest you to create one class thtat extend the HashMap and implement the methods to handle both maps. Example:
public class UserMap extends HashMap<Integer, String> {
TreeMap<String, Integer> nameSortedMap = new TreeMap<String, Integer>(String.CASE_INSENSITIVE_ORDER);
#Override
public String put(Integer key, String value) {
String put = super.put(key, value);
nameSortedMap.put(value, key);
return put;
}
#Override
public String remove(Object key) {
String toRemove = get(key);
if (toRemove != null) {
remove(key);
getOrderedName().remove(toRemove);
}
return toRemove;
}
public Set<String> getSortedNames() {
return nameSortedMap.keySet();
}
}

A hash Map in which on of the value object's fields is the key?

I was wondering if there was an class like HashMap in which the key is an identifying field in the object.
If there is not, I was thinking about having the class I use as the value implement Map.Entry. Does this seem like a reasonable approach or does that seem dangerous? (I'll make my key field immutable.)
I was thinking about having the class I use as the value implement Map.Entry. Does this seem like a reasonable approach or does that seem dangerous?
Dangerous or not, it is bad design since it violates the single-responsibility principle. A class should not be responsible for doing its own stuff, and also being a Map.Entry. What happens when you now want to use it in another library? Do you have to implement another interface?
While it's unclear to me what you hope to gain by implementing Map.Entry (are you trying to extend AbstractMap?), I can tell you this smells bad to me and I have never seen it done in practice.
What's the actual issue here? What's wrong with using a HashMap?
Map<String, MyClass> map = new HashMap<String, MyClass>();
MyClass myObj = new MyClass("myId");
//...
map.put(myObj.getIdentifier(), myObj);
MyClass retrievedObj = map.get("myId");
When you add objects (or classes) to the hashmap, you select the key feild being sent to the map. Just make a getKey() method inside your class which will return your desired key.
Then use it when inserting an object to the map
For example, if you have a Person Class with ID (String) as key. Make this function:
public String getKey()
{
return this.Id; //Or use the getter method
}
And use it when inserting the Person object to the map:
Person1.getKey();
You could always use HashMap and add the field as the key (if you were going to make it immutable anyway, i don't see any problem with that).
It's the HashMap itself. Just make sure that the "identifying field" in the object properly implements the equals() and hashCode() methods.
e.g. If your class is:
public class YourObject {
private String identifyingField;
Then:
Map<String, YourObject> yourMap = new HashMap<String, YourObject>();

Categories