I am currently working on a Java project,
below are my attempts at coding so far:
import java.util.*;
import java.io.*;
import javax.swing.*;
import java.awt.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Iterator;
import java.util.HashMap;
import java.util.TreeMap;
import java.util.Collection;
import java.util.Map;
/**
*
* This class models a zoo. It allows a single animal to be added to the zoo, a
* batch of animals to be "imported" by reading data from a text file and for all
* the animals to be listed in a terminal window. It also ensures that all animals
* in the zoo have a unique identifier.
*
* #author Jacov
* #version Version 1, 01 August 2014
*/
public class MyZoo
{
// zoo identifier
private String zooId;
// a number used in generating a unique identifier for the next animal to be added to the zoo
private int nextAnimalIdNumber;
// zstorage for the Animal objects
private TreeMap<String, Animal> animals;
/**
* Create an "empty" zoo.
*
* #param zooId an identifier for the zoo, at least three characters long.
*/
public MyZoo(String zooId)
{
this.zooId = zooId.trim().substring(0,3).toUpperCase();
nextAnimalIdNumber = 0;
animals = new TreeMap<String, Animal>(animals);
}
/**
* Returns a unique identifier, for an <tt>Animal</tt> object, based on the
* zoo identifier and the field <tt>nextAnimalIdNumber</tt> which is incremented
* ready for next time the method is called.
*
* #return a unique identifier.
*/
public String allocateId()
{
// increment nextAnimalIdNumber and then construct a six digit string from it
nextAnimalIdNumber++;
String s = Integer.toString(nextAnimalIdNumber);
while ( s.length()<6 )
s = "0" + s;
return zooId + "_" + s;
}
/**
* Adds an animal to the zoo.
*
* #param animal the Animal object to be added.
*/
public void addAnimal(Animal animal)
{
animals.put(animal.getName(), animal);
}
/**
* Reads <tt>Animal</tt> data from a text file and adds them to the zoo. The
* format of the data is specified in the MyZoo coursework assignment.
*
* #param animal the Animal object to be added.
*/
public void readDataFromFile()
{
int noOfAnimalsRead = 0;
// set up an owner for the FileDialog
JFrame jframe = new JFrame();
jframe.setVisible(true);
// use a Filedialog to select a file to read from
FileDialog fDialog = new FileDialog(jframe, "Read from", FileDialog.LOAD);
fDialog.setFile("import001.txt");
fDialog.setDirectory(".");
fDialog.setVisible(true);
String fname = fDialog.getFile();
jframe.dispose();
File inFile = new File(fname);
String fileName = "import002.txt";
// This will reference one line at a time
String line = null;
try {
// FileReader reads text files in the default encoding.
FileReader fileReader =
new FileReader(fileName);
// Always wrap FileReader in BufferedReader.
BufferedReader bufferedReader =
new BufferedReader(fileReader);
while((line = bufferedReader.readLine()) != null) {
System.out.println(line);
}
// Always close files.
bufferedReader.close();
}
catch(FileNotFoundException ex) {
System.out.println(
"Unable to open file '" +
fileName + "'");
}
catch(IOException ex) {
System.out.println(
"Error reading file '"
+ fileName + "'");
}
addAnimal( new Animal("golden eagle", "Eddie", this) ); //
addAnimal( new Animal("tiger", "Tommy", this) );
addAnimal( new Animal("lion", "Leo", this) );
addAnimal( new Animal("parrot", "Polly", this) );
addAnimal( new Animal("cobra", "Collin", this) );
noOfAnimalsRead = 5;
// this next line should be retained
System.out.println("no of animals read from file was " + noOfAnimalsRead + "\n");
}
/**
* Prints out details of all animal in the zoo.
*
*/
public void printAllAnimals()
{
System.out.println("\nDetails for all animals in Zoo " + zooId);
System.out.println( "==================================");
Collection<Animal> c = animals.values();
// The name of the file to open.
String fileName = "import001.txt";
// This will reference one line at a time
String line = null;
for(Object s: animals.keySet()) {
// Yeah, I hate this too.
String k = (String) s;
// Now you can get the MailItems. This is the part you were missing.
List<Animal> listOfAnimals = animals.get(s);
for(Animal animal: listOfAnimals) {
System.out.println(animalItem.getSomething());
}
}
}
}
I currently cannot get my printAllAnimals() method to work as it should.
When executing the method printAllAnimals(), it does not do anything and wont, However it is supposed to use the Collection object c, so that animals stored in the zoo can easily be checked
Any help would be much appreciated as I have been trying to getting this working for hours and I am therefore confused.
There are a number of issues with this code, the first thing I noticed is that your constructor uses the animals Map to initialize itself. Just initialize the map using an empty constructor. i.e.
animals = new TreeMap<String, Animal>();
Then call the method to read from the file which also fills your map.
readDataFromFile();
finally if you want to iterate over a map and display the contents, you will need to do something like this:
for (Map.Entry<String, Animal> animalEntry : animals.entrySet())
{
System.out.println(animalEntry.getKey() + "/" + ((Animal)animalEntry.getValue()).getName());
}
Related
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 1 year ago.
This post was edited and submitted for review last year and failed to reopen the post:
Original close reason(s) were not resolved
Improve this question
I am reading a CSV file into a List<String>. However, my program creates a new List for each row in the CSV file. structure of the CSV file is shown below:
[KI , -3.370417, -168.734039, Kiribati]
[KM , -11.875001, 43.872219, Comoros]
[KN , 17.357822, -62.782998, Saint Kitts and Nevis]
[KP , 40.339852, 127.510093, North Korea]
[KR , 35.907757, 127.766922, South Korea]
[KW , 29.31166, 47.481766, Kuwait]
[KY , 19.513469, -80.566956, Cayman Islands]
[KZ , 48.019573, 66.923684, Kazakhstan]
[LA , 19.85627, 102.495496, Laos]
I want to be able to iterate over each of these lists and access items such as the "South Korea" or "KI".
However I cannot find an efficient way of doing so. My attempt is shown below for traversing the Lists in the method distance():
import java.util.*;
import java.io.*;
public class Main {
public static void distance(List<String> list) {
//attempt
for (List row : list) {
for (Object item : row) {
System.out.println(item + "\t");
}
System.out.println();
}
}
public static void main(String[] args) throws FileNotFoundException, IOException {
String file = "countries.csv";
List<String> countries;
BufferedReader reader = null;
String line = "";
reader = new BufferedReader(new FileReader(file));
while ( (line = reader.readLine()) != null ) {
List<String> nodes = Arrays.asList(line.split(","));
countries = nodes;
//System.out.println(countries);
// System.out.println(Arrays.toString(nodes));
}
System.out.println();
distance(countries);
}
}
Is there a way of iterating over and accessing elements of List of Lists?
.
I don't quite understand your question, but in any case, your code does not compile because you are treating countries as a list of lists while it is only a list of String! here is a working version of your application:
package com.company;
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class Main {
public static void distance(List<List<String>> list) {
for (List row : list) {
for(Object item: row)
System.out.println(item + "\t");
System.out.println();
}
}
public static void main(String[] args) throws IOException {
String file = "countries.csv";
List<List<String>> countries = new ArrayList<>();
BufferedReader reader = null;
String line = "";
reader = new BufferedReader(new FileReader(file));
while ( (line = reader.readLine()) != null ) {
List<String> nodes = Arrays.asList(line.split(","));
countries.add(nodes);
//System.out.println(countries);
// System.out.println(Arrays.toString(nodes));
}
System.out.println();
distance(countries);
}
}
I changed countries = nodes; to countries.add(nodes); which creates a list of List<string>, now if you want to access the last element of the inner list, you can do so like this:
System.out.println("Country: " + row.get(3));
I believe you would benefit a lot by reading on:
how to initialize objects in Java.
data structures such as Array, LinkedList and ArrayList.
You can use jackson (here you'll find documention of it https://github.com/FasterXML/jackson-dataformats-text/tree/master/csv) to read CSV file.
you can try this code, in this way you can iterate the list easily.
import com.fasterxml.jackson.dataformat.csv.CsvMapper;
import com.fasterxml.jackson.dataformat.csv.CsvSchema;
import java.io.File;
import java.io.IOException;
import java.util.List;
public class CsvUtils {
private final static CsvMapper mapper = new CsvMapper();
/**
* function to read SCV
* #param clazz {#link Class}
* #param file {#link File}
* #param <T> {#link T}
* #return List of object
* #throws IOException must catch it
*/
public static <T> List<T> read(Class<T> clazz, File file) throws IOException {
CsvSchema schema = mapper.schemaFor(clazz).withHeader().withColumnSeparator(',');
return mapper.readerFor(clazz).with(schema).<T>readValues(file).readAll();
}
}
I am learning how to work with files in Java. I have a sample file which contains key pairs and it values. I am trying to find a key pairs and if it matches, then output file would be updated with both, key pair and it's value. I am able to get key pairs in output file but unable to get values too. Stringbuilder may work here to append strings but I don't know how.
Below are my input and output files.
Input File:
born time 9 AM London -- kingNumber 1234567890 -- address: abc/cd/ef -- birthmonth: unknown
born time 9 AM Europe -- kingNumber 1234567890 -- address: abc/cd/ef -- birthmonth: december
Expected Output File:
kingNumber 1234567890 birthmonth unknown
kingNumber 1234567890 birthmonth unkbown
Current Output File:
kingNumber birthmonth
kingNumber birthmonth
I am able to write key pair ("kingNumber" and "birthmonth" in this case) to output file but I am not sure what I can do to get it's value too.
String kn = "kingNumber:";
String bd = "birthmonth:";
try {
File f = new File("sample.txt");
Scanner sc = new Scanner(f);
FileWriter fw = new FileWriter("output.txt");
while(sc.hasNextLine()) {
String lineContains = sc.next();
if(lineContains.contains(kn)) {
fw.write(kn + "\n");
// This is where I am stuck. What
// can I do to get it's value (number in this case).
}
else if(lineContains.contains(bd)) {
fw.write(bd);
// This is where I am stuck. What
// can I do to get it's value (birthday in this case).
}
}
} catch (IOException e) {
e.printStackTrace();
}
you could use java.util.regex.Pattern & java.util.regex.Matcherwith a pattern alike:
^born\stime\s([a-zA-Z0-9\s]*)\s--\skingNumber\s(\d+)\s--\saddress:\s([a-zA-Z0-9\s/]*)\s--\sbirthmonth:\s([a-zA-Z0-9\s]*)$
write less, do more.
I have written a simple parser that it following data format from your example.
You will need to call it like this:
PairParser parser = new PairParser(lineContains);
then you can get value from the parser by pair keys
How to get value:
parser.getValue("kingNumber")
Note that keys do not have trailing column character.
The parser code is here:
package com.grenader.example;
import java.util.HashMap;
import java.util.Map;
public class PairParser {
private Map<String, String> data = new HashMap<>();
/**
* Constructor, prepare the data
* #param dataString line from the given data file
*/
public PairParser(String dataString) {
if (dataString == null || dataString.isEmpty())
throw new IllegalArgumentException("Data line cannot be empty");
// Spit the input line into array of string blocks based on '--' as a separator
String[] blocks = dataString.split("--");
for (String block : blocks)
{
if (block.startsWith("born time")) // skip this one because it doesn't looks like a key/value pair
continue;
String[] strings = block.split("\\s");
if (strings.length != 3) // has not exactly 3 items (first items is empty), skipping this one as well
continue;
String key = strings[1];
String value = strings[2];
if (key.endsWith(":"))
key = key.substring(0, key.length()-1).trim();
data.put(key.trim(), value.trim());
}
}
/**
* Return value based on key
* #param key
* #return
*/
public String getValue(String key)
{
return data.get(key);
}
/**
* Return number of key/value pairs
* #return
*/
public int size()
{
return data.size();
}
}
And here is the Unit Test to make sure that the code works
package com.grenader.example;
import com.grenader.example.PairParser;
import org.junit.Test;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.fail;
public class PairParserTest {
#Test
public void getValue_Ok() {
PairParser parser = new PairParser("born time 9 AM London -- kingNumber 1234567890 -- address: abc/cd/ef -- birthmonth: unknown");
assertEquals("1234567890", parser.getValue("kingNumber"));
assertEquals("unknown", parser.getValue("birthmonth"));
}
#Test(expected = IllegalArgumentException.class)
public void getValue_Null() {
new PairParser(null);
fail("This test should fail with Exception");
}
#Test(expected = IllegalArgumentException.class)
public void getValue_EmptyLine() {
new PairParser("");
fail("This test should fail with Exception");
}
#Test()
public void getValue_BadData() {
PairParser parser = new PairParser("bad data bad data");
assertEquals(0, parser.size());
}
}
Currently I am working on a way to run java code in string form. So here is how I did it.
import java.util.HashMap;
import java.util.Map;
import groovy.lang.GroovyClassLoader;
public class GroovyStackOverflow {
public static void main(String[] args) {
GroovyClassLoader gcl = new GroovyClassLoader();
String codeSnippet = "double calculatedAnswer = (Double)"
+ "contextMap.get(\"doubleValue\") * (Double)contextMap.get(\"doubleValue\");"
+ " calculatedAnswer = Math.sqrt(calculatedAnswer); "
+ "calculatedAnswer = calculatedAnswer * calculatedAnswer;"
+ "System.out.println(calculatedAnswer);"
+ " return calculatedAnswer;";
StringBuilder sb = new StringBuilder();
sb.append("public class ScriptImplementor implements ScriptEvaluator { public Object evaluate(Map contextMap) {");
sb.append(codeSnippet);
sb.append("} }");
Class<?> clazz = gcl.parseClass(sb.toString());
ScriptEvaluator scriptEvaluator = null;
double calculatedAnswer = 100.0;
try {
Map contextMap = new HashMap();
contextMap.put("doubleValue", (double)100.0);
contextMap.put("threadId", "thread"+100);
contextMap.put("hashCode", 100);
scriptEvaluator = (ScriptEvaluator) clazz.newInstance();
scriptEvaluator.evaluate(contextMap);;
} catch (InstantiationException | IllegalAccessException e) {
e.printStackTrace();
}
}
}
public interface ScriptEvaluator {
public Object evaluate(Map contextMap);
}
Problem is that it fails in following case.
import java.util.HashMap;
import java.util.Map;
import groovy.lang.GroovyClassLoader;
public class GroovyStackOverflow {
public static void main(String[] args) {
GroovyClassLoader gcl = new GroovyClassLoader();
String codeSnippet = "double calculatedAnswer = (Double)"
+ "\n "
+ "contextMap.get(\"doubleValue\") * (Double)contextMap.get(\"doubleValue\");"
+ " calculatedAnswer = Math.sqrt(calculatedAnswer); "
+ "calculatedAnswer = calculatedAnswer * calculatedAnswer;"
+ "System.out.println(calculatedAnswer);"
+ " return calculatedAnswer;";
StringBuilder sb = new StringBuilder();
sb.append("public class ScriptImplementor implements ScriptEvaluator { public Object evaluate(Map contextMap) {");
//sb.append(codeSnippet.replaceAll("\n", " "));
sb.append(codeSnippet);
sb.append("} }");
Class<?> clazz = gcl.parseClass(sb.toString());
ScriptEvaluator scriptEvaluator = null;
double calculatedAnswer = 100.0;
try {
Map contextMap = new HashMap();
contextMap.put("doubleValue", (double)100.0);
contextMap.put("threadId", "thread"+100);
contextMap.put("hashCode", 100);
scriptEvaluator = (ScriptEvaluator) clazz.newInstance();
scriptEvaluator.evaluate(contextMap);;
} catch (InstantiationException | IllegalAccessException e) {
e.printStackTrace();
}
}
}
public interface ScriptEvaluator {
public Object evaluate(Map contextMap);
}
I don't understand why it fails and what this error message means-
Exception in thread "main" org.codehaus.groovy.runtime.typehandling.GroovyCastException: Cannot cast object 'class java.lang.Double' with class 'java.lang.Class' to class 'double'
at org.codehaus.groovy.runtime.typehandling.DefaultTypeTransformation.castToNumber(DefaultTypeTransformation.java:163)
at org.codehaus.groovy.runtime.typehandling.DefaultTypeTransformation.doubleUnbox(DefaultTypeTransformation.java:88)
at ScriptImplementor.evaluate(script15126616543572010791987.groovy:1)
at GroovyStackOverflow.main(GroovyStackOverflow.java:33)
After uncommenting this code //sb.append(codeSnippet.replaceAll("\n", " ")); it works. But please suggest a better way to handle it. Also why it does not give error while parsing class?
And what other surprises I can expect like this?
You hit a difference between Java and Groovy.
In Java a statement is ended by a semicolon.
In Groovy a satement is ended by a semicolon, or by a linebreak if the statement already is a complete statement.
In your case this means the code
double calculatedAnswer = (Double)
contextMap.get("doubleValue") * (Double)contextMap.get("doubleValue")
is two statements.
The first of these statements is double calculatedAnswer = (Double).
In Groovy you can also omit .class to reference a class, so Double.class can be written as Double.
So what you do in that statement is, that you assign the Double class object to a double variable. The parentheses are just no-ops here.
This of course fails like the message says, as the Double class object cannot be case automatically to a double.
You can explicitly escape a linebreak to make it not end a statement like in
double calculatedAnswer = (Double)\
contextMap.get("doubleValue") * (Double)contextMap.get("doubleValue")
which would work like you expected.
But there can of course be other cases where Groovy and Java are different.
Always remember, the Groovy syntax is close to the Java syntax, yet not identical.
Afair each valid Java code is also valid Groovy code, but not necessarily with the exact same meaning as you can see in this example.
I am trying to read a file of string int and boolean values into an array list as object blocks. The string values go into the array list just fine, its the boolean values I'm having trouble with. Every time I encounter the variable 'active'there is a mismatch exception. Please help! The text file for if the block is a wizard goes in this order
name (string)
location (string)
active (boolean) ... the one I'm having issues with
skill level (int)
friendliness (int)
I included the driver class as well as the Witch class which contains the
variable 'active' originally.
Driver class that adds objects to the array list based on what the scanner
reads from the file
package project2;
import java.util.Scanner;
import java.io.File;
import java.io.FileNotFoundException;
import java.util.ArrayList;
public class Project2 {
public static void main(String[] args) {
Scanner inputFileScanner1 = null;
//file name
String listFile = "list.txt";
// Check to see if file exists
try {
inputFileScanner1 = new Scanner(new File(listFile));
} catch (FileNotFoundException e) {
System.out.println("Error opening file.");
System.exit(1);
}
//create Individuals arraylist and Location arraylist
ArrayList < Individual > Individual = new ArrayList < > ();
ArrayList < String > Location = new ArrayList < > ();
//declare variables to read file contents into the arraylist
String wizName, witchName, individualName, location, position,
profession = null, line = null;
int wizLevel, witchSkillLevel, friendliness;
boolean active;
//while there is a next line, if the line equals Wizard, the next four lines
// are wizard name, location, position and level
while (inputFileScanner1.hasNext()) {
line = inputFileScanner1.nextLine();
if (line.trim().equals("Wizard")) {
wizName = inputFileScanner1.nextLine().trim();
location = inputFileScanner1.nextLine().trim();
position = inputFileScanner1.nextLine().trim();
wizLevel = inputFileScanner1.nextInt();
//create wizard object
Individual wizard = new Wizard(wizName, location, position, profession, wizLevel);
//fill arraylist with wizard objects
Individual.add(wizard);
Location.add(location);
} //if the next line is Witch, the next five lines are
// witch name, location, yes/no active, skill level, and friendliness
//in that order
else if (line.trim().equals("Witch")) {
witchName = inputFileScanner1.nextLine().trim();
location = inputFileScanner1.nextLine().trim();
active = inputFileScanner1.nextBoolean();
witchSkillLevel = inputFileScanner1.nextInt();
friendliness = inputFileScanner1.nextInt();
//create witch object
Individual witch = new Witch(witchName, location, profession, witchSkillLevel, friendliness, active);
//fill the arraylist with witch objects
Individual.add(witch);
Location.add(location);
} else {
profession = line.trim();
individualName = inputFileScanner1.nextLine().trim();
location = inputFileScanner1.nextLine().trim();
Individual i = new Individual(profession, individualName, location);
Individual.add(i);
Location.add(location);
}
java.util.Collections.sort(Individual);
java.util.Collections.sort(Location);
}
System.out.println("List of friends and possible allies: " + Location);
inputFileScanner1.close();
}
}
//Witch class which holds values that are in the text file. active is the boolean value Im having trouble with
package project2;
public class Witch extends Individual implements Magical {
private int skill;
private int friendly;
//Constructor with witch parameters
public Witch(String name, String location, String profession,
int skill, int friendly, boolean active) {
}
//default constructor
public Witch() {
this("", "", "", 0, 0, false);
}
//overridden abstract method from magical interface
#Override
public void assess() {
System.out.print(this.friendly + " " + this.skill + " " + super.toString());
}
}
<!-- end snippet -->
Text file :
enter image description here
When you pull in your boolean variable do something like this.
if(inputFileScanner1.nextLine().trim().equals("yes"))
{
active = true;
}
else
{
active = false;
}
Okay, the problem is that the file contains the strings yes and no, that are not directly parsable as booleans (should be true or false).
If you can change the original data file somehow, I would suggest to use the two true and false keywords, otherwise, the #Sendrick Jefferson solution will do the job (at your own risk: every typo, as for instance "ye", will be translated into false).
I am currently working on a Java project,
below are my attempts at coding so far:
public class MyZoo
{
// zoo identifier
private String zooId;
// a number used in generating a unique identifier for the next animal to be added to the zoo
private int nextAnimalIdNumber;
// zstorage for the Animal objects
private TreeMap<String, List<Animal>> animals;
/**
* Create an "empty" zoo.
*
* #param zooId an identifier for the zoo, at least three characters long.
*/
public MyZoo(String zooId)
{
this.zooId = zooId.trim().substring(0,3).toUpperCase();
nextAnimalIdNumber = 0;
animals = new TreeMap<String, List<Animal>>();
}
/**
* Returns a unique identifier, for an <tt>Animal</tt> object, based on the
* zoo identifier and the field <tt>nextAnimalIdNumber</tt> which is incremented
* ready for next time the method is called.
*
* #return a unique identifier.
*/
public String allocateId()
{
// increment nextAnimalIdNumber and then construct a six digit string from it
nextAnimalIdNumber++;
String s = Integer.toString(nextAnimalIdNumber);
while ( s.length()<6 )
s = "0" + s;
return zooId + "_" + s;
}
/**
* Adds an animal to the zoo.
*
* #param animal the Animal object to be added.
*/
public void addAnimal(Animal animal)
{
String animalName = animal.getName();
// Is there already an animal with the same name?
if (!animals.containsKey(animalName)){
// If it is not in the map, create a list
animals.put(animalName, new ArrayList<Animal>());
}
// Now add the animal to the list
animals.get(animalName).add(animal);
}
/**
* Reads <tt>Animal</tt> data from a text file and adds them to the zoo. The
* format of the data is specified in the MyZoo coursework assignment.
*
* #param animal the Animal object to be added.
*/
public void readDataFromFile()
{
int noOfAnimalsRead = 0;
// set up an owner for the FileDialog
JFrame jframe = new JFrame();
jframe.setVisible(true);
// use a Filedialog to select a file to read from
FileDialog fDialog = new FileDialog(jframe, "Read from", FileDialog.LOAD);
fDialog.setFile("import001.txt");
fDialog.setDirectory(".");
fDialog.setVisible(true);
String fname = fDialog.getFile();
jframe.dispose();
File inFile = new File(fname);
String fileName = "import002.txt";
// This will reference one line at a time
String line = null;
try {
// FileReader reads text files in the default encoding.
FileReader fileReader =
new FileReader(fileName);
// Always wrap FileReader in BufferedReader.
BufferedReader bufferedReader =
new BufferedReader(fileReader);
while((line = bufferedReader.readLine()) != null) {
System.out.println(line);
}
// Always close files.
bufferedReader.close();
}
catch(FileNotFoundException ex) {
System.out.println(
"Unable to open file '" +
fileName + "'");
}
catch(IOException ex) {
System.out.println(
"Error reading file '"
+ fileName + "'");
}
addAnimal( new Animal("golden eagle", "Eddie", this) ); //
addAnimal( new Animal("tiger", "Tommy", this) );
addAnimal( new Animal("lion", "Leo", this) );
addAnimal( new Animal("parrot", "Polly", this) );
addAnimal( new Animal("cobra", "Collin", this) );
noOfAnimalsRead = 5;
// this next line should be retained
System.out.println("no of animals read from file was " + noOfAnimalsRead + "\n");
}
/**
* Prints out details of all animal in the zoo.
*
*/
public void printAllAnimals()
{
System.out.println("\nDetails for all animals in Zoo " + zooId);
System.out.println( "==================================");
Collection<Animal> c = animals.values();
// The name of the file to open.
String fileName = "import001.txt";
// This will reference one line at a time
String line = null;
for (Map.Entry<String, List<Animal>> animalEntry : animals.entrySet())
{
List<Animal> animalsOfAName = animalEntry.getValue();
for (Animal animal: animalsOfAName){
// output here, change as appropriate, maybe add the type of animal
System.out.println(animal.getName());
}
}
}
}
however there are text names in the text file (Eddie) which are the same, how do I get the second Eddie to replace the first Eddie without losing alphabetical order, in the addAnimal() the put() uses the name field
Keys must be unique in a Map so that is why the second Eddie animal replaces the first one.
To hold multiple objects under the same key, you can declare a Map that uses a List (or another appropriate Collection) as the value in the key-value pair.
TreeMap<String, List<Animal>> animals;
Now some logic is needed to handle this when adding animals.
public void addAnimal(Animal animal)
{
String animalName = animal.getName();
// Is there already an animal with the same name?
if (!animals.containsKey(animalName){
// If it is not in the map, create a list
animals.put(animalName, new ArrayList<Animal>();
}
// Now add the animal to the list
animals.get(animalName).add(animal);
}
Now for printing, you need to iterate through the animals for each name:
for (Map.Entry<String, List<Animal>> animalEntry : animals.entrySet())
{
List<Animal> animalsOfAName = animalEntry.getValue();
for (Animal animal: animalsOfAName){
// output here, change as appropriate, maybe add the type of animal
System.out.println(animal.getName());
}
}