对象列表-获取对象字段不同计数

s5a0g9ez  于 2021-07-11  发布在  Java
关注(0)|答案(2)|浏览(366)

对于对象列表,我必须检查(某些)字段:
对该字段具有相同值的所有对象
对该字段具有不同值的所有对象

class Person {
   final String name;
   final int age;
   final int group;

   public Person( final String name, final int age, final int group ) {
      this.name = name;
      this.age = age;
      this.group = group;
   }

   public String getName() {
      return this.name;
   }

   public int getAge() {
      return this.age;
   }

   public int getGroup() {
      return this.group;
   }
}

public static <T> long distinctByField( final List<Person> personList, final Function<Person, T> field ) {
   return personList.stream()
         .map( field )
         .distinct().count();
}

public static void main( final String[] args ) {
   final List<Person> personList = Arrays.asList(
         new Person( "Fred", 25, 1 ),
         new Person( "Bill", 22, 1 ),
         new Person( "Fred", 27, 1 ),
         new Person( "Lisa", 25, 1 )
   );

   System.out.println( distinctByField( personList, Person::getName ) );
   System.out.println( distinctByField( personList, Person::getAge ) );
   System.out.println( distinctByField( personList, Person::getGroup ) );
}

根据stream/distinct/count的结果,我可以与当前列表大小进行比较:
if count==1:该字段具有相同值的所有对象
if count==list.size:该字段具有不同值的所有对象
缺点是,我必须为每一个感兴趣的领域流。
是否可以通过一个查询来实现这一点(对于感兴趣的字段列表)?

5fjcxozz

5fjcxozz1#

可以使用反射:

public class ReflectionTest {

    class Person {
        final String name;
        final int age;
        final int group;

        public Person(final String name, final int age, final int group) {
            this.name = name;
            this.age = age;
            this.group = group;
        }

        public String getName() {
            return this.name;
        }

        public int getAge() {
            return this.age;
        }

        public int getGroup() {
            return this.group;
        }
    }

    @DisplayName("should determine distinct fields")
    @Test
    public void distinct() {
        final List<Person> personList = Arrays.asList(new Person("Fred", 25, 1),
                                                      new Person("Bill", 22, 1),
                                                      new Person("Fred", 27, 1),
                                                      new Person("Lisa", 25, 1));
        Map<String,Long> fieldCountMap = Stream.of("name", "age", "group")
                                                  .map(fieldName -> ReflectionUtils.findField(Person.class, fieldName))
                                                  .filter(Objects::nonNull)
                                                  .collect(Collectors.toMap(Field::getName, field -> personList.stream().map(person -> getField(field, person)).distinct().count()));

        assertEquals(3,fieldCountMap.get("name"));
        assertEquals(1,fieldCountMap.get("group"));
        assertEquals(3,fieldCountMap.get("age"));
    }

    //extracted into a method because field.get throws a checked exception
    Object getField(Field field, Person object) {
        try {
            return field.get(object);
        } catch (IllegalAccessException e) {
            throw new RuntimeException(e);
        }
    }

}
3z6pesqy

3z6pesqy2#

首先让我提一下:这或多或少是代码质量的一个巨大缺点(手动搜索所有字段,使用一个额外的类来存储结果)。我怀疑,这在计算时间或内存方面会更有效。按照逻辑,您必须接触每个人的每个字段并存储已经发生的值,以便找到每个字段的不同计数。这正是你的3流解决方案所做的。我劝你还是坚持下去。
但这里有一个解决办法。我构建了一个收集器,它在一次运行中将每个字段的所有不同值收集到一个自定义类中。

static class PersonStatistic {
    Set<String> names = new HashSet<>();
    Set<Integer> ages = new HashSet<>();
    Set<Integer> groups = new HashSet<>();
  }

  public static void main(final String[] args) {
    final List<Person> personList = Arrays.asList(
        new Person("Fred", 25, 1),
        new Person("Bill", 22, 1),
        new Person("Fred", 27, 1),
        new Person("Lisa", 25, 1));

    PersonStatistic personStatistic = personList.stream().collect(
        // Create new Statistic
        PersonStatistic::new, 
        // Merge A Person into statistic
        (statistic, person) -> {
          statistic.names.add(person.name);
          statistic.ages.add(person.age);
          statistic.groups.add(person.group);
        },
        // Merge second statistic into first
        (stat1, stat2)-> {
          stat1.names.addAll(stat2.names);
          stat1.ages.addAll(stat2.ages);
          stat1.groups.addAll(stat2.groups);
        });

    System.out.println(personStatistic.names.size());
    System.out.println(personStatistic.ages.size());
    System.out.println(personStatistic.groups.size());
  }

相关问题