【问题标题】:Parsing file and sort lines by property按属性解析文件和排序行
【发布时间】:2017-12-04 21:51:25
【问题描述】:

所以基本上有人给了我一个文本文件让我通过 Java 阅读,我必须打印出其中的某些部分。

所以我所做的是将所有文本文件放入String 中,每个单词之间都有一个":"。所以我使用split 函数将所有文本与":" 分开。一开始每一行都是这样的

firstName:Surname:Age:Country
firstName:Surname:Age:Country
firstName:Surname:Age:Country
firstName:Surname:Age:Country
firstName:Surname:Age:Country
firstName:Surname:Age:Country
firstName:Surname:Age:Country
firstName:Surname:Age:Country

后面没有冒号也是一样的。

所以现在如果我说all[0],我会得到all firstNames only

我想要获得的是前 3 个最高年龄,但我不知道该怎么做。

【问题讨论】:

  • “那么现在如果我说 all[0]...” 你有没有尝试使用非零的数组索引?
  • 您要获取整行还是仅获取年龄值?
  • 您可以在阅读该行时将第二个索引作为整数处理并以所需的顺序存储。然后,之后,您只需检索前三个。
  • @wleao 我想得到三个最高的年龄数字

标签: java arrays parsing collections


【解决方案1】:

说明

假设您有一个文件,其中包含如下行

John:Doe:20:USA
Jane:Doe:35:Germany
Robert:Moe:14:Japan
Larry:Loe:25:China
Richard:Roe:27:India

你想要年龄最高的 3 行,那就是

Jane:Doe:35:Germany
Richard:Roe:27:India
Larry:Loe:25:China

程序很简单。首先读取所有行,用: 分割,然后将数据解析到像Person 这样的包装类中。将它们收集到像List<Person> 这样的集合中,并使用比较年龄的Comparator 对它们进行排序。或者,您可以让Person 实现Comparable,然后使用它们的自然顺序。

如果效率很重要,您也可以进行部分排序,因为您只对前 3 个匹配项感兴趣。为此,您可以使用PriorityQueue,插入所有元素并调用poll 三次。


解决方案

首先是Person 包装类

public class Person {
    private String mFirstName;
    private String mSurname;
    private int mAge;
    private String mCountry;

    public Person(String firstName, String surname, int age, String country) {
        this.mFirstName = firstName;
        this.mSurname = surname;
        this.mAge = age;
        this.mCountry = country;
    }

    // TODO Some getters

    public String toString() {
        return this.mFirstName + ":" + this.mSurname
            + ":" + this.mAge + ":" + this.mCountry;
    }

    public static Person parse(String[] data) {
        String firstName = data[0];
        String surname = data[1];
        int age = Integer.parseInt(data[2]);
        String country = data[3];

        return new Person(firstName, surname, age, country);
    }
}

接下来我们读取所有行,拆分数据并将它们解析为Person。之后,我们对结果进行排序并将结果限制为3。最后我们收集到List 并打印结果。

Path file = Paths.get(...);
Pattern separator = Pattern.compile(":");

List<Person> persons = Files.lines(file) // Stream<String>
    .map(separator::splitAsStream)       // Stream<String[]>
    .map(Person::parse)                  // Stream<Person>
    .sorted(Comparator.comparingInt(Person::getAge).reversed())
    .limit(3)
    .collect(Collectors.toList());

persons.forEach(System.out::println);

或者如果您想按照建议使用PriorityQueue,这将改善运行时间:

Path file = Paths.get(...);
Pattern separator = Pattern.compile(":");

PriorityQueue<Person> personQueue = Files.lines(file)
    .map(separator::splitAsStream)
    .map(Person::parse)
    .collect(Collectors.toCollection(() -> {
        return new PriorityQueue<>(
            Comparator.comparingInt(Person::getAge).reversed());
    }));

List<Person> persons = new ArrayList<>(3);
persons.add(personQueue.poll());
persons.add(personQueue.poll());
persons.add(personQueue.poll());

persons.forEach(System.out::println);

【讨论】:

  • +1 以获得详细答案,但我认为 OP 想要前 3 个最高年龄,对吧?因此也许我们需要做Comparator.comparing(Person::getAge).reversed() 而不是Comparator.comparing(Person::getAge)。另外,最好使用Comparator.comparingInt 来避免装箱。
  • @Aominè 是的,好建议。不知道后面的方法,谢谢。
  • 您对此代码使用了哪些导入,以及“路径文件 = Paths.get(...);”的作用是什么意思。
  • @Anwarkhan 当我使用 IDE 时,会自动创建导入。但是不应该有模棱两可的类,一切都是标准库,你自己找到正确的路径应该没有问题。 Path file = Paths.get(...) 是获取 file 引用的现代方式(使用 new File(...) 的旧方式是遗留的)。因此对于...,您将替换文件的路径,例如"dir/otherDir/file.txt",请查看文档
  • 是否有其他方式可以将我的代码发送给您,因为它真的很难,而且两天后到期。
猜你喜欢
  • 2011-02-16
  • 2019-12-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-05-26
相关资源
最近更新 更多