2012-06-07 10 views
7

List<Integer>は、私のユーザーのIDで構成されています。データベースクエリの後に、私はList<User>を取得しています。私は最初のIdリストに従ってこのリストを注文したいと思います。 List<User>にはIdの一部が含まれていない可能性があります。このリストをソートするためのGuavaの方法は何ですか?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ファクトリメソッドとしての私の関数を宣言したいと思い、クリーンなコード(Javaの関数宣言の冗長性は、ユーティリティクラスに隠されている)のために:

/** 
* 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

私はGuavaにこれを行うための具体的なことはないと思います。しかし、ちょうどこのコンパレータを書くの問題です:

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

これは、indexOfメソッドの線形時間要件のために効率的ではありません。ありがとう – Cemo

+0

私の編集した答えを見てください。 –

2

その他は、すでにグァバを使用して、あなたの質問に答えています。ここにはFunctional Javaの回答があります。

ライブラリの不変なデータ構造を使用して、すべての利点を利用する必要があることに注意してください。 Googleのグアバ

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

脇に:Scalaでは、ソリューションは 'userList.sortBy(idList.indexOf(_。id))'になります。 – missingfaktor

+0

私はjava 8と似たようなものを得ます;) – Premraj

0

より単純な答えはここでのJava 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としてnullが表示されないようにする必要があると思います –