Sorry of the title is a little bit confusing. What I need to do is read a text file with a bunch of cities and states on separate lines like this:
Salem, Oregon
St. George, Utah
Augusta, Maine
Portland, Maine
Jefferson City, Missouri
Kansas City, Missouri
Portland, Oregon
Salt Lake City, Utah
And then make an output from that like this:
Maine: Augusta, Portland
Missouri: Jefferson City, Kansas City
Oregon: Portland, Salem
Utah: Salt Lake City, St. George
I have to get it done in a single method and sent into a multidimensional array or arraylist where the first dimension would be the states and the second dimension would be the corresponding cities.
I assumed the easiest way to go about this would be to make sort-of tokens for each city and state but I have no idea how to go about sorting them properly afterwards. I've gotten as far as creating the tokens and then just re-printing them on to separate lines, which is nothing short of useless.
Here is my current code:
import java.i开发者_Go百科o.File;
import java.util.Scanner;
import java.util.Formatter;
import java.io.FileNotFoundException;
import java.util.Arrays;
public class Munge
{
private String inFileName, outFileName;
private Scanner inFile;
private Formatter outFile;
private int line = 0;
private String[] data;
public Munge(String inFileName, String outFileName)
{
this.inFileName = inFileName;
this.outFileName = outFileName;
data = new String[100];
}
public void openFiles()
{
try
{
inFile = new Scanner(new File(inFileName));
}
catch(FileNotFoundException exception)
{
System.err.println("File not found.");
System.exit(1);
}
catch(SecurityException exception)
{
System.err.println("You do not have access to this file.");
System.exit(1);
}
try
{
outFile = new Formatter(outFileName);
}
catch(FileNotFoundException exception)
{
System.err.println("File not found.");
System.exit(1);
}
catch(SecurityException exception)
{
System.err.println("You do not have access to this file.");
System.exit(1);
}
}
public void readRecords()
{
while(inFile.hasNext())
{
data[line] = inFile.nextLine();
System.out.println(data[line]);
line++;
}
}
public void writeRecords()
{
for(int i = 0; i < line; i++)
{
String tokens[] = data[i].split(", ");
Arrays.sort(tokens);
for(int j = 0; j < tokens.length; j++)
outFile.format("%s\r\n", tokens[j]);
}
}
public void closeFiles()
{
if(inFile != null)
inFile.close();
if(outFile != null)
outFile.close();
}
}
I really have no idea what I'm doing and my understanding of Java and any programming is extremely limited. I've been at this for way too many hours now. If anyone can help me out I would really appreciate it.
You need to have a list of cities for each state.
So, you will have something like Map<String, List<String>>
, and after parsing (i.e. splitting) your input, you look up the right list for your state and put in the city.
At the end, you iterate through your map to print out everything in the right order.
I would suggest using a HashMap that maps each state name to an ArrayList of city names. As you process each input record, retrieve the ArrayList for the state from the HashMap. If it's not there, then this is the first record for the state, so create a new ArrayList and put it in the HashMap under the state name. Assuming that any particular city/state pair occurs only once, you don't need to check for duplicates. If you need it as a multidimensional array at the end, then you can extract all the key/value pairs from the HashMap after everything has been processed.
Try approaching this problem using a Hashtable, using the state names as keys.
By default, in the case of a "hash collision" (a state-city pair already exists), a single bucket for a key stores multiple entries, which can be searched sequentially using the HashTable Java api. In the end, you end up with a data structure where you can access cities given a state as a key.
Alternatively, you can use state names as keys and store array lists as values. If given a state, there is no value associated with it, create a new ArrayList, add your city to it, then store the ArrayList as a pair in your HashTable. If given a state, an ArrayList already exists as the value, retrieve the ArrayList and insert your city. :)
You can look up the data structure in the Java 6 api.
HashTable
Here's some code with comments for you, hope it helps:
// your input file with city, state values
File file = new File("states.txt");
// data structure to hold mapping of state to list of cities, sorted by state
SortedMap<String, List<String>> map = new TreeMap<String, List<String>>();
// scan file by line and populate data structure
Scanner scanner = new Scanner(file).useDelimiter("\\n");
while (scanner.hasNext()) {
String line = scanner.next();
// only process lines with a comma
if (line.contains(",")) {
// split the line on the comma and extract the city and state
// note this won't work properly if the city has a comma in it
String[] parts = line.split(",");
String city = parts[0].trim();
String state = parts[1].trim();
// if the state doesn't exist in the map yet, create it
List<String> cities = map.get(state);
if (cities == null) {
cities = new ArrayList<String>();
map.put(state, cities);
}
// add the city to the list for the state if it's not in it yet
if (!cities.contains(city)) {
cities.add(city);
}
}
}
// iterate over the states for output
for (String state : map.keySet()) {
// build up a string for each state with the list of cities
StringBuilder sb = new StringBuilder();
// start with the state
sb.append(state + ": ");
// now append the cities
List<String> cities = map.get(state);
for (String city : cities) {
sb.append(city + ", ");
}
// remove the last comma
sb.delete(sb.length() - 2, sb.length());
// print out the finished line
String output = sb.toString();
System.out.println(output);
}
Code using a HashMap or ArrayList.
The key of the HashMap represents the state, The ArrayList will have the cities.
Disclaimer: I typed out the code in a Notepad, therefore there maybe compilation errors. But you get the idea.
/*
Store each State as a key in the HashMap.
For each State assign an arraylist of cities.
We use StringTokenizer to split the state and the city.
*/
HashMap<String,ArrayList<String>> hmStateCity = new HashMap<String,ArrayList<String>>();
public void readRecords()
{
while(inFile.hasNext())
{
String sInputLine = inFile.nextLine();
StringTokenizer stInput = new StringTokenizer(sInputLine , "," , true);
int i = 0; //when i is 0 = State, 1 = city
ArrayList<String> arrCity = new ArrayList<String>();
while (stInput.hasMoreElements())
{
String sToken = stInput.nextElement();
if( i == 0)
{
arrCity = hmStateCity.get( sToken );
if(arrCity == null)
{ // this indicates that this particular State was never created.
// so assign a new ArrayList to the State.
arrCity = new ArrayList<String>();
hmStateCity.put( token , arrCity );
}
}
else if( i == 1 )
{
arrCity.add( sToken );
}
i++;
}
}
}
/* Iterate through HashMAp. The Map's key is the State name.
Retrieve the List of cities using the "State".
The String sStateCityLine will have each line that can be written one at a time.
*/
public void writeRecords()
{
if(hmStateCity !=null)
{
Set<String> setStateName = hmStateCity.keySet();
for(String sState : setStateName )
{
String sStateCityLine = sState + ":" ;
ArrayList<String> arrCity = hmStateCity.get( sState );
if( arrCity!=null && !arrCity.isEmpty() )
{
boolean isFirstCity = true;
for(String sCity : arrCity )
{
if( !isFirstCity )
{
sStateCityLine = sStateCityLine + ",";
}
sStateCityLine = sStateCityLine + " " + sCity;
isFirstCity = false;
}
}
//Insert code here to write the String sStateCityLine line by line
}
}
}
精彩评论