将数组列表打印到输出文件中? [英] Printing arraylist into output file?
问题描述
在此处跟进问题:Java:将 Arraylist 打印到输出文件?
出于某种原因,将 ArrayLists
打印到输出文件需要花费大量时间,通常为 20-30 分钟.然而,这只发生在 sort 方法或 filterTitle
或 filterArtist
方法(涉及字符串输入的方法).当我运行 filterRank
或 filterYear
时,它运行得非常好.
For some reason, it takes an extraordinary amount of time for the ArrayLists
to be printed to the output file, usually 20-30 minutes. However, this only happens with the sort methods or the filterTitle
or filterArtist
methods (methods that concern String inputs).
When I run filterRank
or filterYear
, it runs perfectly fine.
当我直接从过滤器方法打印song2 ArrayList
时,唯一打印的是[]
,这意味着ArrayList
是空的,但它不应该是?无论如何,filterRank
和 filterYear
方法仍然有效.不过,我认为这是相关的.
When I print the song2 ArrayList
directly from the filter methods, the only thing that is printed is []
, which means the ArrayList
is empty, but it shouldn't be? And the filterRank
and filterYear
methods still work regardless of this.
Somehow I think it's related, though.
输入文件可以在这里找到:http://staff.rentonschools.us/hhs/ap-comp-science/projects/download/agazillionsongs.txt?id=223098
Input file can be found here: http://staff.rentonschools.us/hhs/ap-comp-science/projects/download/agazillionsongs.txt?id=223098
示例排序方法:
public void sortYear() {
Collections.sort(songs2, SongComparator.byYear()); // now we have a sorted list
System.out.println(songs2);
}
示例过滤器方法(用于字符串)
Example filter method (for strings)
public void filterArtist(String s) {
int n = 0;
if (n == 0) {
System.out.println("Program is processing.");
n++;
for (Song song1 : songs2) {
if ((!(((song1.artist).contains(s))))) {
itemsToRemove.add(song1);
}
}
songs2.removeAll(itemsToRemove);
itemsToRemove.clear();
}
System.out.println(songs2);
}
示例过滤器方法(对于整数)
Example filter method (for ints)
public void filterRank(Range r) {
int n = 0;
if (n == 0) {
System.out.println("Program is processing.");
n++;
for (Song song1 : songs2) {
if (song1.rank > (r.getMax()) || (song1.rank) < (r.getMin())) {
itemsToRemove.add(song1);
}
}
songs2.removeAll(itemsToRemove);
itemsToRemove.clear();
}
System.out.println(songs2);
}
主类中用于打印/输出文件的代码
Code in main class for printing/output file
while (input.hasNextLine()) {
int n = 0;
SongCollection collection = new SongCollection(songs);
String inputType = input.nextLine();
String delims = "[ ]";
String[] tokens = inputType.split(delims);
for (int i = 0; i < tokens.length; i++) {
n = 0;
if (n == 0) {
if ((tokens[i]).contains("year:")) {
collection.filterYear(Range.parse(tokens[i]));
n = 1;
}// end of year loop
if ((tokens[i]).contains("rank:")) {
collection.filterRank(Range.parse(tokens[i]));
n = 1;
}// end of rank
if ((tokens[i]).contains("artist:")) {
collection.filterArtist(tokens[i]);
n = 1;
}// end of artist
if ((tokens[i]).contains("title:")) {
collection.filterTitle(tokens[i]);
n = 1;
}// end of title
if ((tokens[i]).contains("sort:")) {
if ((tokens[i]).contains("title")) {
collection.sortTitle();
n = 1;
}// end of sort title
if ((tokens[i]).contains("artist")) {
collection.sortArtist();
n = 1;
}// end of sort artist
if ((tokens[i]).contains("rank")) {
collection.sortRank();
n = 1;
}// end of sort rank
if ((tokens[i]).contains("year")) {
collection.sortYear();
n = 1;
}// end of sort year
}//end of sort
}// end of for loop
}// end of input.hasNextline loop
final PrintStream console = System.out; //saves original System.out
File outputFile = new File("output.txt"); //output file
PrintStream out = new PrintStream(new FileOutputStream(outputFile)); //new FileOutputStream
System.setOut(out); //changes where data will be printed
System.out.println(collection.toString());
System.setOut(console); //changes output to print back to console
Scanner outputFileScanner = new Scanner(outputFile); //inputs data from file
while ((outputFileScanner.hasNextLine())) { //while the file still has data
System.out.println(outputFileScanner.nextLine()); //print
}
outputFileScanner.close();
out.close();
}
完整的编译代码:
import java.io.*;
import java.io.File;
import java.io.FileNotFoundException;
import java.util.*;
import java.util.Comparator;
import java.util.Scanner;
import java.util.StringTokenizer;
public class GazillionSongs {
public static void main(String[] args) throws FileNotFoundException, IOException {
System.out.println("Welcome to Java Song Collection!"); // greets the user
System.out
.println("This program sorts and filters large databases of popular songs."); // explains purpose of program
System.out
.println("This program is able to filter and sort by year, artist, title and rank.");
System.out
.println("Please enter a file that contains a database you wish to filter or sort. (i.e, alistofsongs.txt)"); // sample file = agazillionsongs.txt
Scanner fileInput = new Scanner(System.in); //Scanner which accepts filename
String filename = fileInput.nextLine();
File f = new File(filename); //creates file from input
/*error check for file here*/
Scanner fileScanner = new Scanner(f); //inputs data from file
ArrayList<Song> songs = new ArrayList<Song>();
while ((fileScanner.hasNextLine())) {
songs.add(Song.parse(fileScanner.nextLine()));
}
System.out
.println("Please select which commands you would like to use for the program.");
System.out
.println("Please format your command like the following example: year:<year(s)> rank:<rank(s)> artist:<artist> title:<title> sortBy:<field>");
System.out.println();
System.out.println("You may pick any number of commands you want.");
System.out
.println("For years and rank, you may select a range of years or ranks.");
System.out
.println("For artists and titles, you may enter a partial name or title.");
System.out.println("i.e, year:1983 rank:1");
Scanner input = new Scanner(System.in);
while (input.hasNextLine()) {
int n = 0;
SongCollection collection = new SongCollection(songs);
String inputType = input.nextLine();
String delims = "[ ]";
String[] tokens = inputType.split(delims);
for (int i = 0; i < tokens.length; i++) {
n = 0;
if (n == 0) {
if ((tokens[i]).contains("year:")) {
collection.filterYear(Range.parse(tokens[i]));
n = 1;
}// end of year loop
if ((tokens[i]).contains("rank:")) {
collection.filterRank(Range.parse(tokens[i]));
n = 1;
}// end of rank
if ((tokens[i]).contains("artist:")) {
collection.filterArtist(tokens[i]);
n = 1;
}// end of artist
if ((tokens[i]).contains("title:")) {
collection.filterTitle(tokens[i]);
n = 1;
}// end of title
if ((tokens[i]).contains("sort:")) {
if ((tokens[i]).contains("title")) {
collection.sortTitle();
n = 1;
}// end of sort title
if ((tokens[i]).contains("artist")) {
collection.sortArtist();
n = 1;
}// end of sort artist
if ((tokens[i]).contains("rank")) {
collection.sortRank();
n = 1;
}// end of sort rank
if ((tokens[i]).contains("year")) {
collection.sortYear();
n = 1;
}// end of sort year
}//end of sort
}// end of for loop
}// end of input.hasNextline loop
final PrintStream console = System.out; //saves original System.out
File outputFile = new File("output.txt"); //output file
PrintStream out = new PrintStream(new FileOutputStream(outputFile)); //new FileOutputStream
System.setOut(out); //changes where data will be printed
System.out.println(collection.toString());
System.setOut(console); //changes output to print back to console
Scanner outputFileScanner = new Scanner(outputFile); //inputs data from file
while ((outputFileScanner.hasNextLine())) { //while the file still has data
System.out.println(outputFileScanner.nextLine()); //print
}
outputFileScanner.close();
out.close();
}
}// end of main
}// end of class
class Song{
public enum Order {Year, Rank, Title, Artist}
public int year;
public int rank;
public String artist;
public String title;
public static Song parse(String s) {
Song instance = new Song();
StringTokenizer tokenizer = new StringTokenizer(s, "\t");
instance.year = Integer.parseInt(tokenizer.nextToken());
instance.rank = Integer.parseInt(tokenizer.nextToken());
instance.artist = (tokenizer.nextToken());
instance.title = (tokenizer.nextToken());
return instance;
}
public int getYear() {
return year;
}
public int getRank() {
return rank;
}
public String getArtist() {
return artist;
}
public String getTitle() {
return title;
}
public String toString() {
String output = "\n\nYear = " + year + "\nRank = " + rank + "\nArtist = "
+ artist + "\nTitle = " + title;
return output;
}
}
class Range {
private int min;
private int max;
public Range() {
System.out.println("Please wait.");
}
public static Range parse(String s) {
Range instance = new Range(); // instance is created here so object
// variables may be accessed
String field; // String to contain deleted part of user input
StringTokenizer tokenizer = new StringTokenizer(s, "-");
StringTokenizer tokenizer2 = new StringTokenizer(s, ":");// for separating "field:" from the
// other part of the String
if (s.contains(":")) { // this deletes the "field:" of the user input so
// it does not interfere with the parsing
field = (tokenizer2.nextToken());
s = s.replace(field, "");
s = s.replace(":", "");
}
if (s.contains("-")) {
instance.min = Integer.parseInt(tokenizer.nextToken());
instance.max = Integer.parseInt(tokenizer.nextToken());
} else if (!(s.contains("-"))) {
{
instance.min = Integer.parseInt(s);
instance.max = Integer.parseInt(s);
}
}
System.out.println("Range max = " + instance.max);
System.out.println("Range min = " + instance.min);
return instance;
}
public boolean contains(int n) {
if (n > min && n < max) { //if the number is contained in the range, method returns true.
return true;
} else if (n == min && n == max) {
return true;
} else {
return false;
}
}
public int getMin() {
return min;
}
public int getMax() {
return max;
}
}
class SongCollection {
ArrayList<Song> songs2;
ArrayList<Song> itemsToRemove = new ArrayList<Song>(); // second collection
// for items to
// remove
public SongCollection(ArrayList<Song> songs) { // constructor for SongCollection
System.out.println("Test");
this.songs2 = songs;
}
public void filterYear(Range r) {
int n = 0;
if (n == 0) {
System.out.println("Program is processing.");
n++;
for (Song song1 : songs2) {
if (song1.year > (r.getMax()) || (song1.year) < (r.getMin())) {
itemsToRemove.add(song1);
}
}
songs2.removeAll(itemsToRemove);
itemsToRemove.clear();
}
System.out.println(songs2);
}
public void filterRank(Range r) {
int n = 0;
if (n == 0) {
System.out.println("Program is processing.");
n++;
for (Song song1 : songs2) {
if (song1.rank > (r.getMax()) || (song1.rank) < (r.getMin())) {
itemsToRemove.add(song1);
}
}
songs2.removeAll(itemsToRemove);
itemsToRemove.clear();
}
System.out.println(songs2);
}
public void filterArtist(String s) {
int n = 0;
if (n == 0) {
System.out.println("Program is processing.");
n++;
for (Song song1 : songs2) {
if ((!(((song1.artist).contains(s))))) {
itemsToRemove.add(song1);
}
}
songs2.removeAll(itemsToRemove);
itemsToRemove.clear();
}
System.out.println(songs2);
}
public void filterTitle(String s) {
int n = 0;
if (n == 0) {
System.out.println("Program is processing.");
n++;
for (Song song1 : songs2) {
if ((!(((song1.title).contains(s))))) {
itemsToRemove.add(song1);
}
}
songs2.removeAll(itemsToRemove);
itemsToRemove.clear();
}
System.out.println(songs2);
}
public void sortTitle() {
Collections.sort(songs2, SongComparator.byTitle()); // now we have a sorted list
System.out.println(songs2);
}
public void sortRank() {
Collections.sort(songs2, SongComparator.byRank()); // now we have a sorted list
System.out.println(songs2);
}
public void sortArtist() {
Collections.sort(songs2, SongComparator.byArtist()); // now we have a sorted list
System.out.println(songs2);
}
public void sortYear() {
Collections.sort(songs2, SongComparator.byYear()); // now we have a sorted list
System.out.println(songs2);
}
public String toString() {
String result = "";
for (int i = 0; i < songs2.size(); i++) {
result += " " + songs2.get(i);
}
return result;
}
}
class SongComparator implements Comparator<Song> {
public enum Order{
YEAR_SORT, RANK_SORT, ARTIST_SORT, TITLE_SORT
}
private Order sortingBy;
public SongComparator(Order sortingBy){
this.sortingBy = sortingBy;
}
public static SongComparator byTitle() {
return new SongComparator(SongComparator.Order.TITLE_SORT);
}
public static SongComparator byYear() {
return new SongComparator(SongComparator.Order.YEAR_SORT);
}
public static SongComparator byArtist() {
return new SongComparator(SongComparator.Order.ARTIST_SORT);
}
public static SongComparator byRank() {
return new SongComparator(SongComparator.Order.RANK_SORT);
}
@Override
public int compare(Song song1, Song song2) {
switch (sortingBy) {
case YEAR_SORT:
return Integer.compare(song1.year, song2.year);
case RANK_SORT:
return Integer.compare(song1.rank, song2.rank);
case ARTIST_SORT:
return song1.artist.compareTo(song2.artist);
case TITLE_SORT:
return song1.title.compareTo(song2.title);
}
throw new RuntimeException(
"Practically unreachable code, can't be thrown");
}
}
推荐答案
您的文本文件数据库中有近 37,000 首歌曲,并且用户可以通过多种方式访问它(按年份、年份范围、排名、排名)-范围,...),包括排序的可能性,我认为几乎需要您使用一次性过程预处理您的歌曲数据库 - 每次数据库更改一次 - 以优化您的在给您的用户机会对其进行查询之前.
With almost 37,000 songs in your text-file database, and a significant number of ways for users to access it (by year, year-range, rank, rank-range, ...), including the possibility of sorting, I think it's almost required that you pre-process your song-database with a one-time-only process--once every time the database is changed--to optimize your data before ever giving your users the chance to query against it.
(我在这里假设您不能使用真正的数据库,这将是理想的解决方案)
(I am making the assumption here that you can't use a real database, which would be the ideal solution)
我建议的第一件事是为每首歌曲分配一个唯一的键 (ID),从 1
开始,在代码中,它应该用长表示.将其设为数据库中的第一列.例如,将其命名为agazillionsongs_with_id.txt
:
The first thing I would recommend is to assign a unique key (ID) to each song, starting with 1
, which, in code, should be represented with a long. Make this the first column in your database. For example, call it agazillionsongs_with_id.txt
:
1 2008 50 Ashley Tisdale He Said, She Said
2 2008 123 Taylor Swift Teardrops On My Guitar
3 2008 233 Finger Eleven Paralyzer
4 2008 258 Paramore Misery Business
...
470 2007 251 Hannah Montana True Friend
471 2006 1 Beyonce Irreplaceable
...
现在在单独的文本文件中创建额外的子表(索引),每个子表都只引用歌曲的键.最简单的是年份索引,它可以存储在一个名为 agazillionsongs_sub_year.txt
的文件中:
Now create additional sub-tables (indexes), in separate text files, each of which simply refer to the song's key. The simplest one is a year-index, which could be stored in a file called agazillionsongs_sub_year.txt
:
2008 1
2008 2
2008 3
2008 4
...
2007 470
...
2006 471
...
或者,您可以以这种形式存储每一年(我更喜欢这种格式)
Alternatively, you could store each year in this form (I prefer this format)
2008 1, 2, 3, 4, ...
2007 470, ...
2006 471, ...
无论哪种方式,这都可以在代码中表示为 yearMap
对象,它是一个 Map
,其中值是一个引用适当的 Song
对象.创建这些地图后,将它们输出到文件很容易.
Either way, this could be represented in code as a yearMap
object, which is a Map<Integer,List<Song>>
, where the value is a reference to the appropriate Song
object. Once these maps are created, outputting them to file is easy.
也使用等级:agazillionsongs_sub_rank.txt
/rankMap
/Map
按名称和标题索引比较棘手——你是索引整个名称,字面意思还是带有一些模糊"的概念,还是只索引开头,......?这是一个很难但很重要的概念.
Indexing by name and title is trickier--do you index the whole name, literally or with some concept of "fuzziness", or only the beginning, ...? It's a hard but important concept.
您越深入地了解这个想法,您对数据进行切片和切块的方式就越多,您的用户查询数据库的速度就越快.这是因为无需每次都读取完整的歌曲数据库,将每一行放入Song
对象中.
The farther you can take this idea, the more ways you slice-and-dice your data, the faster your users can query the database. This is because the need for reading through the full song-database each time, putting every line into a Song
object, is eliminated.
相反,这种预处理允许您确切地知道需要检索数据库中的哪些行.因此,您可以忽略所有其他行并丢弃它们.
Instead, this pre-processing allows you to know exactly which rows in the database need to be retrieved. So you can ignore all other lines and discard them.
希望对你有帮助.
这篇关于将数组列表打印到输出文件中?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!