按多个属性分组

rhfm7lfc  于 2021-07-03  发布在  Java
关注(0)|答案(4)|浏览(282)

我有一个java类:

class Person {
  String firstName;
  String lastName;
  int income;

public Person(String firstName, String lastName, int income)
{
  this.firstName = firstName;
  this.lastName = lastName;
  this.income = income;
}

我有一个 Collection<Person> ,具有4个person对象:

Collection<Person> persons = new ArrayList<>();
  persons.add(new Person("John", "Smith", 5));
  persons.add(new Person("Mary", "Miller", 2));
  persons.add(new Person("John", "Smith", 4));
  persons.add(new Person("John", "Wilson", 4));

我想创建一个新的集合示例,但是从具有相同“firstname”和“lastname”的元素中,创建1个元素,结果“income”将是每个元素的“incomes”之和。因此,对于这种特殊情况,得到的集合将有3个元素,“john smith”将有“income”=9。
在sql中,等效的查询是:

SELECT FIRSTNAME, LASTNAME, SUM(INCOME) FROM PERSON GROUP BY FIRSTNAME, LASTNAME

我只找到了包含map作为结果的答案,“key”包含用于分组的列。我想直接从最初的( ArrayList<Person> ),而不是Map,因为如果在我的集合中有数百万个元素,则会降低代码的性能。我知道如果我在sql端工作会更容易,但在这种情况下,我必须在java端工作。

vmpqdwk3

vmpqdwk31#

我认为josql是您的发展方向,它允许您在java对象上运行sql查询:
josql(sql for java objects)为开发人员提供了将sql语句应用于java对象集合的能力。josql提供了搜索、排序和分组任何java对象的能力,当您希望对java对象集合执行类似sql的查询时,应该应用josql。
以下是如何在您的案例中使用它:

Query q=new Query();
q.parse("SELECT firstname, lastname, SUM(income) FROM package.Person GROUP BY firstname, lastname");
List<?> results=q.execute(names).getResults();

您还可以按照这个josql教程进一步阅读。

m3eecexj

m3eecexj2#

我不知道这是不是最好的解决办法,但你可以试试
groupBy firstName 以及 lastName 在它们之间有一个分隔符 . . 在你把数据收集到 Map<String, Integer> 包含你的 firstName.lastName ,则创建新的 Person 从它那里。

List<Person> collect = persons.stream()
            .collect(Collectors.groupingBy(person -> person.getFirstName() + "." + person.getLastName(),
                    Collectors.summingInt(Person::getIncome)))
            .entrySet().stream().map(entry -> new Person(entry.getKey().split(".")[0],
                                                                      entry.getKey().split(".")[1],
                                                                      entry.getValue()))
            .collect(Collectors.toList());
jecbmhm3

jecbmhm33#

您可以使用java 8 streams的收集器分组方式:

Map<String, Integer> sum = items.stream().collect(
            Collectors.groupingBy(p -> p.getFirstName()+p.getSecondName(), Collectors.summingInt(Person::getIncome)));
kuuvgm7e

kuuvgm7e4#

我发现答案如下:

List<Person> collect = persons.stream()
            .collect(Collectors.groupingBy(person -> person.getFirstName() + "." + person.getLastName(),
                    Collectors.summingInt(Person::getIncome)))
            .entrySet().stream().map(entry -> new Person(entry.getKey().split(".")[0],
                                                                      entry.getKey().split(".")[1],
                                                                      entry.getValue()))
            .collect(Collectors.toList());

不要那样做!它占用了很多内存。在需要分组的字段上使用 Package 器(personcomparator)。

public class Main {
    public static void main(String[] args) {
        Collection<Person> persons = new ArrayList<>();
        persons.add(new Person("John", "Smith", 5));
        persons.add(new Person("Mary", "Miller", 2));
        persons.add(new Person("John", "Smith", 4));
        persons.add(new Person("John", "Wilson", 4));

        Map<Person, Integer> groupedByIncomes = persons.stream()
                .collect(
                        Collectors.groupingBy(
                                Person::getPersonComparator,
                                Collectors.summingInt(Person::getIncome)
                        )
                )
                .entrySet()
                .stream()
                .collect(Collectors.toMap(
                        e -> e.getKey().person,
                        Map.Entry::getValue
                ));

        System.out.println(groupedByIncomes);
    }

    static class Person {
        String firstName;
        String lastName;
        int income;

        public Person(String firstName, String lastName, int income) {
            this.firstName = firstName;
            this.lastName = lastName;
            this.income = income;
        }

        public String getFirstName() {
            return firstName;
        }

        public String getLastName() {
            return lastName;
        }

        public int getIncome() {
            return income;
        }

        PersonComparator getPersonComparator() {
            return new PersonComparator(this);
        }

        static class PersonComparator {
            Person person;

            PersonComparator(Person person) {
                this.person = person;
            }

            @Override
            public boolean equals(Object o) {
                if (this == o) return true;
                if (o == null || getClass() != o.getClass()) return false;
                PersonComparator that = (PersonComparator) o;
                if (!person.getFirstName().equals(that.person.getFirstName())) return false;
                return person.getLastName().equals(that.person.getLastName());
            }

            @Override
            public int hashCode() {
                int result = person.getFirstName().hashCode();
                result = 31 * result + person.getLastName().hashCode();
                return result;
            }
        }
    }
}

如果您需要框架解决方案f.e.当您需要对现有的数据类型(sql、mongo或collections)进行抽象时,我建议您使用querydsl:http://www.querydsl.com/

相关问题