List adding overwrting again and again - java

Below is my JAVA method
public static List<Match<String, String>> Decider
(List<Preference<String, String>> hospitalPrefs,List<Preference<String, String>> studentPrefs)
{
Match<String, String> matching = new Match<String, String>(null, null);
List<Match<String, String>> matcher = new ArrayList<Match<String, String>>();
/** Matching the preference of the hospital with the student */
for(int hospitalLoop = 0;hospitalLoop < hospitalPrefs.size(); hospitalLoop++)
{
String hospitalPreferrer = hospitalPrefs.get(hospitalLoop).getPreferrer();
String hospitalPreferred = hospitalPrefs.get(hospitalLoop).getPreferred();
int hospitalValue = hospitalPrefs.get(hospitalLoop).getValue();
for(int studentLoop = 0;studentLoop < studentPrefs.size();studentLoop++)
{
String studentPreferrer = studentPrefs.get(studentLoop).getPreferrer();
String studentPreferred = studentPrefs.get(studentLoop).getPreferred();
int studentValue = studentPrefs.get(studentLoop).getValue();
if(hospitalPreferred.equals(studentPreferrer)
&& hospitalPreferrer.equals(studentPreferred)
&& hospitalValue == studentValue)
{
System.out.println(hospitalPreferred + "," + studentPreferred);
matching.setItem1(hospitalPreferred);
matching.setItem2(studentPreferred);
matcher.add(matching);
break;
}
}
}
return matcher;
}
matcher variable is overwrite the list. I am confused about it.
Something like if I am adding
a,b,c.
In the matcher variable it is adding
c,c,c
I am confused where I m going wrong.
Thanks !!!

You are creating instance of matching before loop and then adding the same instance to your collection. You probably wanted to create matching inside the loop:
................
System.out.println(hospitalPreferred + "," + studentPreferred);
Match<String, String> matching = new Match<String, String>(null, null);
matching.setItem1(hospitalPreferred);
matching.setItem2(studentPreferred);
matcher.add(matching);
break;
................

You intialize matching once and then change its value. You need
matching = new Match<String,String>();
somwhere in your loops.

You're just adding the same matching over an over again.
If I were you, I'd move
Match<String, String> matching = new Match<String, String>(null, null);
to right before
matching.setItem1(hospitalPreferred);
matching.setItem2(studentPreferred);
matcher.add(matching);

Related

How to Loop next element in hashmap

I have a set of strings like this
A_2007-04, A_2007-09, A_Agent, A_Daily, A_Execute, A_Exec, B_Action, B_HealthCheck
I want output as:
Key = A, Value = [2007-04,2007-09,Agent,Execute,Exec]
Key = B, Value = [Action,HealthCheck]
I'm using HashMap to do this
pckg:{A,B}
count:total no of strings
reports:set of strings
Logic I used is nested loop:
for (String l : reports[i]) {
for (String r : pckg) {
String[] g = l.split("_");
if (g[0].equalsIgnoreCase(r)) {
report.add(g[1]);
dirFiles.put(g[0], report);
} else {
break;
}
}
}
I'm getting output as
Key = A, Value = [2007-04,2007-09,Agent,Execute,Exec]
How to get second key?
Can someone suggest logic for this?
Assuming that you use Java 8, it can be done using computeIfAbsent to initialize the List of values when it is a new key as next:
List<String> tokens = Arrays.asList(
"A_2007-04", "A_2007-09", "A_Agent", "A_Daily", "A_Execute",
"A_Exec", "P_Action", "P_HealthCheck"
);
Map<String, List<String>> map = new HashMap<>();
for (String token : tokens) {
String[] g = token.split("_");
map.computeIfAbsent(g[0], key -> new ArrayList<>()).add(g[1]);
}
In terms of raw code this should do what I think you are trying to achieve:
// Create a collection of String any way you like, but for testing
// I've simply split a flat string into an array.
String flatString = "A_2007-04,A_2007-09,A_Agent,A_Daily,A_Execute,A_Exec,"
+ "P_Action,P_HealthCheck";
String[] reports = flatString.split(",");
Map<String, List<String>> mapFromReportKeyToValues = new HashMap<>();
for (String report : reports) {
int underscoreIndex = report.indexOf("_");
String key = report.substring(0, underscoreIndex);
String newValue = report.substring(underscoreIndex + 1);
List<String> existingValues = mapFromReportKeyToValues.get(key);
if (existingValues == null) {
// This key hasn't been seen before, so create a new list
// to contain values which belong under this key.
existingValues = new ArrayList<>();
mapFromReportKeyToValues.put(key, existingValues);
}
existingValues.add(newValue);
}
System.out.println("Generated map:\n" + mapFromReportKeyToValues);
Though I recommend tidying it up and organising it into a method or methods as fits your project code.
Doing this with Map<String, ArrayList<String>> will be another good approach I think:
String reports[] = {"A_2007-04", "A_2007-09", "A_Agent", "A_Daily",
"A_Execute", "A_Exec", "P_Action", "P_HealthCheck"};
Map<String, ArrayList<String>> map = new HashMap<>();
for (String rep : reports) {
String s[] = rep.split("_");
String prefix = s[0], suffix = s[1];
ArrayList<String> list = new ArrayList<>();
if (map.containsKey(prefix)) {
list = map.get(prefix);
}
list.add(suffix);
map.put(prefix, list);
}
// Print
for (Map.Entry<String, ArrayList<String>> entry : map.entrySet()) {
String key = entry.getKey();
ArrayList<String> valueList = entry.getValue();
System.out.println(key + " " + valueList);
}
for (String l : reports[i]) {
String[] g = l.split("_");
for (String r : pckg) {
if (g[0].equalsIgnoreCase(r)) {
report = dirFiles.get(g[0]);
if(report == null){ report = new ArrayList<String>(); } //create new report
report.add(g[1]);
dirFiles.put(g[0], report);
}
}
}
Removed the else part of the if condition. You are using break there which exits the inner loop and you never get to evaluate the keys beyond first key.
Added checking for existing values. As suggested by Orin2005.
Also I have moved the statement String[] g = l.split("_"); outside inner loop so that it doesn't get executed multiple times.

java recursion: object is replaced rather than adding a new one

I am trying to add an object inside an object using recursion. My object contains an arrayList and I am trying to add my objects to this arrayList. But instead of adding a new object, my objects are being replaced.
My code which is doing this: This is where the logic of adding an object is being done. But it is being replaced instead.
private ArrayList<SubChapters> recursiveSubChapters(ReportingTree tree, LinkedHashMap<String, HashMap<String, String>> linkedHashMap, Boolean isSubTree){
SubChapters subChapters = new Subchapters();
ArrayList<SubChapters> alchildUnits = new ArrayList<SubChapters>();
final String chapterId = linkedHashMap.get(tree.getUnitID()).get("unit_num");
final String chapterName= linkedHashMap.get(tree.getUnitID()).get("unit_name");
if (!isSubTree) {
subChapters.set(chapterId);
subChapters.setTreeName(chapterName);
}
final ArrayList<ReportingTree> branches = tree.getBranches();
if (branches != null) {
subChapters.hasSubUnits(true);
for (ReportingTree subTree: branches) {
subChapters.setSubChapters(recursiveSubChapters(subTree, linkedHashMap, false));
//This is where the logic of adding an object is being done. But it is being replaced instead.
}
alchildUnits.add(subChapters);
}
return alchildUnits;
}
My guess is that I am messing somewhere in the loop here but I am not able to figure out where I am messing up. Thanks in advance for any suggestions or help.
My subChapters class:
public String subChapterID;
public String subChapterName;
public boolean isSubTree= false;
public ArrayList<SubChapters> subChapters;
and getters and setters.
I have coded the same solution to return a string and see the order on a jsp. It works just fine. I am not able to apply the same to my issue here.
private String recursive(ReportingTree tree, LinkedHashMap<String, HashMap<String, String>> listUnitInfo, boolean isTop) {
final String unitID = tree.getUnitID();
final HashMap<String, String> unit = listUnitInfo.get(unitID);
String output = "";
if (!isTop) {
output += "<li>" + unit.get("unit_num") + "/" + unit.get("unit_name") + "";
}
final ArrayList<ReportingTree> branches = tree.getBranches();
if (branches != null) {
if (isTop) {
output += "<li>" + unit.get("unit_num") + "/" + unit.get("unit_name") + "";
}
output += "<ul>\n";
for (ReportingTree subTree : branches) {
output += recursive(subTree, listUnitInfo, false);
}
output += "</ul>";
} else {
if (isTop) {
output += "<li>No units match your criteria.";
}
}
output += "</li>\n";
return output;
}
What you're doing is subChapters.setSubChapters, what I think you're trying to do is
subChapters.addSubChapters.
The reason why it works with the strings is because you're using += to add
the new string to the old string. Doing setSubChapters would be the same as using = with the strings.
addSubChapters would be a method that should add something to an ArrayList variable inside your subChapters class.

Java string parsing to HashMap

I have an input string of the following format:
Message:id1:[label1:label2....:labelN]:id2:[label1:label2....:labelM]:id3:[label1:label2....:labelK]...
It is basically ids associated with sets of labels. There can be an arbitrary number of ids and labels associated with those ids.
I want to be able to parse this string and generate a HashMap of the form id->labels for quick look up later.
I was wondering what would be the most efficient way of parsing this message in java?
Something like this should work for you:
String str = "Message:id1:[label1:label2:labelN]:id2:[label1:label2:labelM]:id3:[label1:label2:labelK]";
Pattern p = Pattern.compile("([^:]+):\\[([^\\]]+)\\]");
Matcher m = p.matcher(str.substring(8));
Map<String, List<String>> idmap = new HashMap<String, List<String>>();
while (m.find()) {
List<String> l = new ArrayList<String>();
String[] tok = m.group(2).split(":");
for (String t: tok)
l.add(t);
idmap.put(m.group(1), l);
}
System.out.printf("IdMap %s%n", idmap);
Live Demo: http://ideone.com/EoieUt
Consider using Guava's Multimap
If you take the string you gave:
Message:id1:[label1:label2....:labelN]:id2:[label1:label2....:labelM]:id3:[label1:label2....:labelK]
And do String.split("]"), You get:
Message:id1:[label1:label2....:labelN
:id2:[label1:label2....:labelM
:id3:[label1:label2....:labelK
If you loop through each of those, splitting on [, you get:
Message:id1: label1:label2....:labelN
:id2: label1:label2....:labelM
:id3: label1:label2....:labelK
Then, you can parse the id name out of the first element in the String[], and the labelname out of the second element in the String, and store that in your Multimap.
If you don't want to use Guava, you can also use a Map<String, List<String>>
Following code will serve your requirement.
import java.util.HashMap;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class RegexTest {
public static void main(String[] args){
String msg = "id1:[label1:label2]:id2:[label1:label2:label3]:id3:[label1:label2:label3:label4]";
Pattern pattern = Pattern.compile("id");
HashMap<String,String> kv = new HashMap<String,String>();
Matcher m = pattern.matcher(msg);
int prev = -1;
int next = -1;
int start = -1;
int end = -1;
String subMsg = "";
while (m.find()){
if(prev == -1){
prev = m.end();
}
else
{
next = m.end();
start = prev;
end = next;
subMsg = msg.substring(start,end);
kv.put(String.valueOf(subMsg.charAt(0)),subMsg.substring(subMsg.indexOf("["),subMsg.lastIndexOf("]")+1));
prev = next;
}
}
subMsg = msg.substring(next);
kv.put(String.valueOf(subMsg.charAt(0)),subMsg.substring(subMsg.indexOf("["),subMsg.lastIndexOf("]")+1));
System.out.println(kv);
}
}
Output : {3=[label1:label2:label3:label4], 2=[label1:label2:label3], 1=[label1:label2]}
Live Demo : http://ideone.com/HM7989

How to sort a string into a map and print the results

I have a string in the format nm=Alan&hei=72&hair=brown
I would like to split this information up, add a conversion to the first value and print the results in the format
nm Name Alan
hei Height 72
hair Hair Color brown
I've looked at various methods using the split function and hashmaps but have had no luck piecing it all together.
Any advice would be very useful to me.
Map<String, String> aliases = new HashMap<String, String>();
aliases.put("nm", "Name");
aliases.put("hei", "Height");
aliases.put("hair", "Hair Color");
String[] params = str.split("&"); // gives you string array: nm=Alan, hei=72, hair=brown
for (String p : params) {
String[] nv = p.split("=");
String name = nv[0];
String value = nv[1];
System.out.println(nv[0] + " " + aliases.get(nv[0]) + " " + nv[1]);
}
I really do not understand what you problem was...
Try something like this:
static final String DELIMETER = "&"
Map<String,String> map = ...
map.put("nm","Name");
map.put("hei","Height");
map.put("hair","Hair color");
StringBuilder builder = new StringBuilder();
String input = "nm=Alan&hei=72&hair=brown"
String[] splitted = input.split(DELIMETER);
for(Stirng str : splitted){
int index = str.indexOf("=");
String key = str.substring(0,index);
builder.append(key);
builder.append(map.get(key));
builder.append(str.substring(index));
builder.append("\n");
}
A HashMap consists of many key, value pairs. So when you use split, devise an appropriate regex (&). Once you have your string array, you can use one of the elements as the key (think about which element will make the best key). However, you may now be wondering- "how do I place the rest of elements as the values?". Perhaps you can create a new class which stores the rest of the elements and use objects of this class as values for the hashmap.
Then printing becomes easy- merely search for the value of the corresponding key. This value will be an object; use the appropriate method on this object to retrieve the elements and you should be able to print everything.
Also, remember to handle exceptions in your code. e.g. check for nulls, etc.
Another thing: your qn mentions the word "sort". I don't fully get what that means in this context...
Map<String, String> propsMap = new HashMap<String, String>();
Map<String, String> propAlias = new HashMap<String, String>();
propAlias.put("nm", "Name");
propAlias.put("hei", "Height");
propAlias.put("hair", "Hair Color");
String[] props = input.split("&");
if (props != null && props.length > 0) {
for (String prop : props) {
String[] propVal = prop.split("=");
if (propVal != null && propVal.length == 2) {
propsMap.put(propVal[0], propVal[1]);
}
}
}
for (Map.Entry tuple : propsMap.getEntrySet()) {
if (propAlias.containsKey(tuple.getKey())) {
System.out.println(tuple.getKey() + " " + propAlias.get(tuple.getKey()) + " " + tuple.getValue());
}
}

Java finding substring

I have the following String:
oauth_token=safcanhpyuqu96vfhn4w6p9x&**oauth_token_secret=hVhzHVVMHySB**&application_name=Application_Name&login_url=https%3A%2F%2Fapi-user.netflix.com%2Foauth%2Flogin%3Foauth_token%3Dsafcanhpyuqu96vfhn4w6p9x
I am trying to parse out the value for oauth_token_secret. I need everything from the equals sign (=) to the next ampersand sign (&). So I need to parse out: hVhzHVVMHySB
Currently, I have the following code:
Const.OAUTH_TOKEN_SECRET = "oauth_token_secret";
Const.tokenSecret =
content.substring(content.indexOf((Const.OAUTH_TOKEN_SECRET + "="))
+ (Const.OAUTH_TOKEN_SECRET + "=").length(),
content.length());
This will start at the beginning of the oauth_token_string, but it will not stop at the next ampersand. I am unsure how to specify to stop at the end of the following ampersand. Can anyone help me?
The indexOf() methods allow you to specify an optional fromIndex. This allows you to find the next ampersand:
int oauth = content.indexOf(Const.OAUTH_TOKEN_SECRET);
if (oauth != -1) {
int start = oath + Const.OATH_TOKEN_SECRET.length(); // or
//int start = content.indexOf('=', oath) + 1;
int end = content.indexOf('&', start);
String tokenSecret = end == -1 ? content.substring(start) : content.substring(start, end);
}
public static Map<String, String> buildQueryMap(String query)
{
String[] params = query.split("&");
Map<String, String> map = new HashMap<String, String>();
for (String param : params)
{
String[] pair = param.split("=");
String name = pair[0];
String value = pair[1];
map.put(name, value);
}
return map;
}
// in your code
Map<String, String> queryMap = buildQueryMap("a=1&b=2&c=3....");
String tokenSecret = queryMap.get(Const.OAUTH_TOKEN_SECRET);
Using String.split gives a much cleaner solution.
static String getValue(String key, String content) {
String[] tokens = content.split("[=&]");
for(int i = 0; i < tokens.length - 1; ++i) {
if(tokens[i].equals(key)) {
return tokens[i+1];
}
}
return null;
}
Click here for a test drive! ;-)
A much better solution is using the Pattern and corresponding Matcher class.
By using a capturing group you can check and "cut out" the the appropriate substring in one step.

Categories