Java 8에서 여러 필드 이름으로 그룹화
POJO의 일부 필드 이름으로 개체를 그룹화하는 코드를 찾았습니다. 다음은 이에 대한 코드입니다.
public class Temp {
static class Person {
private String name;
private int age;
private long salary;
Person(String name, int age, long salary) {
this.name = name;
this.age = age;
this.salary = salary;
}
@Override
public String toString() {
return String.format("Person{name='%s', age=%d, salary=%d}", name, age, salary);
}
}
public static void main(String[] args) {
Stream<Person> people = Stream.of(new Person("Paul", 24, 20000),
new Person("Mark", 30, 30000),
new Person("Will", 28, 28000),
new Person("William", 28, 28000));
Map<Integer, List<Person>> peopleByAge;
peopleByAge = people
.collect(Collectors.groupingBy(p -> p.age, Collectors.mapping((Person p) -> p, toList())));
System.out.println(peopleByAge);
}
}
그리고 출력은 다음과 같습니다.
{24=[Person{name='Paul', age=24, salary=20000}], 28=[Person{name='Will', age=28, salary=28000}, Person{name='William', age=28, salary=28000}], 30=[Person{name='Mark', age=30, salary=30000}]}
하지만 여러 필드로 그룹화하려면 어떻게해야합니까? 해당 POJO에서 groupingBy()
메서드를 구현 한 후 equals()
메서드에서 일부 POJO를 분명히 전달할 수 있지만 주어진 POJO에서 둘 이상의 필드로 그룹화 할 수있는 다른 옵션이 있습니까?
예를 들어 여기 제 경우에는 이름과 나이별로 그룹화하고 싶습니다.
여기에 몇 가지 옵션이 있습니다. 가장 간단한 방법은 수집가를 연결하는 것입니다.
Map<String, Map<Integer, List<Person>>> map = people
.collect(Collectors.groupingBy(Person::getName,
Collectors.groupingBy(Person::getAge));
그런 다음 Fred라는 18 세 노인 목록을 얻으려면 다음을 사용합니다.
map.get("Fred").get(18);
두 번째 옵션은 그룹화를 나타내는 클래스를 정의하는 것입니다. 이것은 Person 내부에있을 수 있습니다.
class Person {
public static class NameAge {
public NameAge(String name, int age) {
...
}
// must implement equals and hash function
}
public NameAge getNameAge() {
return new NameAge(name, age);
}
}
그런 다음 다음을 사용할 수 있습니다.
Map<NameAge, List<Person>> map = people.collect(Collectors.groupingBy(Person::getNameAge));
및 검색
map.get(new NameAge("Fred", 18));
마지막으로 자신 만의 그룹 클래스를 구현하고 싶지 않다면 주변의 많은 Java 프레임 워크에는 pair
정확히 이러한 유형의 클래스를 위해 설계된 클래스 가 있습니다 . 예 : apache commons pair 이러한 라이브러리 중 하나를 사용하는 경우 맵에 대한 키를 이름과 연령 쌍으로 만들 수 있습니다.
Map<Pair<String, Integer>, List<Person>> map =
people.collect(Collectors.groupingBy(p -> Pair.of(p.getName(), p.getAge())));
다음으로 검색 :
map.get(Pair.of("Fred", 18));
개인적으로 저는이 튜플 라이브러리를 정말 싫어합니다. 그들은 좋은 OO 디자인의 정반대 인 것처럼 보입니다. 의도를 노출하는 대신 숨 깁니다.
자신의 그룹화 클래스를 정의하여 두 번째 두 옵션을 결합 할 수 있지만 확장하여 구현할 수 있다고 말했지만 Pair
정의 equals
와 관련된 많은 작업을 절약 하고 튜플의 사용을 다른 것과 같은 편리한 구현 세부 사항으로 숨 깁니다. 다른 컬렉션.
행운을 빕니다.
여기 코드를보세요 :
당신은 단순히 Function을 생성하고 그것이 당신을 위해 일하도록 할 수 있습니다. 일종의 기능적 스타일!
Function<Person, List<Object>> compositeKey = personRecord ->
Arrays.<Object>asList(personRecord.getName(), personRecord.getAge());
이제지도로 사용할 수 있습니다.
Map<Object, List<Person>> map =
people.collect(Collectors.groupingBy(compositeKey, Collectors.toList()));
건배!
이 groupingBy
메소드에는 첫 번째 매개 변수가 있습니다 Function<T,K>
.
@param
<T>
입력 요소의 유형@param
<K>
키 유형
코드에서 람다를 익명 클래스로 바꾸면 다음과 같은 것을 볼 수 있습니다.
people.stream().collect(Collectors.groupingBy(new Function<Person, int>() {
@Override
public int apply(Person person) {
return person.getAge();
}
}));
이제 출력 매개 변수를 변경하십시오 <K>
. 예를 들어,이 경우에는 org.apache.commons.lang3.tuple의 페어 클래스를 이름과 연령별로 그룹화했지만 필요에 따라 그룹 필터링을위한 고유 한 클래스를 만들 수 있습니다.
people.stream().collect(Collectors.groupingBy(new Function<Person, Pair<Integer, String>>() {
@Override
public YourFilter apply(Person person) {
return Pair.of(person.getAge(), person.getName());
}
}));
마지막으로 람다로 바꾼 후 코드는 다음과 같습니다.
Map<Pair<Integer,String>, List<Person>> peopleByAgeAndName = people.collect(Collectors.groupingBy(p -> Pair.of(person.getAge(), person.getName()), Collectors.mapping((Person p) -> p, toList())));
안녕하세요 당신은 단순히 다음 groupingByKey
과 같은 것을 연결할 수 있습니다.
Map<String, List<Person>> peopleBySomeKey = people
.collect(Collectors.groupingBy(p -> getGroupingByKey(p), Collectors.mapping((Person p) -> p, toList())));
//write getGroupingByKey() function
private String getGroupingByKey(Person p){
return p.getAge()+"-"+p.getName();
}
그룹에서 키 정의를위한 클래스를 정의하십시오.
class KeyObj {
ArrayList<Object> keys;
public KeyObj( Object... objs ) {
keys = new ArrayList<Object>();
for (int i = 0; i < objs.length; i++) {
keys.add( objs[i] );
}
}
// Add appropriate isEqual() ... you IDE should generate this
}
이제 코드에서
peopleByManyParams = people
.collect(Collectors.groupingBy(p -> new KeyObj( p.age, p.other1, p.other2 ), Collectors.mapping((Person p) -> p, toList())));
I needed to make report for a catering firm which serves lunches for various clients. In other words, catering may have on or more firms which take orders from catering, and it must know how many lunches it must produce every single day for all it's clients !
Just to notice, I didn't use sorting, in order not to over complicate this example.
This is my code :
@Test
public void test_2() throws Exception {
Firm catering = DS.firm().get(1);
LocalDateTime ldtFrom = LocalDateTime.of(2017, Month.JANUARY, 1, 0, 0);
LocalDateTime ldtTo = LocalDateTime.of(2017, Month.MAY, 2, 0, 0);
Date dFrom = Date.from(ldtFrom.atZone(ZoneId.systemDefault()).toInstant());
Date dTo = Date.from(ldtTo.atZone(ZoneId.systemDefault()).toInstant());
List<PersonOrders> LON = DS.firm().getAllOrders(catering, dFrom, dTo, false);
Map<Object, Long> M = LON.stream().collect(
Collectors.groupingBy(p
-> Arrays.asList(p.getDatum(), p.getPerson().getIdfirm(), p.getIdProduct()),
Collectors.counting()));
for (Map.Entry<Object, Long> e : M.entrySet()) {
Object key = e.getKey();
Long value = e.getValue();
System.err.println(String.format("Client firm :%s, total: %d", key, value));
}
}
참고URL : https://stackoverflow.com/questions/28342814/group-by-multiple-field-names-in-java-8
'Nice programing' 카테고리의 다른 글
주어진 달의 첫날과 마지막 날을 얻는 방법 (0) | 2020.11.29 |
---|---|
Bash에서 작은 따옴표 문자열에서 작은 따옴표를 이스케이프하는 방법은 무엇입니까? (0) | 2020.11.29 |
Vue @click 이벤트 핸들러에 매개 변수를 전달하는 방법 (0) | 2020.11.29 |
정규식으로 괄호 안의 텍스트를 제거하려면 어떻게해야합니까? (0) | 2020.11.29 |
ImageMagick을 사용하여 안티 앨리어싱을 사용하여 SVG를 투명 PNG로 변환 (0) | 2020.11.29 |