从文件中读取数据并打印数据的唯一特定实例



我试图操作这个练习,但执行起来很困难。输入是从文件中扫描的。然后将信息格式化为其输出。

csv文件当前包含以下信息:

16:40,Wonders of the World,G
20:00,Wonders of the World,G
19:00,End of the Universe,NC-17
12:45,Buffalo Bill And The Indians or Sitting Bull's History Lesson,PG
15:00,Buffalo Bill And The Indians or Sitting Bull's History Lesson,PG
19:30,Buffalo Bill And The Indians or Sitting Bull's History Lesson,PG
10:00,Adventure of Lewis and Clark,PG-13
14:30,Adventure of Lewis and Clark,PG-13
19:00,Halloween,R

但我的输出是这样的:

Wonders of the World                         |     G | 16:40
Wonders of the World                         |     G | 20:00
End of the Universe                          | NC-17 | 19:00
Buffalo Bill And The Indians or Sitting Bull |    PG | 12:45
Buffalo Bill And The Indians or Sitting Bull |    PG | 15:00
Buffalo Bill And The Indians or Sitting Bull |    PG | 19:30
Adventure of Lewis and Clark                 | PG-13 | 10:00
Adventure of Lewis and Clark                 | PG-13 | 14:30
Halloween                                    |     R | 19:00

我需要能够只输出一部有放映时间的电影,所以它看起来像这样。

Wonders of the World                         |     G | 16:40 20:00
End of the Universe                          | NC-17 | 19:00
Buffalo Bill And The Indians or Sitting Bull |    PG | 12:45 15:00 19:30
Adventure of Lewis and Clark                 | PG-13 | 10:00 14:30
Halloween                                    |     R | 19:00

到目前为止我的代码:

public class LabProgram4 {
public static void main(String[] args) throws IOException {
String filename = "movies.csv";
int recordCount = 0;
Scanner fileScanner = new Scanner(new File(filename));
while (fileScanner.hasNextLine()) {
fileScanner.nextLine();
++recordCount;
}
String[] showtimes = new String[recordCount];
String[] title = new String[recordCount];
String[] rating = new String[recordCount];
fileScanner.close();
fileScanner = new Scanner(new File(filename));
for (int i = 0; i < recordCount; ++i) {
String[] data = fileScanner.nextLine().strip().split(",");
showtimes[i] = data[0].strip();
title[i] = data[1].strip();
rating[i] = data[2].strip();
}
fileScanner.close();
for (int i = 0; i < recordCount; ++i) {
if (title[i].length() > 44)
title[i] = title[i].substring(0, 44);
System.out.printf("%-44s | %5s | %sn", title[i], rating[i], showtimes[i]);
}
}
}
public static final class Movie {
private String title;
private String showTime;
private String rating;
}
public static void main(String... args) throws FileNotFoundException {
List<Movie> movies = readMovies(new File("d:/movies.csv"));
Map<String, List<Movie>> map = movies.stream().collect(Collectors.groupingBy(movie -> movie.title));
print(map);
}
private static void print(Map<String, List<Movie>> map) {
int titleWidth = getTitleWidth(map);
int ratingWidth = getRatingWidth(map);
map.forEach((title, movies) -> {
String rating = movies.stream().map(movie -> movie.rating).distinct().collect(Collectors.joining(" "));
String showTime = movies.stream().map(movie -> movie.showTime).distinct().sorted().collect(Collectors.joining(" "));
System.out.format("%-" + titleWidth + "s | %-" + ratingWidth + "s | %sn", title, rating, showTime);
});
}
private static int getTitleWidth(Map<String, List<Movie>> map) {
return map.keySet().stream()
.mapToInt(String::length)
.max().orElse(0);
}
private static int getRatingWidth(Map<String, List<Movie>> map) {
return map.values().stream()
.mapToInt(movies -> movies.stream()
.map(movie -> movie.rating)
.distinct()
.mapToInt(String::length)
.sum())
.max().orElse(0);
}
private static final int SHOW_TIME = 0;
private static final int TITLE = 1;
private static final int RATING = 2;
private static List<Movie> readMovies(File file) throws FileNotFoundException {
try (Scanner scan = new Scanner(file)) {
List<Movie> movies = new ArrayList<>();
while (scan.hasNext()) {
String[] data = scan.nextLine().split(",");
Movie movie = new Movie();
movie.title = data[TITLE].trim();
movie.showTime = data[SHOW_TIME].trim();
movie.rating = data[RATING].trim();
movies.add(movie);
}
return movies;
}
}

在我看来,仅仅为了获取记录数量(比如说(而读取一次文件是错误的做法。读取文件一次,然后在读取文件时执行任务。

有很多方法可以读取文件并以独特的方式存储或显示记录(例如没有重复的标题(。我认为使用并行数组存储数据是一种方法,但这些数组需要初始化为特定的长度,因为它们不能动态增长。尽管并非不可能,但在这种特殊情况下,这是一个相当大的问题,与使用Collection对象(如List Interface、ArrayList等(相比,执行任务需要更多的代码,因为可以动态增长

下面的代码使用java.util.List接口来存储并稍后显示从movies.csv文件读取的电影。代码看起来很长,但大部分都是注释。我建议你阅读这些评论,如果你喜欢删除它们,因为它们太多了:

// The Movies data file name.
String filename = "movies.csv";
// Counter to keep track of the number of movies stored.
int moviesCount = 0;
// List Interface object to store movie titles in.
java.util.List<String> movies = new java.util.ArrayList<>();

// 'Try With Resources' used here to auto-close the reader
try (Scanner reader = new Scanner(new File(filename))) {
// Read the data file line by line.
String dataLine;
while (reader.hasNextLine()) {
dataLine = reader.nextLine().trim();
// Skip blank lines...
if (dataLine.isEmpty()) {
continue;
}
/* The regex ("\s*,\s*") passed to the String#split() method 
below handles  any number of whitespaces before or after the 
comma delimiter on any read in data file line.  */
String[] data = dataLine.split("\s*,\s*"); 
/* Do we already have title in the 'movies' List?
If so just add the show-time to the title and
continue on to the next file data line.       */
boolean alreadyHave = false;  // Flag that we don't already have this title
for (int i = 0; i < movies.size(); i++) {
// Do we already have the movie title in the list?
if (movies.get(i).contains(data[1])) {
// Yes we do so flag it that we already do have this title.
alreadyHave = true;
// Add the additional show-time to that title's stored information
movies.set(i, movies.get(i) + " " + data[0]);
/* Break out of this 'for' loop since there is no 
more need to check other titles in the List. */
break; 
}
}
/* If however we don't already have this movie title 
in the List then add it in the desired display 
format using the Pipe (|) character as a delimiter. */
if (!alreadyHave) {
moviesCount++;  // Increment the number of movies 
movies.add(String.format("%s | %s | %s", data[1], data[2], data[0]));
}
}
}
// DISPLAY THE MOVIES LIST IN TABLE STYLE FASHION
// Display Title in Console Window:
String msg = "There are " + moviesCount + " movies with various show-times:";
System.out.println(msg);  // Print title
// Display Table Header:
String header = String.format("%-44s | %6s | %s", "Movie Title", "Rating", "Show Times");
String overUnderline = String.join("", java.util.Collections.nCopies(header.length(), "="));
// Header Overline
System.out.println(overUnderline);
System.out.println(header);
// Header Underline
System.out.println(overUnderline);
// Display the movies in console window.
for (String movie : movies) {
/* Split the current List element into its respective parts
using the String#split() method so that the List contents
can be displayed in a table format. The regex passed t0 
the 'split()' method ("\s*\|\s*") will take care of any
whitespaces before or after any Pipe (|) delimiter so that 
String#trim() or String#strip() is not required. Note that
the Pipe (|) delimiter needs to be escaped (\|) within the
expression so as to acquire is literal meaning since it is 
a regex meta character.                          */
String[] movieParts = movie.split("\s*\|\s*");
/* 'Ternary Operators' are used in the String#format() data
section components so to truncate movie Title Names to the 
desire table cell width of 44 and to convert Rating and
Show-Times to "N/A" should they EVER be empty (contain no
data).            */
System.out.println(String.format("%-44s | %6s | %s", 
(movieParts[0].length() > 44 ? movieParts[0].substring(0, 44) : movieParts[0]), 
(movieParts[1].isEmpty() ? "N/A" : movieParts[1]), 
(movieParts[2].isEmpty() ? "N/A" : movieParts[2])));
}
System.out.println(overUnderline);

如果数据文件实际上包含你在帖子中指出的内容,那么上面的代码将在控制台窗口中显示以下内容:

There are 5 movies with various show-times:
==================================================================
Movie Title                                  | Rating | Show Times
==================================================================
Wonders of the World                         |      G | 16:40 20:00
End of the Universe                          |  NC-17 | 19:00
Buffalo Bill And The Indians or Sitting Bull |     PG | 12:45 15:00 19:30
Adventure of Lewis and Clark                 |  PG-13 | 10:00 14:30
Halloween                                    |      R | 19:00
==================================================================

最新更新