[Info]Tags categorized posts and contents patterns..

[AJAX] Ajax Code E xamples.. [Book] About the book.. [CSS] CSS Code E xamples.. [DB] Sql Code E xamples.. [DEV] All development stor...

레이블이 List인 게시물을 표시합니다. 모든 게시물 표시
레이블이 List인 게시물을 표시합니다. 모든 게시물 표시

2016년 4월 6일 수요일

[JAVA]Guava로 리스트에서 객체의 필드로 새로운 리스트 만들기..

출처 : Outsider's Dev Story https://blog.outsider.ne.kr/

List<Person>같은 컬렉션을 가지고 있을 때 Person클래스의 특정필드만을 가지고 새로운 리스트를 만들고 싶었습니다. for문으로 돌면서 새로운 리스트를 만들어도 되지만 Guava를 쓰면 쉽게 만들 수 있었습니다.

Java
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
// Person.java
package kr.sideeffect;

public class Person {
  private String name;
  private int age;
    
  public Person(String name, int age) {
    this.name = name;
    this.age = age;
  }
    
  public String getName() {
    return name;
  }
  public void setName(String name) {
    this.name = name;
  }
  public int getAge() {
    return age;
  }
  public void setAge(int age) {
    this.age = age;
  }
}

지난번 Ordering에 대한 포스팅에서도 사용했던 Person클래스입니다.(새로 만들기가 귀찮아서...) Guava에는 List<F>를 List<F>로 바꿔주는 Lists.transform함수를 제공하고 있는데 정의는 다음과 같습니다.


Java

1
2
3
4
5
public static <F,T>
  List<T> transform(
    List<F> fromList,
    Function<? super F,? extends T> function
  )

transform함수는 변환할 대상이 되는 리스트를 받고 이 리스트를 어떻게 변환할지를 정하는 Function을 두번째 파라미터로 받아서 새로운 리스트를 만들어줍니다.

Java
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
// PersonTest.java
package kr.sideeffect;

import static org.junit.Assert.*;

import java.util.ArrayList;
import java.util.List;
import org.junit.Test;
import com.google.common.base.Function;
import com.google.common.collect.Lists;

public class PersonTest {
    
  @Test
  public void 필테스트() throws Exception {
    // given
    Person p1 = new Person("Outsider", 32);
    Person p2 = new Person("nephlim", 40);
    Person p3 = new Person("Anarcher", 35);
    Person p4 = new Person("fupfin", 43);
    Person p5 = new Person("Arawn", 33);
        
    List<Person> list = new ArrayList<Person>();
    list.add(p1);
    list.add(p2);
    list.add(p3);
    list.add(p4);
    list.add(p5);
        
    // when
    Function<Person, String> nameFilter = new Function<Person, String>() {
        public String apply(Person person) {
          return person.getName();
        }
    };
        
    List<String> result = Lists.transform(list, nameFilter);

    // then
    assertEquals(result.size(), 5);
    assertEquals(result.get(0), p1.getName());
  }
}

여기서는 Person을 담고 있는 리스트인 list에서 Person의 name만으로 만들어진 새로운 리스트를 만들려고 하는 것이기 때문에 nameFilter라는 Function객체를 만들었습니다.  이 객체는 Person타입에서 String타입으로 변환되기 때문에 Function<Person, String>으로 정의했습니다. 변환하는 함수는 클래스 내부의 apply함수로 정의하는데 apply함수는 Person을 받아서 String을 리턴해 주도록 만들었고 내부에서 name의 값을 리턴해 줍니다. 이를 Lists.transform(list, nameFilter)와 같이 사용하면 name만 담긴 새로운 리스트를 만들어줍니다.

디버그모드에서 result의 타입을 확인한 화면

list는 ArrayList였지만 transform이 리턴해주는 리스트는 ArrayList는 아닙니다. 디버그로 찍어보면 위처럼 나오는데 정확한 타입은 잘 모르겠네요. 이를 ArrayList로 변환하려면 다음과 같이 작성할 수 있습니다.


Java
1
2
// ArrayList로 변환
List<String> result = Lists.newArrayList(Lists.transform(list, nameFilter));

Lists에 static함수로 newArrayList가 제공되기 때문에 간단하게 ArrayList로 변환할 수 있습니다.

Java
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
Function<Person, String> nameFilter = new Function<Person, String>() {
  public String apply(Person person) {
    return person == null ? null : person.getName();
  }
};

List<String> result = Lists.newArrayList(Iterables.filter(
    Iterables.transform(list, nameFilter), 
    Predicates.<String>notNull()
  ));

만약 null에 대한 체크가 필요하다면 위처럼 할 수 있습니다. 이건 Guava의 Iterables.transform과 Iterables.filter를 조합한 것입니다. 8번라인을 보면 Lists.transform대신에 Iterables.transform를 사용해서 변환을 하고 변환된 리스트를 다시 Iterables.filter에 Predicates를 사용해서 null인 객체를 모두 제거해 주었습니다. 물론 nameFilter에서는 person이 null일 경우 null을 리턴해주도록 했습니다.

즉흥적으로 찾아보면서 쓰고 있는지라 제대로 쓰고 있는지는 잘 모르겠네요 Lists.transform외에도 Iterables.transform, Iterators.transform, Collections2.transform등이 존재하는데 제대로 안서봐서 차이점들은 잘 모르겠습니다.


2016년 4월 5일 화요일

[JAVA]List에서 중복요소 제거한 List로 만들기..

출처 : Outsider's Dev Story https://blog.outsider.ne.kr/

자바에서 List를 사용하다가 List가 가진 요소들 중 중복된 것을 제거하고 유일한 값들만 가지고 있는 List를 만들어야 할 필요가 있었습니다. 루프를 돌면서 유니크한 값을 찾아서 새로운 배열을 만들자니 약간 귀찮았는데 해쉬셋을 이용해서 간단하게 유일한 요소들만 가진 List로 만들 수 있더군요.

Java
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
List<Integer> items = new ArrayList<Integer>();
items.add(1);
items.add(2);
items.add(1);
items.add(2);
items.add(3);
items.add(3);
System.out.println(items); // [1, 2, 1, 2, 3, 3]

List<Integer> uniqueItems = new ArrayList<Integer>(new HashSet<Integer>(items));
System.out.println(uniqueItems); // [1, 2, 3]

중복되는 요소들을 가질 리스트를 HashSet으로만든뒤에 다시 List로 변환을 하면 중복요소가 사라진 유일한 요소들만 가진 리스트를 만들 수 있습니다.

덧) 저의 경우에는 필요치 않았지만 HashSet을 사용할 경우 순서가 지켜지지 않을 수 있다는 얘기가 있었습니다.

덧2) 김은석님이 List의 contains와의 성능비교를 공유해 주셨습니다.


My Comment..
흠.. 현재 SM 소스를 검색해보니 과거 2013년에 사용한 흔적이 있었다.. 거기에 주석도 코멘트 했었구나.. 배열처리 중복제거 라고.. ㅋㅋㅋ.. 햄보다 2년정도 늦게 쓰긴 했는데 쓰긴 했었구나.. 다만 햄은 기록을 해서 새로운 것에 대해서 항상 남겨두는 편인데 나는 그게 아니였다능.. 무튼 지금이라도 검색해서 다시 한번 기억속에서 상기시키니 스믈스믈 떠오르고 있다..