【问题标题】:Printing arraylist into output file?将arraylist打印到输出文件中?
【发布时间】:2014-03-23 02:11:45
【问题描述】:

在此处跟进问题:Java: Printing Arraylist to Output File?

由于某种原因,将ArrayLists 打印到输出文件需要很长时间,通常需要 20-30 分钟。但是,这只发生在 sort 方法或 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");
   }

}

【问题讨论】:

  • 这还不清楚。你能提供一个完整的(可编译的)类和一些演示输入吗?
  • 上次我这样做时,没有人回答我的问题,并且那些回答的人说代码太多。你确定吗?
  • 将相关代码-sn-ps 放在顶部,就像您已经完成的那样,然后将完整工作的代码放在底部。只是说清楚哪个是哪个。 “代码太多”不是问题,而是缺乏关注重点的指导。 (不要忘记演示输入。)
  • @user3450277 你应该发布那个。
  • 我看到你已经按照我的建议做了。我明天看看。我现在在床上 :)

标签: java sorting arraylist filter comparator


【解决方案1】:

您的文本文件数据库中有近 37,000 首歌曲,用户可以通过多种方式访问​​它(按年份、年份范围、排名、排名范围……),包括排序的可能性,我认为几乎需要您使用一次性流程预处理您的歌曲数据库 - 每次更改数据库时 - 以优化您的数据,然后再让您的用户有机会查询它。

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

我建议的第一件事是为每首歌曲分配一个唯一键 (ID),以 1 开头,在代码中应该用 long 表示。将其设为数据库中的第一列。比如叫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&lt;Integer,List&lt;Song&gt;&gt;,其中值是对适当Song 对象的引用。创建这些地图后,将它们输出到文件很容易。

也可以使用排名:agazillionsongs_sub_rank.txt / rankMap / Map&lt;Integer,List&lt;Song&gt;&gt;

按名称和标题进行索引比较棘手——您是按字面意思还是使用某种“模糊性”概念来索引整个名称,还是只索引开头,...?这是一个很难但很重要的概念。

您可以将这个想法付诸实践,您对数据进行切片和切块的方式越多,您的用户查询数据库的速度就越快。这是因为无需每次都读取完整的歌曲数据库,将每一行放入 Song 对象中。

相反,这种预处理可以让您准确地知道数据库中需要检索哪些行。因此,您可以忽略所有其他行并丢弃它们。

希望对你有帮助。

【讨论】:

  • 那不需要我重做整个项目吗?我不知道我是否有时间这样做,虽然这是一个有趣的解决方案
  • 其中很大一部分,是的。只需一步一步,例如只需添加 ID 并从 with_id 输入文件中读取(将 ID 添加到 Song 对象)。下一步是添加年份索引,并在特别要求年份时利用它。这些是任何具有大型数据集的大型项目中的问题,对于文本文件数据库来说,37,000 个项目是相当大的。即使你没有时间专门做我的建议,也许这些概念可以在更小的范围内实施。无论如何,我希望它至少有所帮助。祝你好运。
  • 你知道为什么我的程序会产生奇怪的输出吗?
  • 我现在还没有。我只关注您问题的速度问题部分。你是通过调试器运行它还是添加了一堆System.out.println(...)s 来输出处理过程中发生的事情?
  • 我有,但目前还没有什么清楚的。我只是不明白。一切似乎都运行良好。除了它不是。