英文:
How to Sort objects by 2 fields Java
问题
你想要将文件按年份排序,并在多线程中读取文件。以下是示例代码,将多线程和归并排序结合在一起以实现你的目标:
import java.io.*;
import java.util.*;
import java.util.concurrent.*;
public class CartoonReader {
public static void main(String[] args) {
// Read the file into a list of cartoons
List<Cartoon> cartoons = readCartoonsFromFile("your_file.txt");
// Specify the number of threads to use for sorting
int numThreads = 4; // Adjust as needed
// Divide the list of cartoons into equal parts for each thread
List<List<Cartoon>> partitions = partitionList(cartoons, numThreads);
// Create a thread pool
ExecutorService executor = Executors.newFixedThreadPool(numThreads);
// Create a list to store the sorted partitions
List<List<Cartoon>> sortedPartitions = new ArrayList<>();
// Submit sorting tasks to the thread pool
for (List<Cartoon> partition : partitions) {
Callable<List<Cartoon>> sortingTask = () -> {
Collections.sort(partition); // Sort the partition by year
return partition;
};
Future<List<Cartoon>> future = executor.submit(sortingTask);
try {
sortedPartitions.add(future.get()); // Collect sorted partitions
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
}
// Shutdown the thread pool
executor.shutdown();
// Merge the sorted partitions
List<Cartoon> mergedCartoons = mergeSortedPartitions(sortedPartitions);
// Print the merged result
for (Cartoon cartoon : mergedCartoons) {
System.out.println(cartoon);
}
}
// Read cartoons from the file and return a list
private static List<Cartoon> readCartoonsFromFile(String filename) {
List<Cartoon> cartoons = new ArrayList<>();
try (BufferedReader in = new BufferedReader(new FileReader(filename))) {
String line;
while ((line = in.readLine()) != null) {
String[] columns = line.split("\t");
if (columns.length == 3) {
Cartoon c = new Cartoon(Integer.parseInt(columns[0]), columns[1], columns[2]);
cartoons.add(c);
}
}
} catch (IOException e) {
e.printStackTrace();
}
return cartoons;
}
// Partition a list into equal parts for multithreading
private static <T> List<List<T>> partitionList(List<T> list, int numPartitions) {
List<List<T>> partitions = new ArrayList<>();
int partitionSize = (int) Math.ceil((double) list.size() / numPartitions);
for (int i = 0; i < list.size(); i += partitionSize) {
partitions.add(list.subList(i, Math.min(i + partitionSize, list.size())));
}
return partitions;
}
// Merge sorted partitions
private static List<Cartoon> mergeSortedPartitions(List<List<Cartoon>> partitions) {
List<Cartoon> mergedList = new ArrayList<>();
PriorityQueue<Cartoon> minHeap = new PriorityQueue<>(Comparator.comparingInt(Cartoon::getYear));
for (List<Cartoon> partition : partitions) {
minHeap.addAll(partition);
}
while (!minHeap.isEmpty()) {
mergedList.add(minHeap.poll());
}
return mergedList;
}
}
请将"your_file.txt"替换为你要读取的文件路径。这段代码将文件中的卡通数据读取、多线程排序,然后合并排序的结果。
英文:
The file I am trying to read looks like this:
1995 Pokemon Ikue Ôtani
1940 Tom and Jerry William Hanna
1995 Pokemon voice actor2
1940 Tom and Jerry voice actor3
2000 Cartoon voice actor
It has around 20k rows. I already got the reading the file and storing the data in an object.
in = new BufferedReader(new FileReader(cartoonsFile));
ArrayList<String> voiceActors = new ArrayList<>();
ArrayList<Cartoon> cartoons = new ArrayList<>();
//read each line
String line = in.readLine();
while (line != null) {
String[] columns = line.split("\\t");
String year = columns[0];
String cartoon = columns[1];
String voiceActor = columns[2];
//make new object and store data
Cartoon c = new Cartoon(Integer.parseInt(columns[0]),
columns[1], columns[2]));
cartoons.add(c); //add to the array list
Object
public class Cartoon {
private int year;
private String title;
private String voiceActor;
public Cartoon(int year, String title, String voiceActor) {
this.year = year;
this.title = title;
this.voiceActor = voiceActor;
}
};
I would like to read the file in threads and sort by year. Can anyone provide sample code on how can multithread and merge sort be implemented together?
The output that I'd like to get
1940 Tom and Jerry William Hanna
voice actor2
voice actor3
voice actor4
voice actor5
1995 Pokemon Ikue Ôtani
voice actor2
A Cartoon voice actor1
voice actor2
voice actor3
2000 Cartoon voice actor
答案1
得分: 0
尝试这个。
List<CartoonYear> readAndSortByYear(String inFile) throws IOException {
return Files.readAllLines(Paths.get(inFile))
.parallelStream()
.map(line -> line.split("\t"))
.map(columns -> new CartoonYear(Integer.parseInt(columns[0]), columns[1], columns[2]))
.sorted(Comparator.comparing(CartoonYear::getYear))
.collect(Collectors.toList());
}
如果您需要进一步的翻译或有其他问题,请随时提出。
英文:
Try this.
List<CartoonYear> readAndSortByYear(String inFile) throws IOException {
return Files.readAllLines(Paths.get(inFile))
.parallelStream()
.map(line -> line.split("\\t"))
.map(columns -> new CartoonYear(Integer.parseInt(columns[0]), columns[1], columns[2]))
.sorted(Comparator.comparing(CartoonYear::getYear))
.collect(Collectors.toList());
}
答案2
得分: 0
以下是翻译好的部分:
坚持使用您的数据结构(只是将其从相当奇特的`CartoonYear`重命名为`Cartoon`),并且继续使用@saka1029的Java流的良好方法(而不是手动实现合并排序算法),您可以这样做:
public class Cartoon {
private int year;
private String title;
private String voiceActor;
public Cartoon(int year, String title, String voiceActor) {
this.year = year;
this.title = title;
this.voiceActor = voiceActor;
}
public static Map<String, List<Cartoon>> readAndGroupByYearAndTitle(String inFile) throws IOException {
return Files.readAllLines(Paths.get(inFile))
.parallelStream()
.map(line -> line.split("\t"))
.map(columns -> new Cartoon(Integer.parseInt(columns[0]), columns[1], columns[2]))
.collect(Collectors.groupingBy(cartoon -> String.format("%4d %s", cartoon.year, cartoon.title)));
}
public static void main(String[] args) throws IOException {
Map<String, List<Cartoon>> cartoonsGrouped = readAndGroupByYearAndTitle(args[0]);
cartoonsGrouped.keySet()
.parallelStream()
.sorted()
.forEachOrdered(group -> {
boolean firstElement = true;
for (Cartoon cartoonYear : cartoonsGrouped.get(group)) {
if (firstElement) {
System.out.printf("%4d %-25s %s%n", cartoonYear.year, cartoonYear.title, cartoonYear.voiceActor);
firstElement = false;
}
else
System.out.printf("%4s %-25s %s%n", "", "", cartoonYear.voiceActor);
}
});
}
}
这只是快速而粗糙的代码,不是我引以为傲的代码。您要求每个组只打印年份和标题一次,也不会使代码更加简洁,使用if-else
也不会使代码更好。但假设您有这样的输入文件:
1995 Pokemon Ikue Ôtani
1940 Tom and Jerry William Hanna
11 Sample foo
1995 Pokemon voice actor2
1940 Tom and Jerry voice actor3
2000 Cartoon voice actor
11 Sample bar
您将获得如下输出:
11 Sample foo
bar
1940 Tom and Jerry William Hanna
voice actor3
1995 Pokemon Ikue Ôtani
voice actor2
2000 Cartoon voice actor
英文:
Sticking with your data structure (just renaming it from the rather peculiar CartoonYear
to Cartoon
), and also sticking with the good approach of using Java streams by @saka1029 (instead of manually implementing a merge sort algorithm), you could do something like this:
package org.acme;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
public class Cartoon {
private int year;
private String title;
private String voiceActor;
public Cartoon(int year, String title, String voiceActor) {
this.year = year;
this.title = title;
this.voiceActor = voiceActor;
}
public static Map<String, List<Cartoon>> readAndGroupByYearAndTitle(String inFile) throws IOException {
return Files.readAllLines(Paths.get(inFile))
.parallelStream()
.map(line -> line.split("\\t"))
.map(columns -> new Cartoon(Integer.parseInt(columns[0]), columns[1], columns[2]))
.collect(Collectors.groupingBy(cartoon -> String.format("%4d %s", cartoon.year, cartoon.title)));
}
public static void main(String[] args) throws IOException {
Map<String, List<Cartoon>> cartoonsGrouped = readAndGroupByYearAndTitle(args[0]);
cartoonsGrouped.keySet()
.parallelStream()
.sorted()
.forEachOrdered(group -> {
boolean firstElement = true;
for (Cartoon cartoonYear : cartoonsGrouped.get(group)) {
if (firstElement) {
System.out.printf("%4d %-25s %s%n", cartoonYear.year, cartoonYear.title, cartoonYear.voiceActor);
firstElement = false;
}
else
System.out.printf("%4s %-25s %s%n", "", "", cartoonYear.voiceActor);
}
});
}
}
This was just quick & dirty, not code I am proud of. Your requirement to only print year and title once per group does not make the code nicer with the if-else
either. But assuming you have an input file like this:
1995 Pokemon Ikue Ôtani
1940 Tom and Jerry William Hanna
11 Sample foo
1995 Pokemon voice actor2
1940 Tom and Jerry voice actor3
2000 Cartoon voice actor
11 Sample bar
you will get output like this:
11 Sample foo
bar
1940 Tom and Jerry William Hanna
voice actor3
1995 Pokemon Ikue Ôtani
voice actor2
2000 Cartoon voice actor
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论