如何按Java中的2个字段对对象进行排序

huangapple go评论72阅读模式
英文:

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 &#212;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&lt;String&gt; voiceActors = new ArrayList&lt;&gt;();	
ArrayList&lt;Cartoon&gt; cartoons = new ArrayList&lt;&gt;();	
//read each line
String line = in.readLine();
while (line != null) {
String[] columns = line.split(&quot;\\t&quot;);
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 &#212;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&lt;CartoonYear&gt; readAndSortByYear(String inFile) throws IOException {
return Files.readAllLines(Paths.get(inFile))
.parallelStream()
.map(line -&gt; line.split(&quot;\\t&quot;))
.map(columns -&gt; 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 &#212;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 &#212;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&lt;String, List&lt;Cartoon&gt;&gt; readAndGroupByYearAndTitle(String inFile) throws IOException {
    return Files.readAllLines(Paths.get(inFile))
      .parallelStream()
      .map(line -&gt; line.split(&quot;\\t&quot;))
      .map(columns -&gt; new Cartoon(Integer.parseInt(columns[0]), columns[1], columns[2]))
      .collect(Collectors.groupingBy(cartoon -&gt; String.format(&quot;%4d %s&quot;, cartoon.year, cartoon.title)));
  }

  public static void main(String[] args) throws IOException {
    Map&lt;String, List&lt;Cartoon&gt;&gt; cartoonsGrouped = readAndGroupByYearAndTitle(args[0]);
    cartoonsGrouped.keySet()
      .parallelStream()
      .sorted()
      .forEachOrdered(group -&gt; {
        boolean firstElement = true;
        for (Cartoon cartoonYear : cartoonsGrouped.get(group)) {
          if (firstElement) {
            System.out.printf(&quot;%4d  %-25s  %s%n&quot;, cartoonYear.year, cartoonYear.title, cartoonYear.voiceActor);
            firstElement = false;
          }
          else
            System.out.printf(&quot;%4s  %-25s  %s%n&quot;, &quot;&quot;, &quot;&quot;, 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 &#212;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 &#212;tani
voice actor2
2000  Cartoon                    voice actor

huangapple
  • 本文由 发表于 2020年8月14日 12:16:28
  • 转载请务必保留本文链接:https://go.coder-hub.com/63406463.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定