Nested map structure - java

I have a map defined like this:
Map<Long, Long> foo = new TreeMap<Long, Long>();
For each entry into the map, I also want to map those entries to a Boolean. How can I do this? This is what I tried so far but it doesn't look right. What I want to achieve is that for every entry in mask, there should be a corresponding Boolean value that it is assigned to.
Map<Long, Boolean> mask = new HashMap<Long, Boolean>();
SortedMap<Long, Map<Long, Boolean>> pairs = new TreeMap<Long, Map<Long, Boolean>>();
mask.put(new Long(2), Boolean.FALSE);
mask.put(new Long(3), Boolean.FALSE);
mask.put(new Long(3), Boolean.FALSE);
pairs.put(new Long(1), new Long(2));
pairs.put(new Long(1), new Long(3));
pairs.put(new Long(2), new Long(3));
The constraint is that I can only use the built-in types. I had a solution before which had a custom object which allowed me to easily achieve this but due to the project design, I cannot create new types.

Create a class that encapsulates both values and make a map of that:
class Pair {
public final boolean booleanValue;
public final long longValue;
public Pair(boolean booleanValue, long longValue) {
this.booleanValue = booleanValue;
this.longValue = longValue;
}
}
Map<Long,Pair> map = new HashMap<>();
map.put(1L, new Pair(false, 123));
map.put(2L, new Pair(true, 456));
map.put(3L, new Pair(false, 789));
Or use two maps having the same keys:
Map<Long,Boolean> map1 = new HashMap<>();
Map<Long,Long> map2 = new HashMap<>();
map1.put(1L, false); map2.put(1L, 123L);
map1.put(2L, true); map2.put(2L, 456L);
map1.put(3L, false); map2.put(3L, 789L);

If I understand you, you want to map both a Long and a Boolean to the same key entry?
If that's the case, and you can't create your own custom objects, you just need to have two maps:
Map<Long, Long> pairs = new HashMap<Long, Long>();
Map<Long, Boolean> mask = new HashMap<Long, Boolean>();
Then just use the same key entry for both:
pairs.put(1L, 5L);
mask.put(1L, false);
pairs.put(2L, 20L);
mask.put(2L, true);
and so on.

Create a new object that has a Long and Boolean and that object put into the map.

What about a holder ?
private class MyHolder
{
public Boolean boolValue;
public Long longValue;
}
Map<Long, MyHolder> myMap = new HashMap<Long, MyHolder>();
MyHolder h = new MyHolder();
h.boolValue = true;
h.longValue = 1L;
myMap.put(1L, h);

Related

Java HashMap used like Python Dictionary

I want to order information about events I got as HTML from a website (Category, multiple events in that category, information about one specific event) in a big HashMap and what I tried looks like this:
HashMap categoryMap = new HashMap();
HashMap eventMap = new HashMap();
HashMap singleEventMap = new HashMap();
categoryMap.put(eventCategory, eventMap);
eventMap.put(eventTitle, singleEventMap);
singleEventMap.put("starttime", eventTime);
singleEventMap.put("location", eventLocation);
singleEventMap.put("description", eventDescription);
I`m used to python dictonaries and can't find, how I can add another event to the category or how I can access the stored information in Java.
I would be glad if anyone could give me a code example or a link with a similar problem or a good explanation.
1) Do not use raw generic types.
Always specify the type arguments. You should also program to the interface. E.g.
Map<String, Map<String, Map<String, Object>>> categoryMap = new HashMap<>();
Map<String, Map<String, Object>> eventMap = new HashMap<>();
Map<String, Object> singleEventMap = new HashMap<>();
2) Java is an Object-Oriented language, use it.
E.g. create an Event class with fields starttime, location, and description.
public class Event {
private final LocalDateTime starttime;
private final String location;
private final String description;
public Event(LocalDateTime starttime, String location, String description) {
this.starttime = starttime;
this.location = location;
this.description = description;
}
public LocalDateTime getStarttime() {
return this.starttime;
}
public String getLocation() {
return this.location;
}
public String getDescription() {
return this.description;
}
}
Then use:
Map<String, Map<String, Event>> categoryMap = new HashMap<>();
Map<String, Event> eventMap = new HashMap<>();
3) To add another event:
Create another instance of singleEventMap, add the properties and add it to the eventMap.
Your way:
HashMap categoryMap = new HashMap();
HashMap eventMap = new HashMap();
categoryMap.put(eventCategory, eventMap);
Map singleEventMap = new HashMap();
eventMap.put(eventTitle1, singleEventMap);
singleEventMap.put("starttime", starttime1);
singleEventMap.put("location", location1);
singleEventMap.put("description", description1);
singleEventMap = new HashMap();
eventMap.put(eventTitle2, singleEventMap);
singleEventMap.put("starttime", starttime2);
singleEventMap.put("location", location2);
singleEventMap.put("description", description2);
The Java way:
Map<String, Map<String, Event>> categoryMap = new HashMap<>();
Map<String, Event> eventMap = new HashMap<>();
categoryMap.put(eventCategory, eventMap);
eventMap.put(eventTitle1, new Event(starttime1, location1, description1));
eventMap.put(eventTitle2, new Event(starttime2, location2, description2));
Or if they have different categories:
Map<String, Map<String, Event>> categoryMap = new HashMap<>();
Map<String, Event> eventMap1 = new HashMap<>();
categoryMap.put(eventCategory1, eventMap1);
eventMap1.put(eventTitle1, new Event(starttime1, location1, description1));
Map<String, Event> eventMap2 = new HashMap<>();
categoryMap.put(eventCategory2, eventMap2);
eventMap2.put(eventTitle2, new Event(starttime2, location2, description2));

Java Hashmap to JavaFX Treeview and Back?

I have a nested HashMap which looks like this:
Map<String,Object> myMap = new HashMap<String,Object>();
This myMap is nested, Like:
String key => String val
String key => String val
String key => Map<String,Object> val
And then that value may contain another similar Map<String,Object>.
I do not expect it to be nested more than 3 levels.
The leafs or last values are always String.
Now I'm trying to make a way to edit this HashMap in a JavaFX GUI.
From what I have learnt so far,
the best way seems like making a editable JavaFX TreeView
and somehow translating the Map to a TreeView and back.
So far I'm thinking
TreeMap<String, Object> treeMap = new TreeMap<String, Object>();
treeMap.putAll(myMap);
And then somehow translating that TreeMap to a JavaFX TreeView.
But I can not figure out how to proceed.
Another headache is that after user edits I need to translate it all back to a HashMap such as the original myMap. Although sorting / sequence is not required.
Create a suitable class to represent the map entry. Since you need to modify the Map, you need to store key and Map in that class.
If you use TextFieldTreeCell as cell type, the StringConverter can be used to modify the source data structure on a edit:
private static TreeItem<MapItem> createTree(Map<String, Object> map) {
TreeItem<MapItem> result = new TreeItem<>();
for (Map.Entry<String, Object> entry : map.entrySet()) {
result.getChildren().add(createTree(map, entry));
}
return result;
}
private static TreeItem<MapItem> createTree(Map<String, Object> map, Map.Entry<String, Object> entry) {
MapItem mi = new MapItem(map, entry.getKey());
TreeItem<MapItem> result = new TreeItem<>(mi);
Object value = entry.getValue();
if (value instanceof Map) {
Map<String, Object> vMap = (Map<String, Object>)value;
// recursive creation of subtrees for map entries
for (Map.Entry<String, Object> e : vMap.entrySet()) {
result.getChildren().add(createTree(vMap, e));
}
} else {
result.getChildren().add(new TreeItem<>(new MapItem(null, value.toString())));
}
return result;
}
private static class MapItem {
private final Map<String, Object> map;
private final String value;
public MapItem(Map<String, Object> map, String value) {
this.map = map;
this.value = value;
}
}
private static class Converter extends StringConverter<MapItem> {
private final TreeCell<MapItem> cell;
public Converter(TreeCell<MapItem> cell) {
this.cell = cell;
}
#Override
public String toString(MapItem object) {
return object == null ? null : object.value;
}
#Override
public MapItem fromString(String string) {
MapItem mi = cell.getItem();
if (mi != null) {
TreeItem<MapItem> item = cell.getTreeItem();
if (item.isLeaf()) {
MapItem parentItem = item.getParent().getValue();
// modify value in parent map
parentItem.map.put(parentItem.value, string);
mi = new MapItem(mi.map, string);
} else if (!mi.map.containsKey(string)) {
// change key of mapping, if there is no mapping for the new key
mi.map.put(string, mi.map.remove(mi.value));
mi = new MapItem(mi.map, string);
}
}
return mi;
}
}
#Override
public void start(Stage primaryStage) {
Map<String, Object> map = new HashMap<>();
map.put("a", "b");
Map<String, Object> inner = new HashMap<>();
map.put("c", inner);
inner.put("d", "e");
Map<String, Object> inner2 = new HashMap<>();
inner.put("f", inner2);
inner2.put("g", "h");
inner2.put("i", "j");
TreeView<MapItem> treeView = new TreeView<>(createTree(map));
treeView.setEditable(true);
treeView.setShowRoot(false);
treeView.setCellFactory(t -> {
TextFieldTreeCell<MapItem> cell = new TextFieldTreeCell<>();
cell.setConverter(new Converter(cell));
return cell;
});
Button btn = new Button("Print Map");
btn.setOnAction((ActionEvent event) -> {
System.out.println(map);
});
VBox root = new VBox(10, btn, treeView);
Scene scene = new Scene(root);
primaryStage.setScene(scene);
primaryStage.show();
}
There is not build-in method that would convert:
either Map directly to TreeView
or TreeMap to TreeView
Moreover, If you see the structure of Map<?,?>, we can see that it is a combination of key, value pair whereas TreeView<?> consists of only value, like that of Collection interface. So It's not possible to insert key, value pair in TreeView. However you can insert only values from Map.
The best you can do is define a new data structure like this:
public class YourCustomDataStructure extends TreeItem<String> {
...
/*
Now you can define methods that will convert `List`s directly to `YourCustomDataStructure`.
You can even define method to convert `Map` values to `YourCustomDataStructure`.
*/
public boolean addAll(Map map) {
//your implementation to convert map to TreeItem
}
public boolean addAll(List list) {
//your implementation to convert list to TreeItem
}
}
Now convert your list or map to YourCustomDataStructure using addAll() method from previous step.
List<Object> list = getListFromSomewhere();
YourCustomDataStructure<String> customList = new YourCustomDataStructure<String>("customList Node");
customList.getChildren().addAll(list);
Now since YourCustomDataStructure extends TreeItem so it's object's can be directly passed to TreeView's constructor and they will be automatically converted to TreeView.
TreeView<String> treeView = new TreeView<String>(customList);
P.S.: I know defining new data structure and all the methods will require lots of efforts at initial level, but once those methods are defined, then it will become too easy to convert TreeView to Map and vice versa.

Cannot instantiate Map<String, ? extends Object> map = new TreeMap<String, ? extends Object>();

I am trying to create a TreeMap with a generic type but I am unable to. I am doing this because my map can like these:
Map<String, QueryTerm> terms = new TreeMap<String, QueryTerm>();
Map<String, String> params = new TreeMap<String, String>();
So instead of creating multiple functions to handle the maps with different types I want to create one which both types.
How can I do this and what am I doing wrong?
Function:
private Map<String, ? extends Object> setDatumMap(UserSession session, String parameterName)
{
Map<String, ? extends Object> map = new TreeMap<String, ? extends Object>();
//Get comma delimited list of filter keys. Split them and use them to retrieve associated values.
String sFilters = (String) session.getAttribute(parameterName);
String[] filterList = sFilters.split(",");
for(String filterName : filterList)
{
String filterValue = (String) session.getAttribute(filterName);
if (filterValue != null && !filterValue.isEmpty())
{
filter.put(filterName, setQueryTermList(filterValue, ListType.BOOLEAN_LIST));
}
}
return filter;
}
You should simply instantiate the map like so:
Map<String, Object> map = new TreeMap<String, Object>();
You can't instantiate using a wildcard, and it's not necessary unless you expect that the compiler will cast to the appropriate class by guessing what value you are going to get. We didn't get there yet.
you need to change you this line :
private Map<String, ? extends Object> setDatumMap(UserSession session, String parameterName)
{
Map<String, ? extends Object> map = new TreeMap<String, ? extends Object>();
//rest of your code
To
private Map<String, Object> setDatumMap(UserSession session, String parameterName)
{
Map<String, Object> map = new TreeMap<String, Object>();
//rest of your code.
This will work.

Sorting a list of maps

I have a list of maps
List<Map<String, Object>> people = new ArrayList<Map<String,Object>>();
that gets populated like so
map.put("firstName",John);
map.put("lastName",Smith);
map.put("type","1"); //type is either 1 or a 0
people.add(map);
and what I want to do with this list after it gets populated is so have all the people as type 0 at the top of the list and all with type 1 at the bottom.
I know I need to use a Comparator but I have never used one before so I dont know how to use one or how it works.
Could someone help me out
Like this
Collections.sort( people, new Comparator<Map<String, Object>>() {
#Override
public int compare( Map<String, Object> o1, Map<String, Object> o2 ) {
return (Integer.parseInt((String)o1.get( "type" ))) -
(Integer.parseInt((String)o2.get( "type" )));
}
} );
However, there are many ways to make this better. If you cannot use a Person object to represent the map as suggested by #Pshemo, then at least, use a reasonable data type for your type attribute. The best would be an enum:
public enum PersonType {
TYPE_1, TYPE_2
}
Then the comparisons are much cleaner and faster and much more readable.
Comparator is just an interface that needs to be implemented, it contains only one method that needs to be overriden.
For example:
List<Map<String, Object>> people = new ArrayList<Map<String,Object>>();
Map<String, Object> map = new HashMap<String, Object>();
map .put("firstName","John");
map.put("lastName","Smith");
map.put("type","1"); //type is either 1 or a 0
people.add(map);
Collections.sort(people, new Comparator<Map<String, Object>>() {
#Override
public int compare(Map<String, Object> o1, Map<String, Object> o2) {
// you may compare your map here
return 0;
}
});
Try this
Collections.sort(people, new Comparator<Map<String, String>>() {
#Override
public int compare(Map<String, String> m1, Map<String, String> m2) {
return m1.get("type").compareTo(m2.get("type"));
}
});
You can try like this :
class ListByType
{
private static class MyComparator implements Comparator<HashMap<String,String>>
{
#Override
public int compare(HashMap mp1 , HashMap mp2)
{
return ((String)(mp1.get("type")).compareTo((String)mp2.get("type"));
}
}
public static void main(String[] args)
{
List<Map<String, String>> people = new ArrayList<Map<String,String>>();
HashMap<String,String> map = new HashMap<String,String>();
map.put("firstName","John");
map.put("lastName","Smith");
map.put("type","1"); //type is either 1 or a 0
people.add(map);
/*...
..
...
Add more maps here..
*/
//Sort the list
Collections.sort(people,new MyComparator());
}
}

TreeMap construtor

I'm having some problems with TreeMap constructors. I have a class with 2 TreeMap<String, Client> inside it. A tree sorted by name and another sorted by number.(Client class : String name, int number, ...)
private TreeMap<String, Client> nameTree;
private TreeMap<Integer, Client> numberTree;
How do I build the constructors for this class? So far I wrote this:
public ManagerTreeMap(){
nameTree = new TreeMap<String, Client>(new StringComparator());
numberTree = new TreeMap<Integer, Client>(new IntegerComparator());
}
My major problem is the construtor "TreeMap(Comparator c)". Can i write two comparators? if not what do I have to do?
public ManagerTreeMap(Comparator<String> cp){
nameTree = new TreeMap<String, Client>(cp);
}
public ManagerTreeMap(Comparator<Integer> cpt){
nameTree = new TreeMap<Integer, Client>(cpt);
}
It seems that you don't need custom comparators.
public ManagerTreeMap(){
nameTree = new TreeMap<String, Client>();
numberTree = new TreeMap<Integer, Client>();
}
Maybe
public ManagerTreeMap(Comparator<String> cs, Comparator<Integer> ci){
nameTree = new TreeMap<String, Client>(cs);
numberTree = new TreeMap<Integer, Client>(ci);
}

Categories

Resources