将ArrayList打印到输出文件中?

3
跟进问题: Java: Printing Arraylist to Output File? 出于某种原因,将ArrayLists打印到输出文件需要很长时间,通常需要20-30分钟。 但是,这仅发生在排序方法或涉及字符串输入的filterTitlefilterArtist方法(方法)时。 当我运行filterRankfilterYear时,它运行得非常好。
当我直接从过滤器方法中打印song2 ArrayList时,唯一打印的是[],这意味着ArrayList为空,但实际上应该不为空。 filterRankfilterYear方法仍然可以正常工作,尽管如此,我认为它们还是有关系的。
输入文件可以在此处找到: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);
}

示例过滤方法(针对字符串)

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 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);
}

主类中的代码用于打印/输出文件

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");
   }

}

这不太清楚。你能提供一个完全可编译的类和一些演示输入吗? - aliteralmind
上次我这样做的时候,没有人回答我的问题,那些回答了的人说代码太多了。你确定吗? - user3450277
输入是我们项目所提供的文件。 - user3450277
你可以在这里获取文件:http://staff.rentonschools.us/hhs/ap-comp-science/projects/download/agazillionsongs.txt?id=223098 - user3450277
请提供一些示例查询,例如 year:1983,包括年份范围和属性组合的示例(例如年份+艺术家姓名或其他)。 - aliteralmind
显示剩余6条评论
1个回答

0

你的文本文件数据库中有近37,000首歌曲,并且用户可以通过多种方式(按年份、年份范围、排名、排名范围等)访问它,包括可能对数据进行排序。因此,在让用户查询之前,我认为几乎必须对歌曲数据库进行一次性预处理,即每次更改数据库时都要进行优化。

(我假设你不能使用真正的数据库,这将是理想的解决方案)

我首先建议给每首歌曲分配一个唯一的键(ID),从1开始,用长整型表示。将其作为数据库中的第一列。例如,命名为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 的文件中:
2008 1
2008 2
2008 3
2008 4
...
2007 470
...
2006 471
...

或者你可以以这种形式存储每年(我更喜欢这种格式)

2008 1, 2, 3, 4, ...
2007 470, ...
2006 471, ...

无论如何,这都可以在代码中表示为一个yearMap对象,它是一个Map<Integer,List<Song>>,其中值是对应的Song对象的引用。一旦创建了这些映射,将它们输出到文件就很容易了。
同样地,使用排名也要这样做:agazillionsongs_sub_rank.txt / rankMap / Map<Integer,List<Song>> 按名称和标题进行索引更加棘手——您是否要索引整个名称,字面上还是带有某种“模糊性”的概念,或者只是开头……?这是一个困难但重要的概念。
您能够深入理解这个想法,以及对数据进行切片和切块的方式越多,用户查询数据库的速度就越快。这是因为消除了每次读取整个歌曲数据库并将每行放入Song对象的需要。
相反,这种预处理允许您准确地知道需要检索数据库中的哪些行。因此,您可以忽略所有其他行并将其丢弃。
我希望这可以帮助您。

这难道不需要我重新做整个项目吗?虽然这是一个有趣的解决方案,但我不知道我是否有时间去做这个。 - user3450277
你知道为什么我的程序会产生奇怪的输出吗? - user3450277
我现在还没有。我只是专注于你问题中关于速度的部分。你是否通过调试器运行它或添加了一堆 System.out.println(...) 来输出处理过程中正在发生的事情? - aliteralmind
我不知道是否能够实现您建议的更改,因为这是明天早上到期,而且我完全不熟悉您所建议的概念。 :/ - user3450277
既然您已经知道如何发布问题,那么请考虑重新发布一个问题,重点放在更多的短期速度修复和错误输出问题上。请声明这是对此问题的跟进,并提供链接。我已经解决了长期的问题,但很遗憾,鉴于您的情况,这并没有太大帮助。我很抱歉造成了误解。非常感谢您为使这个问题更加清晰而付出的努力。只需微调细节即可获得新的帮助。祝您好运。 - aliteralmind
显示剩余4条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接