2012-06-07 19 views
7

Tengo List<Integer> que consiste en Id. De mis usuarios. Y después de una consulta de base de datos, estoy recuperando List<User>. Me gustaría ordenar esta lista de acuerdo a la primera lista de identificación. List<User> puede no incluir algunos de los ID. ¿Cuál es la forma de Guava para ordenar esta lista?Guava modo de clasificación ¿Lista según otra lista?

Respuesta

12

La forma totalmente "funcional", usando la guayaba, combinaría 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); 
    } 

} 

Se puede declarar una función en línea en el anonimato, pero me gusta hablar de mis funciones como métodos de fábrica estáticos en una clase separada, para un código más limpio (el nivel de detalle de las declaraciones de funciones de Java está escondido en la clase de utilidad):

/** 
* 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 puede deshacerse de toda la función y utilizar una referencia de método en su lugar. La línea se vería así (y sin función adicional): Ordenando orderById = Ordering.explicit (userIds) .onResultOf (User :: getId); – Arne

9

No creo que Guava tenga nada específico para hacer esto. Pero es sólo una cuestión de escribir este comparador:

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

Ahora que lo pienso, también se puede implementar de esta manera:

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

que es probablemente más eficiente.

+1

Esto no es eficiente debido al requisito de tiempo lineal del método indexOf. Gracias – Cemo

+0

Ver mi respuesta editada. –

2

Otros ya han respondido a su pregunta usando la guayaba. Aquí hay una respuesta Functional Java.

Tenga en cuenta que tendrá que utilizar estructuras de datos inmutables de la biblioteca para aprovechar todas las bondades.

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

Gracias :) También amo esta biblioteca. :) – Cemo

+0

Un lado: en Scala, la solución sería simplemente 'userList.sortBy (idList.indexOf (_. Id))'. – missingfaktor

+0

Obtendremos algo similar con java 8;) – Premraj

0

respuesta más simple a través de Google guayaba

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

Aquí está cómo hacer esto con Java 8 lambdas.

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

Creo que debes asegurarte de que no aparezcan nulos como id, ya que el OP dijo que podría haber nulos –

Cuestiones relacionadas