My json file looks like this [actually it has more, I am just putting 2 blocks for example]
[{
"answerValue": "2021-02-01",
"parentId": "Policy",
"instance": 1,
"fieldId": "PolicyEffectiveDate"
},
{
"answerValue": "2012",
"parentId": "Insured",
"instance": 1,
"fieldId": "DateBusinessStarted"
}
]
I want to store them in a HashMap and print them.
public void MapCheck() {
Map<String, Object> dataMap = new HashMap<>();
List<Map> lstMap = new ArrayList<>();
dataMap.put("answerValue:", "2021-02-01");
dataMap.put("parentId:", "Policy");
dataMap.put("instance:", 1);
dataMap.put("fieldId:", "PolicyEffectiveDate");
lstMap.add(dataMap);
dataMap.put("answerValue:", "Assurestart LLC");
dataMap.put("parentId:", "Insured");
dataMap.put("instance:", 1);
dataMap.put("fieldId:", "Business_Name");
lstMap.add(dataMap);
System.out.println(lstMap);
}
public static void main(String[] args) {
Test t = new Test();
t.MapCheck();
}
}
Expected: I wanted it to print
[{parentId:=Policy, fieldId:=PolicyEffectiveDate, answerValue:=2021-02-01, instance:=1}, {parentId:=Insured, fieldId:=Business_Name, answerValue:=Assurestart LLC, instance:=1}]
Actual: It is printing, the last value twice.
[{parentId:=Insured, fieldId:=Business_Name, answerValue:=Assurestart LLC, instance:=1}, {parentId:=Insured, fieldId:=Business_Name, answerValue:=Assurestart LLC, instance:=1}]
How can I make it print 2 different values? Thanks in advance for your time and ideas.
You should create a new map for the second entry instead of overwriting the first entry’s values. Add
dataMap = new HashMap<>();
After adding the first entry to the list.
You should create a new map for the second map in the list:
Map<String, Object> dataMap = new HashMap<>();
List<Map<String, Object>> lstMap = new ArrayList<>();
dataMap.put("answerValue:", "2021-02-01");
dataMap.put("parentId:", "Policy");
dataMap.put("instance:", 1);
dataMap.put("fieldId:", "PolicyEffectiveDate");
lstMap.add(dataMap);
dataMap = new HashMap<>(); // create a new map!
dataMap.put("answerValue:", "Assurestart LLC");
dataMap.put("parentId:", "Insured");
dataMap.put("instance:", 1);
dataMap.put("fieldId:", "Business_Name");
lstMap.add(dataMap);
That said, if you actually want to generate JSON, or read a JSON file, I recommend using a JSON serialisation/deserialisation library, such as GSON. That way, you can represent your data not as hash maps, but a class like this:
class MyObject {
private String answerValue;
private String parentId;
private int instance;
private String fieldId;
// getters & setters...
}
HashMap as you know is a data structure that works based on unique key and value pair property.
In the example above when you perform dataMap.put("answerValue:", "2021-02-01"); it saves the value for this key in the HashMap. However when you perform, dataMap.put("answerValue:", "Assurestart LLC"); the second time, it will override the value of "answerValue:" key as it already exists there.
A better approach is to create a new class that can contain all this data in it and then you can decide on a unique key to store this data in. Thus your values will be an object that contains this entire block of data.
For example,
public class MyData {
private String answerValue;
private String parentId;
private Integer instance;
private String fieldId;
//Setters and getters
...
}
Related
I am wondering how to build a nested Map and then retrieve the nested key:value pairs. This is how I created the map to be nested.
//Create List of Nested HashMaps
List<Map> nestedMap = new ArrayList<>();
nestedMap.add(building3Map);
nestedMap.add(building31Map);
nestedMap.add(buildingHFTFMap);
System.out.println("The nested map is: " + nestedMap);
This is the system output for the following code:
The nested map is: [{buildingname=[Building 3], buildingid=[3]}, {buildingname=[Building 31], buildingid=[1]}, {buildingname=[HFTF], buildingid=[4]}]
This is correct as I want a list of maps. But the next step is what is confusing to me. When I try to build the outer layer Map as below:
HashMap<String, List<Map>> queryMap = new HashMap<>();
queryMap.put("buildings", nestedMap);
System.out.println(queryMap.get("buildings.buildingid"));
I get a system output of null when attempting the .get("buildings.buildingid") method. Ideally, I need the output to look like this:
[[3, 1, 4]]
Where it returns all values with a key of "buildings.buildingid" in an array. I am new to coding so please let me know if I'm making any fundamental errors and how I can create a nested Map where I can access the inner layer or if there is another method I should be using.
I think you are making it way too complicated than it should be. you can store your data in a simple map where the ids are the keys for example and the names are the values. So you only need to read the keys or the values from the map to get your result.
Map<Integer, String> myMap = new HashMap<>();
myMap.put(3, "Building 3");
myMap.put(31, "Building 31");
myMap.put(4, "HFTF");
System.out.println(myMap.keySet());
System.out.println(myMap.values());
However, Java is an object-oriented language. If it makes sense for your use case you might want to create a custom class "Building" instead of frantically trying to store your data in nested data structures. See below for an example of how it might look using a custom class:
import java.util.ArrayList;
import java.util.List;
public class Example {
public static void main(String args[]) {
List<Building> buildings = new ArrayList<>();
buildings.add(new Building(3, "Building 3"));
buildings.add(new Building(31, "Building 31"));
buildings.add(new Building(4, "HFTF"));
List<Integer> buildingIds = new ArrayList<>();
buildings.forEach(building -> buildingIds.add(building.getBuildingId()));
List<String> buildingNames = new ArrayList<>();
buildings.forEach(building -> buildingNames.add(building.getBuildingName()));
System.out.println(buildingIds);
System.out.println(buildingNames);
}
public static class Building {
int buildingId;
String buildingName;
public Building(final int buildingId, final String buildingName) {
this.buildingId = buildingId;
this.buildingName = buildingName;
}
public int getBuildingId() {
return buildingId;
}
public void setBuildingId(final int buildingId) {
this.buildingId = buildingId;
}
public String getBuildingName() {
return buildingName;
}
public void setBuildingName(final String buildingName) {
this.buildingName = buildingName;
}
}
}
queryMap.get("buildings.buildingid") returns null, because queryMap only contains a value under the key
buildings. A HashMap can only access the value using the same key it was stored under. The key and the value is not processed in any further way.
A simple alternative could be
queryMap.get("buildings").stream() // Create a Stream<Map>
.map(building -> building.get("buildingid")) // Create Stream<String> by extracting the buildingid values.
.collect(Collectors.toList()); // Collect Stream into a List<String> which contains the buildingid's
If you don't like this solution you could take a deeper look into property expressions, and write your own map implementation that can resolve these expressions. But it will be a lot of work to get it working correctly...
I'm having a BiMap with a String as key and an array of Strings as value.
Now i'm trying to get with a single String (which is part of the value array) the key.
private static BiMap<String, String[]> map = ImmutableBiMap.<String, String[]>builder().build();
static {
map.put("000", new String[] {"CH", "CHE", "Switzerland"});
map.put("001", new String[] {"US", "USA", "United States of America"});
map.put("002", new String[] {"IT", "ITA", "Italy"});
}
And in the next method i'm trying to search with "CH" to get "000" (which does not work).
private static String getKey(Map<String,String[]> map, String find) {
Map<String[], String> inversedMap = map.inverse();
if(inversedMap.containsKey() {
return inversedMap.get(find);
}
return null;
}
Is there a way to 'find' the key like this, without that i need to search with an array like this: String[] find = new String[] {"CH", "CHE", "Switzerland"};
All the values and keys are unique, so there is expected only a single result.
And i'm searching always for the first value in the array, f.ex. "CH" or "US".
No, there is no way to find the key like you want. You have to either change the way you store the data to support all the different lookup method you need or go through all keys one by one (at which point making an inverse map makes no sense an you can just go through the Map entries).
A trivial approach would be a purpose built class that contains several maps.
In case you have a case to find smth. by value (not by key) then you could use for loop in case you do not worry about performance. Otherwise, you should wrap this BiMap with a wrapper and add addtional Map with val -> key:
public final class CountryCache {
private final Map<String, String[]> codeNames = new HashMap<>();
private final Map<String, String> nameCode = new HashMap<>();
{
codeNames.put("000", new String[] { "CH", "CHE", "Switzerland" });
codeNames.put("001", new String[] { "US", "USA", "United States of America" });
codeNames.put("002", new String[] { "IT", "ITA", "Italy" });
codeNames.forEach((code, names) -> Arrays.stream(names).forEach(name -> nameCode.put(name, code)));
}
private static final CountryCache INSTANCE = new CountryCache();
public static CountryCache getInstance() {
return INSTANCE;
}
private CountryCache() {
}
public String findByName(String name) {
return nameCode.get(name);
}
}
I have a map as shown below in which there is a key and values is of type List:
Map<String, List<String> newdatamap = new HashMap<>();
map.put ("RtyName", Arrays.asList("wpn", "wpfnb", "dgeft", "xbthy"));
map.put ("rtyRate", Arrays.asList("dd", "ww", "trrty", "httyure"))
I'd like to add another map over the previous map, such that there is a key and its value will be the above map. Is this the correct data structure, and how do we implement it?
I want something like this shown below
Key Value
B1 RtyName ----> "weepn", "weepfnb", "eedgeft", "xbteehy"
rtyRate ----->"deed", "ww", "terrty", "hteetyure"
B2 RtyName ----> "SSSweepn", "wpefSSSnb", "GGeGdgeft", "xbteYYYYhy"
rtyRate ----->"WWded", "wTeTYw", "YYYYtrerty", "IIIehttyure"
As shown above, only a new key is been introduced to the map, and its value is the previous map.
so it is like a Map<String, Map<String, List<String>>> whis becomes a complex data structure can i organise the data structure as
for example one class containing a Map, so it will be like
Map<B1 , RtyName>
Map<B2 ,rtyRate>
and payer nae contain list of values such as
RtyName ----> "SSSweepn", "wpefSSSnb", "GGeGdgeft", "xbteYYYYhy"
rtyRate ----->"deed", "ww", "terrty", "hteetyure"
so in the above structure complexity will be low since at the end for B1 i have to search key that wiil be RtyName and against payer name further i have to search values which will be "wpn", "wpfnb", "dgeft", "xbthy"
please advise whheteher map will be best or is there any other better data structure also to obtain this .
one data structure coming in my mind is of Guava's Table
final Table<String, String, List<String>> values = HashBasedTable.create();
values.put("B1", "RtyName", Lists.newArrayList("weepn", "weepfnb", "eedgeft", "xbteehy"));
System.out.println(values.get("B1", "RtyName")); // prints the list
My objective is that any data structure I can have in which against B1 I will get Rtyname and for Rtyname I will get possible list of values
I would do this:
Map<Integer, List<String>> dataMap = new HashMap<>();
dataMap.put("B1".hashCode()+"RtyName".hashCode(), Arrays.asList("weepn", "weepfnb", "eedgeft", "xbteehy"));
dataMap.put("B1".hashCode()+"rtyRate".hashCode(), Arrays.asList("deed", "ww", "terrty", "hteetyure"));
dataMap.put("B2".hashCode()+"RtyName".hashCode(), Arrays.asList("SSSweepn", "wpefSSSnb", "GGeGdgeft", "xbteYYYYhy"));
dataMap.put("B2".hashCode()+"rtyRate".hashCode(), Arrays.asList("WWded", "wTeTYw", "YYYYtrerty", "IIIehttyure"));
Which would represent:
B1, RtyName ----> "weepn", "weepfnb", "eedgeft", "xbteehy"
B1, rtyRate ----->"deed", "ww", "terrty", "hteetyure"
B2, RtyName ----> "SSSweepn", "wpefSSSnb", "GGeGdgeft", "xbteYYYYhy"
B2, rtyRate ----->"WWded", "wTeTYw", "YYYYtrerty", "IIIehttyure"
Note that hashCode is just a convient function from the String class that meets my needs. You could roll your own that returns a String key (or really anything else) if you preferred.
Actually since your original method didn't require an order independent function, you could really even concatenate the String keys to use as a new key:
dataMap.put("B1"+"RtyName", Arrays.asList(/*your list here*/));
This is a little less convenient (and not as "good" programmatically) than the first method, but still much better than nesting Map classes. (And makes keys much easier to recognize when outputted than hashCode.)
Two-way Mapping
Values as Keys
If you want each List value to map to keys as well as the other way around, you need a second Map:
Map<List<String>, String> valueMap = new HashMap<>(); //New map for value->key
for(String key: dataMap.keySet()) //Get all keys
valueMap.put(dataMap.get(key), key); //Create mapping value->key
Each Item in Value as a Key
If you want each String item in the values list to map to keys as well as the other way around, you need a second Map:
Map<String, String> itemMap = new HashMap<>(); //New map for item->key mapping
for(String key: dataMap.keySet()) //Get all keys and iterate through
for(String item: dataMap.get(key)) //For each item in your value list
itemMap.put(item, key); //Create new mapping item->key
As you asked for it:
You simply define a class, ABC in this case as you've suggested that name, which holds two lists, the RtyName and the rtyRate list:
public class ABC {
private List<String> RtyName;
private List<String> rtyRate;
public ABC(List<String> RtyName, List<String> rtyRate) {
setRtyNames(RtyName);
setRtyRates(rtyRate);
}
public void setRtyNames(List<String> RtyName) {
this.RtyName = RtyName;
}
public List<String> getRtyNames() {
return this.RtyName;
}
public void setRtyRates(List<String> rtyRate) {
this.rtyRate = rtyRate;
}
public List<String> getRtyRates() {
return this.rtyRate;
}
}
Once this class is ready, you can change your map definition to:
Map<String, ABC> newdatamap = new HashMap<>();
And assign new values to it similar as you already did before - instead of nesting those lists in a further map and putting this map into the outer map though, you create a new instance of ABC, provide the two lists as input parameter and put the resulting ABC object into the map (formally the outer map):
List<String> RtyName = Arrays.asList("wpn", "wpfnb", "dgeft", "xbthy");
List<String> rtyRate = Arrays.asList("dd", "ww", "trrty", "httyure");
newdatamap.put("B1", new ABC(RtyName, rtyRate));
You could also assign those lists directly as input-parameters:
newdatamap.put("B2", new ABC(Arrays.asList("SSSweepn", "wpefSSSnb", "GGeGdgeft", "xbteYYYYhy"),
Arrays.asList("WWded", "wTeTYw", "YYYYtrerty", "IIIehttyure"));
An entry is now simply retrieved on calling get(String) as you already used to do:
ABC data = newdatamap.get("B1);
You can also retrieve one of the lists directly like:
List<String> RtyNames = newdatamap.get("B1").getRtyNames();
In my opinion this is way easier to manage and to read at the same time. On top of that, you gain also runtime-saftiness as you do not run into eventual typing errors for RtyName or rtyRate.
Update for redesign
If RtyName entries and rtyRate entries always go hand in hand, f.e. wpn is the name and dd is the assigned rate, grouping those fields together would make sense. Therefore you could refactor your code to furthermore reduce one list and introduce a new class:
public class RtyEntry {
private String name;
private String rate;
public RtyEntry(String name, String rate) {
setName(name);
setRate(rate);
}
public void setName(String name) {
this.name = name;
}
public String getName() {
return this.name;
}
public void setRate(String rate) {
this.rate = rate;
}
public String getRate() {
return this.rate;
}
}
If you now change ABC to only contain one list of RtyEntry objects like this:
public class ABC {
private List<RtyEntry> rtyEntries;
public ABC(List<RtyEntry> rtyEntries) {
this.rtyEntries = rtyEntries;
}
public ABC() {
this.rtyEntries = new ArrayList<>();
}
public void setRtyEntries(List<RtyEntry> rtyEntries) {
this.rtyEntries = rtyEntries;
}
public List<RtyEntry> getRtyEntries() {
return this.rtyEntries;
}
// convenience methods
public void addRtyEntry(RtyEntry entry) {
this.rtyEntries.add(entry);
}
}
The creation would now change to:
RtyEntry entry1 = new RtyEntry("wpn", "dd");
List<RtyEntry> entries = Arrays.asList(entry1, ...);
newdatamap.put("B1", new ABC(entries));
You can then also assign new entries like that:
newdatamap.get("B1").addRtyEntry(new RtyEntry("wpfnb", "ww"));
Retrieving entries also changed to the refactoring:
ABC data = newdatamap.get("B1");
List<RtyEntry> entries = data.getRtyEntries();
for (RtyEntry entry : entries) {
System.out.println(entry.getName() + " has a rate of: " + entry.getRate());
}
Of course you can also retrieve the list directly via:
List<RtyEntry> entries = newdatamap.get("B1").getRtyEntries();
as before.
// Facility table attributes to be read in json format
String facilityName[], recApp[], recFacility[], sendApp[],
sendFacility[], enable[], doneness[], retryLimit[],
watchDelay[], retryDelay[], ackTimeout[],
keepConOpen[], sendTimeout[], cleanupDelay[],
host[], port[];
String facilityTableAttrs[][] = new String[][] {
facilityName, recApp, recFacility, sendApp,
sendFacility, enable, doneness, retryLimit,
watchDelay, retryDelay, ackTimeout, keepConOpen,
sendTimeout, cleanupDelay, host, port};
I have array of arrays called facilityTableAttrs declared as above.
I have 2 questions:
1) Is it possible to do the above array declaration in a single step ?
2) I wish to get the individual array names of these 1D array using something like:
for(i = 0; i < facilityTableAttrs.length; i++) {
System.out.println(facilityTableAttrs[i].toString());
}
but it fails. How to get the individual array names as string?
The first list of arrays you declare don't seem to be initialized anywhere.
As such they are null, and invoking toString on any of them will cause a NullPointerException to be thrown, hence "it fails".
By the way, invoking toString on an non-null array would actually print something similar to the Object.toString representation, which is not what you want (Arrays.toString(myArray) is your friend here).
You could initialize each and every single array and populate them optionally, before adding them to the main String[][] but I recommend you don't.
Instead, investigate the collections framework.
What you could use here is a Map<String, List<String>>.
Or better even, a custom object with properties such as List<String> facilityName, List<String> recApp, etc.
Finally, note the variable naming, which is camelBack according to code conventions.
This is not possible with arrays. You need to use map, like so:
Map<String, List<String>> myMap = new HashMap<String, List<String>>();
You need to choose correct data structure for your problem.
Arrays are used only for storing values, thay are not interestd in bounding names to them.
Maps on the other hands are great with bounding names (keys that are unique) to any type of value.
I propose to use a wrapper class:
public class Facility {
private final String name;
private final List<String> values;
public Facility(String name) {
this.name = name;
this.values = new ArrayList<>();
}
public String getName() {
return name;
}
public List<String> getValues() {
return values;
}
}
and then do:
Facility[] facilities = new Facility[] {
new Facility("facility 1"),
new Facility("facility 2"),
new Facility("facility 3"),
new Facility("facility 4"),
};
for(Facility facility : facilities) {
System.out.println(facility.getName());
}
To add a value to a facility you'd do:
Facility facility = facilities.get(0);
facility.getValues().add("bla");
If you need to look up facilities by name, then use a Map instead of an array:
...
// see createLookup method below
Map<String, Facility> facilities = createLookup(
new Facility("facility 1"),
new Facility("facility 2"),
new Facility("facility 3"),
new Facility("facility 4"));
// print names
for(Facility facility : facilities.values()) {
System.out.println(facility.getName());
}
// add a value
Facility facility = facilities.get("facility 3");
facility.getValues().add("bla");
}
private Map<String, Facility> createLookup(Facility.. facilities) {
// use TreeMap to have sorted keys
Map<String, Facility> lookup = new TreeMap<>();
for(Facility facility : facilities) {
lookup.put(facility.getName(), facility);
}
return lookup;
}
I have a method in which I load tiles from a text file. The tiles are placed in an array when created, so that they can be cleared later. This has began to cause problems and I am wondering if there would be a way to create an array with a name that corresponds to the text file loaded. For example, I call
loadMap("map1");
With "map1" being the name of the txt file that the map is stored in. And if I were to call the loadMap method with the argument of "map1" how can I create an array titled something like "map1TileArray", or if the argument is "finalMap" I would want an array called "finalMapTileArray". Is it possible to do something like this, and if so, how?
EDIT:
I'm getting a NPE.
I declare my Map like this:
Map<String, ArrayList<Tile>> tileMap = new HashMap<String, ArrayList<Tile>>();
I then store an ArrayList in the tileMap with a string of the current map:
tileMap.put(map, tilearray);
But I get an error at this line:
if(tileMap.get(currentMap).size()>0) {
Which is the start of my unloadTiles method. currentMap is just the String for the map the program is on.
You will want to use a Map such as a HashMap, perhaps a Map<String, Integer[]>. This will allow you to create an array of Integer (or whatever) and associate it with a String.
For example:
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
public class Foo {
public static void main(String[] args) {
Map<String, Integer[]> myMap = new HashMap<>();
myMap.put("foo", new Integer[] { 1, 2, 3 });
myMap.put("bar", new Integer[] { 3, 4, 5 });
myMap.put("spam", new Integer[] { 100, 200, 300 });
for (String key : myMap.keySet()) {
System.out.printf("%8s: %s%n", key, Arrays.toString(myMap.get(key)));
}
}
}
Use a java.util.Map and assign the value to a variable. Probably you will be better if use a List instead of an array
List<Integer> currentArray = loadMap("map1");
....
// inside
private List<Integer> loadMap( String fileName ) {
List<Integer> result = allTheMaps.get( fileName );
if ( result == null ) {
// load it from file...
result = ....
allTheMaps.put( fileName, result );
}
return result;
}
As others have said, a map will work for this.
What others have not said is that you would probably also benefit from using a class to represent your tiles as well.
This way, any array logic you have for manipulating the tiles can be nicely encapsulated in one place. I would imagine something like this:
public class Tiles{
private int[] tiles;
private String name;
private Tile(int[] tiles, String name){
this.tiles = tiles;
}
public static Tiles getTiles(Map<String, Tiles> tilesCache, String tileName){
if (tilesCache.containsKey(tileName)){
return tilesCache.get(tileName);
}
// load from file
return tile;
}
public void clear(Map<String, Tiles> tilesCache){
tilesCache.remove(this.name);
this.tiles = null;
}
//Other logic about tiles
}
You might want to consider using a HashMap with a String as the key and an Integer[] for the value.
Map<String, Integer[]> maps = new HashMap<String, Integer[]>();
and when you call your loadMap function you could do something like this.
public Integer[] loadMap(String name) {
if (maps.contains(name)) {
return maps.get(name);
}
// Falls through if map is not loaded
int[] mapData = new int[##];
// load map
maps.put(name, mapData);
return mapData;
}