2012-06-07 12 views
7

Ho List<Integer> composto da Id dei miei utenti. E dopo una query del database, sto recuperando List<User>. Vorrei ordinare questa lista in base alla prima lista di identificazione. List<User> potrebbe non includere alcuni degli ID. Qual è il modo Guava per ordinare questo elenco?Modo guava di ordinare Elenco in base a un altro elenco?

risposta

12

Il modo completamente "funzionale", usando Guava, unisse Ordering#explicit() con 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); 
    } 

} 

Si potrebbe dichiarare una funzione inline anonima, ma mi piace dichiarare le mie funzioni di metodi factory statici in una classe separata, per un codice più pulito (la verbosità di dichiarazioni di funzioni di Java è nascosto nella classe di utilità):

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

Con java 8 è possibile eliminare l'intera funzione e utilizzare invece un riferimento al metodo. La riga sarebbe quindi simile a questa (e nessuna funzione aggiuntiva): Ordering orderById = Ordering.explicit (userIds) .onResultOf (User :: getId); – Arne

9

Non credo che Guava abbia qualcosa di specifico per farlo. Ma è solo una questione di scrivere questo comparatore:

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); 
    } 
} 

Ora che ci penso, ma può anche essere implementato in questo modo:

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()); 
    } 
} 

che è probabilmente più efficiente.

+1

Questo non è efficiente a causa del requisito di tempo lineare del metodo indexOf. Grazie – Cemo

+0

Vedere la mia risposta modificata. –

2

Altri hanno già risposto alla tua domanda utilizzando Guava. Ecco una risposta Functional Java.

Si prega di notare che sarà necessario utilizzare strutture di dati immutabili dalla libreria al fine di usufruire di tutta la bontà.

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

Grazie :) Adoro anche questa libreria. :) – Cemo

+0

A parte: in Scala, la soluzione sarebbe solo 'userList.sortBy (idList.indexOf (_. Id))'. – missingfaktor

+0

Otterremo qualcosa di simile con java 8;) – Premraj

0

risposta più semplice l'utilizzo di Google Guava

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

Ecco come fare questo con Java 8 lambda.

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

Penso che sia necessario assicurarsi che nessun nullo appaia come id, poiché l'OP ha detto che potrebbero esserci dei null –

Problemi correlati