Get elements from HashMap in Java? - java

I currently have the following code, which gets a table from a webpage, and put the elements into a HashMap (I think).
Document doc = Jsoup.connect(
"http://www.sportinglife.com/greyhounds/abc-guide").get();
Element tableHeader = doc.select("tbody").first();
Map<String, String> data = new HashMap<>();
for (Element element : tableHeader.children()) {
// Here you can do something with each element
if (element.text().indexOf("Pelaw Grange") > 0
|| element.text().indexOf("Shawfield") > 0
|| element.text().indexOf("Shelbourne Park") > 0
|| element.text().indexOf("Harolds Cross") > 0) {
// do nothing
} else {
String dog = element.select("td:eq(0)").text();
String race = element.select("td:eq(1)").text();
data.put(dog, race);
}
}
analyseRunners(data);
}
This seems to work OK and I now need it to run another method "analyseRunners", where it needs to go through each of the dogs and use that "dog" name to access another webpage where there is another table. Here's what I have so far...
String dogPage = "http://www.gbgb.org.uk/raceCard.aspx?dogName=" + dog;
Document doc1 = Jsoup.connect(dogPage).get();
int firsts = 0, seconds = 0, thirds = 0;
Element tblHeader = doc1.select("tbody").first();
for (Element element1 : tblHeader.children()){
String position = element1.select("td:eq(4)").text();
if (position.equals("1st")){
firsts++;
} else if (position.equals("2nd")){
seconds++;
} else if (position.equals("3rd")){
thirds++;
} else {
//do nothing
}
}
System.out.println("Firsts: " + firsts);
System.out.println("Seconds: " + seconds);
System.out.println("Thirds: " + thirds);
As you can see, I am trying to navigate to the webpage in jSoup using the "dog" from the first method above... this isn't working as it says "dog" cannot be resolved. How do I go about getting the dog name out of the HashMap and looping through every dog to work out how many 1st, 2nds and 3rds it has? (the fifth column on this page: http://www.gbgb.org.uk/raceCard.aspx?dogName=A%20Real%20Legend)

Use the dog names on your data map in a loop :
for(String dog : data.keySet())
{
// use dog as required
}

first iterate your map's key list and get the available dogs.
then process your logic inside that..
for (String dog: data.keySet()) {
String dogPage = "http://www.gbgb.org.uk/raceCard.aspx?dogName=" + dog;
Document doc1 = Jsoup.connect(dogPage).get();
....................
}

Related

Checking if item lore contains contains string (loren.contains("§eSigned from "))

I only want to check for:
if (lore.contains("§eSigned of ")) {
but it doesn't get that it does contain "§eSigned of "
I wrote a Minecraft Command /sign you can add a lore to an item ("Signed of playerrank | playername").
Then i wanted to add an /unsign command to remove this lore.
ItemStack is = p.getItemInHand();
ItemMeta im = is.getItemMeta();
List<String> lore = im.hasLore() ? im.getLore() : new ArrayList<String>();
if (lore.contains("§eSigned of " + getChatName(p))) { // this line is important!
for (int i = 0; i < 3; i++) {
int size = lore.size();
lore.remove(size - 1);
}
im.setLore(lore);
is.setItemMeta(im);
p.setItemInHand(is);
sendMessage(p, "§aThis item is no longer signed");
} else {
sendMessage(p, "§aThis item is not signed!");
}
return CommandResult.None;
Everything works fine until you e.g. change your name. than you can't remove the sign because getChatName(p) has changed.
To fix this i only want to check
if (lore.contains("§eSigned of ")) {
but than it doesn't get it and returns false. (it says lore does not contain "§eSigned of ")
I tried a lot but it only works with the string "§eSigned of " and getChatName(p).
As the documentation "contains" searches for the specific string so it should work as I thought right?
Add:
getChatName(p) returns the rank of the player and the playername like: "Member | domi"
sendMessage(p, "") sends a simple message in the Minecraft chat
The problem you run into is that contains(String) looks for a matching string. What you search for is a check if any string in the list starts with "§eSigned of ".
I would suggest adding a function isSignedItem like this:
private boolean isSignedItem(List<String> lore) {
for (String st : lore)
if (st.startsWith("§eSigned of "))
return true;
return false;
}
and then to use this function to check if the item is signed or not:
[...]
List<String> lore = im.hasLore() ? im.getLore() : new ArrayList<String>();
if (isSignedItem(lore)) { // this line is important!
for (int i = 0; i < 3; i++) {
int size = lore.size();
lore.remove(size - 1);
}
[...]

Parsing csv data into object with different column length

I am new to Java and practicing parsing csv file into the object. I've tried but cannot figure it out.
The file looks like this:
[0], [1], [2], [3] , [4] , [5] , [6] , [7] , [8] , [9]
class, gender, age, bodyType, profession, pregnant, isYou ,species, isPet, role
scenario:green, , , , , , , ,
person, female, 24, average , , FALSE , , , , passenger
animal, male , 4, , , FALSE , , dog , TRUE , pedestrian
scenario:red
person, male , 16, athletic, boxer , FALSE , TRUE , , , passenger
person, female, 25, athletic, doctor , TRUE , FALSE , , , pedestrian
I need to parse it by any number of passengers and pedestrians with any scenarios. Finally, add these scenarios into an ArrayList for analyzing.
What I think is to:
loop through each line, stops when reaches to the next scenario:red, adds the passengers and the pedestrians to the Character ArrayList. (I've done adding, but don't how to stop).
Create a scenario using constructor scenario(ArrayList<Character> passenger, ArrayList<Character> pedestrians, boolean redOrGreen);
The ArrayList scenarios add the created scenarios.
What I've done is put everything together instead of separate them. Any help or hint is highly appreciated.
Thanks for this community who helped me, here is what I've got so far.
public void loadCsv() throws IOException {
String csvFile = "config.csv";
String line = "";
String csvSplit = "\\s*,\\s*";
Scenario scenario = new Scenario();
Person person = new Person();
Animal animal = new Animal();
ArrayList<Scenario> scenaios = new ArrayList<Scenario>();
ArrayList<String> csvContents = new ArrayList<String>();
ArrayList<Character> passengers = new ArrayList<Character>();
ArrayList<Character> pedestrians = new ArrayList<Character>();
try (BufferedReader csvReader = new BufferedReader(new FileReader(csvFile));) {
String headerLine = csvReader.readLine(); //get rid of the header
//add each line to the arrayList
while ((line = csvReader.readLine()) != null) {
csvContents.add(line);
}
for(String csvLine : csvContents) {
String[] data = csvLine.split(csvSplit); // split by comma and remove redundant spaces
if (data.length == NO_OF_FIELD) { //check and avoid indexOutOfBoundException
String clazz = data[0].toLowerCase();// cannot use word "class" as a variable
if (clazz.startsWith("scenario") && data.length == 1) {
scenario = new Scenario();
scenario.setLegalCrossing(clazz.endsWith("green"));
continue;
}
else if ("person".equals(clazz) && data.length ==10) {
person = loadCsvPerson(data);
addCharacter(person, data);
}
else if ("animal".equals(clazz) && data.length ==10) {
animal = loadCsvAnimal(data);
addCharacter(animal, data);
}
}
}
}
//passenger and pedestrians are in position
System.out.println("passengers: " + passengers);
System.out.println("pedestrians: " + pedestrians);
if (null != scenario) {
scenario.setPassengers(passengers);
scenario.setPedestrians(pedestrians);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
If it is possible to change the csv file format, I would add scenario type column (and scenario id or name if required), so you can work with csv file as a result set from database when you join tables (scenario + passenger + pedestrian) and return plain rows.
With this approach you will be able to delegate parsing to any csv library and do your logic (group by scenario id/name/type) separately. With surrogate rows you have (scenario:green...) you have to write your custom parser.
For example, you can use univocity to simply parse file into your model (even using annotations) and iteratively group it and handle.
Or if you need to work with existing file format do something like that:
if (clazz.startsWith("scenario") && data.length == 1) {
// collect existing scenario before starting processing new one
if (scenario != null) {
scenario.setPassengers(passengers);
scenario.setPedestrians(pedestrians);
passengers = new ArrayList();
pedestrians = new ArrayList();
scenarios.add(scenario);
}
// now start new group (scenario)
scenario = new Scenario();
scenario.setLegalCrossing(clazz.endsWith("green"));
continue;
}
Following things need to be addressed in your code:
Strive to avoid using the name of a class which is already used by the standard library (and especially when it is in the default package, java.lang) e.g. there is already a class Character in Java library and therefore you should use a different name for your custom class.
Use continue to skip the line, scenario:red
for(String csvLine : csvContents) {
if(csvLine.equals("scenario:red")){
continue;
}
String[] data = csvLine.split(csvSplit); // split by comma and remove redundant spaces
if (data.length == NO_OF_FIELD) {
//..
}
//..
}
If you have already defined final int NO_OF_FIELD = 10, you can use the same instead of using the value 10 directly i.e. you should use NO_OF_FIELD instead of 10 in the following code:
if (data.length == NO_OF_FIELD) { //check and avoid indexOutOfBoundException
String clazz = data[0].toLowerCase();// cannot use word "class" as a variable
//...
else if ("person".equals(clazz) && data.length ==10) {
However, you also need to understand that && data.length ==10 is unnecessary here as you have already checked data.length == NO_OF_FIELD in the enclosing if condition.
I couldn't understand the rest of your points. If you clarify them, I'll be able to help you further.
I need to add the previous scenario in the second round.
Since the last set of data won't be captured, I need to set another new scenario to add it in. Thanks for the art sir.
Character character = null;
try (BufferedReader csvReader = new BufferedReader(new FileReader(csvFile));) {
String headerLine = csvReader.readLine(); //get rid of the header
//add each line to the arrayList
while ((line = csvReader.readLine()) != null) {
csvContents.add(line);
}
final int NO_OF_FIELDS = 10;
for(String csvLine : csvContents) {
String[] data = csvLine.split(csvSplit); // split by comma and remove redundant spaces
String clazz = data[0].toLowerCase();// cannot use word "class" as a variable
if (clazz.startsWith("scenario") && data.length == 1) {
// adding scenario after one set of data
// i.e second round adding the first round data
if (passengers.size() != 0 && pedestrians.size() != 0) {
Scenario scenario = new Scenario();
scenario.setPassengers(passengers);
scenario.setPedestrians(pedestrians);
scenarios.add(scenario);
}
passengers = new ArrayList<Character>();
pedestrians = new ArrayList<Character>();
if (clazz.endsWith("green")) {
scenario.setLegalCrossing(true);
System.out.println("green light");
}
else if (clazz.endsWith("red")){
scenario.setLegalCrossing(false);
System.out.println("red light");
}
continue;
}
//...
Scenario scenario = new Scenario();
scenario.setPassengers(passengers);
scenario.setPedestrians(pedestrians);
scenarios.add(scenario);
scenario.setPassengers(passengers);
scenario.setPedestrians(pedestrians);
Audit audit = new Audit();
audit.setScenario(scenarios);

Adding an Arraylist to another Arraylist in Java

I have seen this 2d Arraylist Question multiple times on SO, but don't understand why this doesn't work for my Language App.
I have an arraylist (called stage1) containing multiple arraylists (each is called entry) The System.out.println("In switch: this is entry" + entry); displays the database values correctly so I am sure that the query string elsewhere is correct (e.g. [In switch: this is entry[water, aqua, C:\Users\Username\Documents\NetBeansProjects\LanguageApp\src\Images\Categories\Food images\water.png])
But when I add entry to stage 1 and try to access it via stage1.get(0).get(0) I get the error "Caused by: java.lang.IndexOutOfBoundsException: Index: 0, Size: 0" which is why I tested if stage1 is empty. The other trace statement confirms that stage1 is null even after entries are added.
ArrayList<List<String>> stage1 = new ArrayList<>();
ArrayList<String> entry = new ArrayList<>();
int count = 0;
//words is an Observable List of all words relating to a specific category and langage
for (Words k : words) {
String eng = k.getEnglishWord();
String trans = "";
switch (lang) {
case "spanish":
trans = k.getSpanishWord();
break;
case "french":
trans = k.getFrenchWord();
break;
case "german":
trans = k.getGermanWord();
break;
}
String pic = k.getPicture();
entry.add(eng);
entry.add(trans);
entry.add(pic);
System.out.println("This is entry" + entry);
stage1.add(entry);
entry.clear();
if(stage1.size()!=0){ System.out.println("Stage1 " + stage1.get(0).get(0));
}
else {System.out.println("IT IS NULL");}
}
You are using single object at each time that's why it gives index out of bounds exception
Just place your arraylist into the for loop
ArrayList<String> entry = new ArrayList<String>();
for (int i = 0; i < 5; i++) {
//put you code here
ArrayList<String> entry = new ArrayList<String>();
entry.add("sd");
entry.add("sd");
entry.add("sd");
System.out.println("This is entry" + entry);
stage1.add(entry);
//entry.clear();
if(stage1.size()==0){ System.out.println("Stage1 " + stage1.get(0).get(0));
}
else {System.out.println("IT IS NULL");}
}
This will give's you desired output.
Every object in Java are reference Object. When you pass an object trought parameters of function, you pass the reference. If you modify the object inside or outside the method you will modify the object in and or out of the function.
I suggest you to take a look to it to clear your mind about all this.
Is Java "pass-by-reference" or "pass-by-value"?
Now, to solve your problem, you can reinstanciate you entre with entry = new ArrayList(); and the begiining of each loop and remove the entry.clear();.
ArrayList<List<String>> stage1 = new ArrayList<>();
ArrayList<String> entry = null;
int count = 0;
//words is an Observable List of all words relating to a specific category and langage
for (Words k : words) {
entry = new ArrayList<>();
String eng = k.getEnglishWord();
String trans = "";
switch (lang) {
case "spanish":
trans = k.getSpanishWord();
break;
case "french":
trans = k.getFrenchWord();
break;
case "german":
trans = k.getGermanWord();
break;
}
String pic = k.getPicture();
entry.add(eng);
entry.add(trans);
entry.add(pic);
System.out.println("This is entry" + entry);
stage1.add(entry);
//entry.clear();
if(stage1.size()!=0){ System.out.println("Stage1 " + stage1.get(0).get(0));
}
else {System.out.println("IT IS NULL");}
}

Nested loop creates duplicate entries when ran, cannot find issue?

When the code is ran the nested loop causes it to create occasional duplicate entries to the system, i have spent a while looking through this but still cant find what is causing this, would greatly appreciate any help?
for(int i = 0; i < subWorkItemElement.getChildNodes().getLength(); i++) {
Boolean test = false;
WorkItemCommon existingChild = null;
String summary = null;
if(subWorkItemElement.getChildNodes().item(i).getNodeName().equals("workitem")) {
// We know it's a work item - but is it in the existing list?
Element childWorkItem = (Element) subWorkItemElement.getChildNodes().item(i);
for(int j = 0; j < subWorkItemElement.getChildNodes().getLength(); j++) {
if(childWorkItem.getChildNodes().item(j) instanceof Element) {
if(((Element)childWorkItem.getChildNodes().item(j)).getNodeName().equals("details")) {
summary = ((Element) childWorkItem.getChildNodes().item(j)).getElementsByTagName("summary")
.item(0).getTextContent();
for(String k : userInfoHashMap.keySet()) {
summary = summary.replace("${" + k + "}", userInfoHashMap.get(k));
}
if(childHashTable.containsKey(summary)) {
test = true;
existingChild = childHashTable.get(summary);
IWorkItem workItem = existingChild.getWorkItem();
System.out.println("INFO: The task with summary \"" + summary + "\" already exists. Skipping creation.");
System.out.println("this task is work item: " + workItem.getId());
//either check the tasks in the xml for updated details and then modify the existing workitem
//or just modify the work item without checking for updates
makeChildTask(childWorkItem, existingChild, childHashTable, userInfoHashMap, workItemHashMap, rtc, false);
break;
}
}
}
}
if(!test) {
System.out.println("INFO: The task with summary " + summary + " does not currently exist. Creating.");
makeChildTask(childWorkItem, thisItem, childHashTable, userInfoHashMap, workItemHashMap, rtc, true);
} else makeFromExistingChildTask(childWorkItem, existingChild, userInfoHashMap, workItemHashMap, rtc);
}
}
You are possibly (not sure what makeChildTask() does) changing an XML structure while iterating through the children list. While not necessarily incorrect, this can mean you get entries inserted while you process the list. Since you call the subWorkItemElement.getChildNodes().getLength() each time instead of cache'ing it, this might result in the length changing in between the loop iterations.

hasNext skips first value in HashMap

I'm trying to implement an expandable listview with data from a remote server. I've already have the JSON part covered. My sample has three value sets returned (confirmed by checking logcat on the original JSON response). My problem now is while dividing the JSON return into header and child datas, the first value set is skipped. My code is as follows:
int lisDataHeaderCounter = 0;
String searchKey;
for (int i = 0; i < components.length(); i++) {
List<String> component_value = new ArrayList<String>();
searchKey = main_components.get(i);
if (!listDataHeader.contains(searchKey)) {
listDataHeader.add(searchKey);
Iterator<Map.Entry<String, String>> entries = sub_components.entrySet().iterator();
while (entries.hasNext()) {
Map.Entry<String, String> entry = entries.next();
Log.d("getValue() ", "+ " + entry.getValue());
if (searchKey == entry.getKey())
component_value.add(entry.getValue());
}
listDataChild.put(listDataHeader.get(lisDataHeaderCounter), component_value);
lisDataHeaderCounter++;
}
}
I've also tried the code below and it still has the same result.
for (Map.Entry<String, String> entry : sub_components.entrySet()) {
if (searchKey == entry.getKey())
component_value.add(entry.getValue());
}
Here is a sample of the JSON response that is being process by the above codes:
[{"activity_code":"1","activity_name":"Midterm Exam"},
{"activity_code":"1","activity_name":"Final Exam"},
{"activity_code":"2","activity_name":"Project"}]
With the current codes, in the for loop, the first value of searchKey is '1'. When I placed a Log.d(); in the while loop to check what the first value is read, I found that it is "Final Exam" and not "Midterm Exam". Is there a way for me to get the value of the first data set before it goes into the while loop?
Here is a workaround I've made to ensure that the first value would be included to the sub_components. But I guess it doesn't look neat. If anyone has a better solution, please feel free to share.
for (int i = 0; i < components.length(); i++) {
JSONObject c = components.getJSONObject(i);
String formula_code = c.getString(TAG_FORMULA_CODE);
String component_name = c.getString(TAG_ACTIVITY_NAME);
main_components.add(formula_code);
sub_components.put(formula_code, component_name);
if (!listDataHeader.contains(formula_code))
listDataHeader.add(formula_code);
if (i == 0) {
component_value.add(component_name);
}
}
for (int i = 0; i < listDataHeader.size(); i++) {
for (Map.Entry<String, String> entry : sub_components.entrySet()) {
if (listDataHeader.get(i) == entry.getKey())
component_value.add(entry.getValue());
}
listDataChild.put(listDataHeader.get(i), component_value);
component_value = new ArrayList<String>();
}
I can't see any off by one error on the two, but perhaps it's the searchKey == entry.getKey(), that might have to be searchKey.equals(entry.getKey()), but I would need to see more code to know for sure.

Categories

Resources