2012-06-07 3 views
7

나는 내 사용자의 ID로 구성된 List<Integer>을 가지고 있습니다. 그리고 데이터베이스 쿼리 후 List<User>을 검색하고 있습니다. 첫 번째 ID 목록에 따라이 목록을 주문하고 싶습니다. List<User>에는 일부 ID가 포함되지 않을 수 있습니다. 이 목록을 정렬하기위한 Guava 방식은 무엇입니까?구아바 정렬 방식 다른 목록으로 목록이 있습니까?

답변

12

완전 "기능"방법, 구아바를 사용하여, 당신은 익명 함수를 인라인으로 선언 할 수 Ordering#onResultOf()

public class UserService { 

    @Inject private UserDao userDao; 

    public List<User> getUsersWithIds(List<Integer> userIds) { 
     List<User> users = userDao.loadUsersWithIds(userIds); 
     Ordering<User> orderById = Ordering.explicit(userIds).onResultOf(UserFunctions.getId()); 
     return orderById.immutableSortedCopy(users); 
    } 

} 

으로 Ordering#explicit()을 결합,하지만 별도의 클래스에서 static 팩토리 메소드로 내 함수를 선언하고 싶습니다, 깨끗한 코드 (자바의 함수 선언의 상세는 유틸리티 클래스에 숨겨져) :

/** 
* Static factory methods to create {@link Function}s for {@link User}s. 
*/ 
public final class UserFunctions { 
    private UserFunctions() { /* prevents instantiation */ } 

    /** 
    * @return a {@link Function} that returns an {@link User}'s id. 
    */ 
    public static Function<User, Integer> getId() { 
     return GetIdFunction.INSTANCE; 
    } 

    // enum singleton pattern 
    private enum GetIdFunction implements Function<User, Integer> { 
     INSTANCE; 

     public Integer apply(User user) { 
      return user.getId(); 
     } 
    } 

} 
+1

java 8을 사용하면 전체 함수를 없애고 대신 메서드 참조를 사용할 수 있습니다. 그러면 행은 다음과 같이 표시됩니다 (추가 기능은 없습니다). orderById = Ordering.explicit (userIds) .onResultOf (User :: getId); – Arne

9

구아바에는이 작업을 수행하는 데 특정한 것이 없다고 생각합니다. 그러나이 비교기를 작성 단지 문제 :

Collections.sort(userList, new Comparator<User>() { 
    @Override 
    public int compare(User u1, User u2) { 
     int i1 = idList.indexOf(u1.getId()); 
     int i2 = idList.indexOf(u2.getId()); 
     return Ints.compare(i1, i2); 
    } 
} 

을 지금은 그것에 대해, 또한이 방법으로 구현 될 수 생각 : 아마 더 효율적입니다

final Ordering<Integer> idOrdering = Ordering.explicit(idList); 
Collections.sort(userList, new Comparator<User>() { 
    @Override 
    public int compare(User u1, User u2) { 
     return idOrdering.compare(u1.getId(), u2.getId()); 
    } 
} 

합니다.

+1

이것은 인덱스 시간 메서드의 선형 시간 요구 때문에 효율적이지 않습니다. 감사합니다 – Cemo

+0

내 편집 된 답변보기 –

2

다른 사람이 이미 구아바를 사용하여 질문에 대답했다. 여기 Functional Java 답변입니다.

라이브러리의 불변의 데이터 구조를 사용해야 모든 이점을 얻을 수 있습니다. 구글 구아바

class Form { 
    public Integer index; // for simplicity, no setter/getter included 
} 

List<Form> forms = ... // list instances, each of each with values for index 

// ordering of forms by the ui sort index. 
private static final Ordering<Form> sorter = Ordering.natural().onResultOf(new Function<Form, Integer>() { 

    @Override 
    public Integer apply(Form form) { 
     return form.index; 
    } 
}); 

private List<Form> sortForms(List<Form> forms) { 
    return sorter.sortedCopy(forms); 
} 
+0

감사합니다 :)이 라이브러리를 너무 사랑해. :) – Cemo

+0

별다른 생각 : 스칼라에서 솔루션은 단지'userList.sortBy (idList.indexOf (_. id))'가 될 것입니다. – missingfaktor

+0

우리는 자바 8과 비슷한 것을 얻을 것입니다;) – Premraj

0

간단한 대답은 여기에 자바 8 람다이 작업을 수행하는 방법은 다음과 같습니다.

List<Integer> ids = ...; List<User> users = ...; 
//map ids to their list indices, to avoid repeated indexOf calls 
Map<Integer, Integer> rankMap = IntStream.range(0, ids.size()).boxed() 
    .collect(Collectors.toMap(ids::get, Function.identity())); 
//sort on the id's position in the list 
users.sort(Comparator.comparing(u -> rankMap.get(u.id()))); 
0

를 사용

F<User, Integer> indexInIdList = new F<User, Integer>() { 
    public Integer f(User u) { 
    return idList.elementIndex(Equal.intEqual, u.getId()).toNull(); 
    } 
}; 
userList.sort(Ord.intOrd.comap(indexInIdList)); 
+0

나는 OP가 null이있을 수 있다고 말했듯이, 당신이 ID로 나타나지 않는지 확인해야한다고 생각합니다. –

관련 문제