I have a HashMap which certain keys like "crash" and "crashes" which return the same response. I want to create a new HashMap that maps synonyms to a unique key in the responseMap (for example, map "crash", "crashes" and "crashed" to "crash" in the synonymMap).
private void fillSynonymMap()
{
synonymMap.put("crash", "crash");
synonymMap.put("crashes", "crash");
synonymMap.put("crashed", "crash");
}
What I am stuck on is how to input these keys so that I can simplify the code below.
private void fillResponseMap()
{
responseMap.put("crash",
"Well, it never crashes on our system. It must have something\n" +
"to do with your system. Tell me more about your configuration.");
responseMap.put("crashes",
"Well, it never crashes on our system. It must have something\n" +
"to do with your system. Tell me more about your configuration.");\
responseMap.put("crashed",
"Well, it never crashes on our system. It must have something\n" +
"to do with your system. Tell me more about your configuration.");
}
public String generateResponse(HashSet<String> words)
{
for (String word : words) {
String response = responseMap.get(word);
if(response != null) {
return response;
}
}
// If we get here, none of the words from the input line was recognized.
// In this case we pick one of our default responses (what we say when
// we cannot think of anything else to say...)
return pickDefaultResponse();
}
After a little messing about I wrote a function that will look for a synonym, before returning a default message.
public String getResponse()
{
HashMap<String, String> responseMap = new HashMap<String, String>();
HashMap<String, String> synonymMap = new HashMap<String, String>();
responseMap.put("crash", "Hello there");
// Load the response value.
synonymMap.put("crash", "crash");
synonymMap.put("crashed", "crash");
synonymMap.put("crashes", "crash");
// Load the synonyms.
String input = "crashed";
// Select input value.
if(responseMap.containsKey(input))
{
// Response is already mapped to the word.
return responseMap.get(input);
}
else
{
// Look for a synonym of the word.
String synonym = synonymMap.get(input);
if(!synonym.equals(input) && responseMap.containsKey(synonym))
{
// If a new value has been found that is a key..
return responseMap.get(synonym);
}
}
// If no response, set default response.
input = "This is a default response";
return input;
}
As you can see the function first checks if the key exists. If it doesn't, it attempts a synonym. If that synonym doesn't pass the test, it will move to the default code at the bottom, which will set input to some default value and return that instead :)
You could use a second map.
The first map translates the synonyms to the basic key, which in turn can be used for the second map with the answers.
This also allows flexible extension of synonyms without enlarging the actual response map.
Besides, in this case you can actually use another type as key for the answser map. It just has to be same as the value type of synonyms maps.
That way, you could also use
Map<String, YourEnum> and Map<YourEnum, String>
with EnumMap as implementation of the Map interface.
Related
I'm using a HashMap to store a list of tags that are required in a certain message, for multiple messages, ie a HashMap<String,ArrayList<TagObject>>. Each TagObject has attributes, the main one is whether that tag is required or not in a certain message. Now, if a tag is required in one message, and not in another, the final required value ends up being the one that was processed last. I am also creating a HashMap<String,TagObject> to store all the tags processed. Maybe that is causing the issue? I think the issue is the same variable gets overridden repeatedly, how do I make separate copies for each message to store in the main HashMap of messages?
I've looked up HashMap overridden by last value, but I am creating a new Field everytime, so this doesn't seem to be the reason.
for(TagObject o:allTags) {
if(o instanceof Field){
fieldResult=new Field();
Field field = (Field) o;
String required=field.getRequired(); //this is the value found in the file where the specifications are, ie whether the field should be required or no in this message. this value is received correctly
if(required == null || required.equalsIgnoreCase("yes")) {
required="true";
}else{
required="false";
}
else {
fieldResult=ctd.searchFieldMap(field.name); //find the already created Field object
fieldResult.setRequired(required); //set the required now as got from the specifications
}
fieldsInMessage.add(fieldResult); //add this field to list of fields to be there in the message
//while being added, I can see the value of the required tag go as in the specs, however when I later print the hashmap of all messages, the tag which was required in one message, but set as not required in another, has changed value to the value of required of the last appearance of the field in the specifications
}
}
I was hoping that a new copy of the field will be created for each message, but seems like the same object is used in all. How do I make sure each message can have a separate copy of the tag, and hence unique attributes?
I guess that you're adding the tags incorrectly to the HashMap.
For example, if I would like to do a structure with messages and tags I would do as the following snippet:
public static void main(String[] args) {
MessageTagsMap map = new MessageTagsMap();
map.addNewMessage("Hello World!", "Snippet");
map.addNewMessage("StackOverflow", "Webpage", "Interesting");
map.paintMap();
map.addTagsToMessage("Hello World!", "Deprecated");
map.paintMap();
}
public class MessageTagsMap {
HashMap<String, ArrayList<String>> content;
public MessageTagsMap() {
content = new HashMap<>();
}
void addNewMessage(String message, String... tags) {
ArrayList<String> messageTags = new ArrayList<>();
for (String tag : tags) {
messageTags.add(tag);
}
this.content.put(message, messageTags);
}
void addTagsToMessage(String message, String... tags) {
ArrayList<String> messageTags = this.content.get(message);
for (String tag : tags) {
messageTags.add(tag);
}
}
void paintMap() {
for (Map.Entry<String, ArrayList<String>> entry : content.entrySet()) {
System.out.print("Message: " + entry.getKey() + " tags: {");
for (String tag : entry.getValue()) {
System.out.print(tag + " ");
}
System.out.println("}");
}
}
}
As you can see, it's not the same to add more information to a previous Map.Entry than to add a new Map.Entry to your HashMap.
Of course, if you create a new instance of an object each time that you want to add information to your Map, and you put that information with the same key that already exists, you're overriding the value in the Map.
Figured out what I really needed. I wanted to create a copy of a value in a HashMap, what I had been doing was copying over the reference to the object, which is why it kept getting overridden.
What I really needed was a copy constructor.
This helped: https://stackoverflow.com/a/33547834/1677804
So I have an Object that comes in that can be any of 100 different specific objects, with different elements inside it, from other objects, lists, sequences, primitives etc.
I want to strip the values in a depth first fashion to make a string of simple values with a delimiter between them. I have mapped the fields and stored them elsewhere using recursion/reflection that only happens once a new Object type comes in for the first time.
An example of how I'm storing the data in the database for a few simple example objects:
Object A layout table: Timestamp = 12345 Fields = Length|Width|Depth
Object B layout table: Timestamp = 12345 Fields = Height|Weight|Name
Object A layout table: Timestamp = 12350 Fields = Length|Width|Depth|Label
Object A sample: Timestamp = 12348 Values = 5|7|2
Object A sample: Timestamp = 12349 Values = 4|3|1
Object B sample: Timestamp = 12346 Values = 75|185|Steve Irwin
Object A sample: Timestamp = 12352 Values = 7|2|8|HelloWorld
Below is my current solution. I'm seeking improvements or alternatives to the design to accomplish the goal stated above.
Currently I get the object in and translate it to JSON using gson.toJson(); From that, I cycle through the JSON to get values using the code below. Issue is, this code is very CPU intensive on the low end CPU I am developing for due to the fact that there are many samples coming in per second. Overall purpose of the application is a data recorder that records real time samples into a SQLite database. I have also attempted to store the unmodified JSON into a SQLite BLOB column, but this is terribly inefficient with regards to DB size. Is there a better/more efficient method for getting values out of an object?
I don't have an issue storing the field mapping since it only needs to be done once, but the value stripping needs to be done for every sample. I know you can do it via reflection as well, but that is also processing heavy. Anyone have a better method?
public static List<String> stripValuesFromJson(JsonElement json)
{
// Static array list that will have the values added to it. This will
// be the return object
List<String> dataList = new ArrayList<String>();
// Iterate through the JSONElement and start parsing out values
for (Entry<String, JsonElement> entry : ((JsonObject) json).entrySet())
{
// Call the recursive processor that will parse out items based on their individual type: primitive, array, seq etc
dataList.addAll(dataParser(entry.getValue()));
}
return dataList;
}
/**
* The actual data processor that parses out individual values and deals with every possible type of data that can come in.
*
* #param json - The json object being recursed through
* #return - return the list of values
*/
public static List<String> dataParser(JsonElement json)
{
List<String> dataList = new ArrayList<String>();
// Deal with primitives
if (json instanceof JsonPrimitive)
{
// Deal with items that come up as true/false.
if (json.getAsString().equals("false"))
{
dataList.add("0");
} else if (json.getAsString().equals("true"))
{
dataList.add("1");
} else
{
dataList.add(json.getAsString());
}
// Send through recursion to get the primitives or objects out of this object
} else if (json instanceof JsonObject)
{
dataList.addAll(stripValuesFromJson(json));
} else if (json instanceof JsonArray)
{
// Send through recursion for each element in this array/sequence
for (JsonElement a : (JsonArray) json)
{
dataList.addAll(dataParser(a));
}
} else if (json instanceof JsonNull)
{
dataList.add(null);
} else
{
errorLog.error("Unknown JSON type: " + json.getClass());
}
return dataList;
}
One thing you could try out is writing your own JSON parser which simply emits values. I have more experience in JavaCC so I'd take one of existing JSON grammars and modify it so that it only outputs values. This should not be too complicated.
Take for example the booleanValue production from the mentioned grammar:
Boolean booleanValue(): {
Boolean b;
}{
(
(
<TRUE>
{ b = Boolean.TRUE; }
) | (
<FALSE>
{ b = Boolean.FALSE; }
)
)
{ return b; }
}
Basically you will need to replace returning the boolean value with appending "1" or "0" to the target list.
ANTLR is another option.
I have a method which maps a given string to another string like if the input to the method is "RS256" it will return "SHA256WithRSA" and many more. My method is given below
public String getAlgorithm(String alg) {
// The internal crypto provider uses different alg names
switch(alg) {
case "RSA256" : return "SHA256withRSA";
case "SHA384" : return "SHA384withRSA";
case "SHA512" : return "SHA512withRSA";
}
throw new Exception("Not supported");
}
is there any other way to do this (i don't want to use MAP). I'm looking to see if there is any design pattern or any OOP concept to do this.
Use real map, I mean java.util.Map which keeps key-value pair ex. Map<Key,Value>
Map<String,String> map= new HashMap<String,String>();
map.add("RSA256","SHA256withRSA");
map.add("SHA384","SHA384withRSA");
map.add("SHA512","SHA512withRSA");
...
public String getAlgorithm(String alg) {
return map.get(alg);
}
You are actually written a Facade Pattern here, I think you are wrapping some kind of library. switch-case statement should be fine.
Using map introduces overhead, so better no to use it.
You can use if-else to check alg equals to your condition and return value similar to this. But current way is very similar to this.
Why you can't use Map? that is the better way.
Map<String,String> algoMap=new HashMap<>(String,String);
Now you can put algoMap.put("algoName","Value")
Use HashMap
HashMap<String, String> newMap = new HashMap<String, String>();
newMap.put("RSA256", "SHA256withRSA");
newMap.put("SHA384", "SHA384withRSA");
newMap.put("SHA512", "SHA512withRSA");
String value = (String) newMap.get("RS256");
You can use enum types as well, but either way you have to use a switch statement without maps.
enum Algorithm {
RSA256,
SHA384,
SHA512;
public String name(String pValue) throws Exception {
switch(this) {
case RSA256:
return "SHA256withRSA";
case SHA384:
return "SHA384withRSA";
case SHA512:
return "SHA512withRSA";
default:
throw new Exception("Not supported");
}
}
}
I have a HashSet that I created and this is what it contains. It will contain more later on, this is pasted from standard out when I did a toString on it. Just to show the contents.
foo.toString(): Abstractfoo [id=2, serial=1d21d, value=1.25, date=2012-09-02 12:00:00.0]
INFO [STDOUT] price.toString(): Abstractfoo [id=1, serial=1d24d, value=1.30, date=2012-09-19 12:00:00.0]
I have a List that I also have and I need to compare the two. One of the elements in List is:
Bar.toString(): Bar [id=1d21d, name=Dell, description=Laptop, ownerId=null]
Here is what I am trying to do...
Bar contains all of the elements I want foo to have. There will only be one unique serial. I would like my program to see if an element in the list that is in HashSet contains the id for bar. So serial == id.
Here is what I've been trying to do
Removed code and added clearer code below
I've verified the data is getting entered into the HashSet and List correctly by viewing it through the debugger.
foo is being pulled from a database through hibernate, and bar is coming from a different source. If there is an element in bar I need to add it to a list and I'm passing it back to my UI where I'll enter some additional data and then commit it to the database.
Let me know if this makes sense and if I can provide anymore information.
Thanks
EDIT: Here is the class
#RequestMapping(value = "/system", method = RequestMethod.GET)
public #ResponseBody
List<AbstractSystem> SystemList() {
// Retrieve system list from database
HashSet<AbstractSystem> systemData = new HashSet<AbstractSystem>(
systemService.getSystemData());
// Retrieve system info from cloud API
List<SystemName> systemName= null;
try {
systemName = cloudClass.getImages();
} catch (Exception e) {
LOG.warn("Unable to get status", e);
}
// Tried this but, iter2 only has two items and iter has many more.
// In production it will be the other way around, but I need to not
// Have to worry about that
Iterator<SystemName> iter = systemName.iterator();
Iterator<AbstractSystem> iter2 = systemData .iterator();
while(iter.hasNext()){
Image temp = iter.next();
while(iter2.hasNext()){
AbstractPricing temp2 = iter2.next();
System.out.println("temp2.getSerial(): " + temp2.getSerial());
System.out.println("temp.getId(): " + temp.getId());
if(temp2.getSerial().equals(temp.getId())){
System.out.println("This will be slow...");
}
}
}
return systemData;
}
If N is the number of items in systemName and M is the number of items in systemData, then you've effectively built an O(N*M) method.
If you instead represent your systemData as a HashMap of AbstractSystem by AbstractSystem.getSerial() values, then you just loop through the systemName collection and lookup by systemName.getId(). This becomes more like O(N+M).
(You might want to avoid variables like iter, iter2, temp2, etc., since those make the code harder to read.)
EDIT - here's what I mean:
// Retrieve system list from database
HashMap<Integer, AbstractSystem> systemDataMap = new HashMap<AbstractSystem>(
systemService.getSystemDataMap());
// Retrieve system info from cloud API
List<SystemName> systemNames = cloudClass.getImages();
for (SystemName systemName : systemNames) {
if (systemDataMap.containsKey(systemName.getId()) {
System.out.println("This will be slow...");
}
}
I used Integer because I can't tell from your code what the type of AbstractSystem.getSerial() or SystemName.getId() are. This assumes that you store the system data as a Map elsewhere. If not, you could construct the map yourself here.
I am looking for some nice solution. I've got a couple of textfields on my page and I am sending these via Ajax using jQuery serialize method. This serialized string is parsed in my java method to hashmap with key = 'nameOfTextfield' nad value = 'valueInTextfield'
For example, I've got this String stdSel=value1&stdNamText=value2&stdRevText=value3 and everything works fine.
String[] sForm = serializedForm.split("&");
Map<String, String> fForm = new HashMap<String, String>();
for (String part : sForm) {
String key = null;
String value = null;
try {
key = part.split("=")[0];
value = part.split("=",2)[1];
fForm.put(key, value);
//if textfield is empty
} catch(IndexOutOfBoundsException e) {
fForm.put(key, "");
}
}
But this method will break down when ampersand in some textfield appears, for example this stdSel=value1&stdNamText=value2&stdRevText=val&&ue3. My thought was that I'll replace ampersand as separator in searialized string for some other character or maybe more characters. Is it possible and good idea or is there any better way?
Regards
Ondrej
Ampersands are escaped by the serialize function, so they don't break the URL.
What you need to unescape a field you got from an URL is
value = URLDecoder.decode(value,"UTF-8");
But, as was pointed by... Pointy, if you're using a web framework and not using only vanilla java.net java you probably don't have to do this.