2015-05-03 16 views
25

Ho due elenchi e desidero filtrare gli elementi thoose che contengono entrambi gli elenchi. E voglio farlo con espressione lambda.Java 8 Filtro lambda da elenchi

Gli utenti getName e Client getUserName sono entrambi restituiti con String.

Ecco il mio codice di esempio:

List<Client> clients = new ArrayList<>(); 
List<User> users = new ArrayList<>(); 
List<Client> results = new ArrayList<>(); 

for (Client user : users) { 
    for(Client client: clients){ 
     if(user.getName().equals(client.getUserName())){ 
      result.add(client); 
     } 
    } 
} 
+2

Il tuo codice non verrà compilato; un 'User' non è un' Client', a meno che 'User' non erediti' Client'. – fge

risposta

47
Predicate<Client> hasSameNameAsOneUser = 
    c -> users.stream().anyMatch(u -> u.getName().equals(c.getName())); 

return clients.stream() 
       .filter(hasSameNameAsOneUser) 
       .collect(Collectors.toList()); 

Ma questo è abbastanza inefficiente, perché è O (m * n). Faresti meglio a creare una serie di nomi accettabili:

Set<String> acceptableNames = 
    users.stream() 
     .map(User::getName) 
     .collect(Collectors.toSet()); 

return clients.stream() 
       .filter(c -> acceptableNames.contains(c.getName())) 
       .collect(Collectors.toList()); 

Si noti inoltre che non è strettamente equivalente al codice che avete (se compilato), che aggiunge lo stesso cliente due volte per la lista se diversi utenti hanno la stesso nome del cliente.

+0

Sono curioso di sapere come la seconda implementazione sia più efficiente? Sembra che sia ancora O (m * n) per me. Quando facciamo acceptNames.contains (...) stiamo attraversando quel set. L'idea che il Set eliminerà i duplicati è leggermente migliore O (m * n)? –

+2

No. La chiamata contiene() su una lista attraversa la lista. Ma chiamare contiene su un HashSet calcola semplicemente hashCode e attraversa il bucket corrispondente a hashCode, che in genere contiene 0 o 1 elemento. Un HashSet contiene la ricerca è O (1). –

+1

Ah, capisco. La chiamata a .taintains() su una lista sarebbe O (n), ma O (1) su HashSet. Grazie per il chiarimento! –

0

Qualcosa di simile:

clients.stream.filter(c->{ 
    users.stream.filter(u->u.getName().equals(c.getName()).count()>0 
}).collect(Collectors.toList()); 

Questo non è però un modo terribilmente efficace per farlo. A meno che le raccolte non siano molto piccole, sarà meglio creare un insieme di nomi utente e utilizzarli nella condizione.

+1

Qui non stiamo confrontando gli oggetti con il loro metodo 'equals'. Per favore rileggi la domanda – Pshemo

+1

Vedo l'approccio corretto nella risposta, ma ci sono ancora problemi minori con esso. Si prega di non pubblicare la risposta se prima non l'avete testata.Non c'è vergogna a cancellarlo per evitare ulteriori downgoting e confusione, correggendolo * nelle ombre * e annullandolo quando è corretto. – Pshemo

1

Guardate questo:.

List<Client> result = clients 
    .stream() 
    .filter(c -> 
     (users.stream().map(User::getName).collect(Collectors.toList())).contains(c.getName())) 
     .collect(Collectors.toList()); 
+0

'users.stream(). Map (User :: getName) .collect (Collectors.toList())' È più efficiente se si utilizza Collectors.toSet() per utenti distinti user.name –

1

Vorrei condividere un esempio per capire l'utilizzo del flusso() filtrare

Snippet di codice: Esempio di programma per identificare numero pari.

import java.util.ArrayList; 
import java.util.List; 
import java.util.stream.Collectors; 

public void fetchEvenNumber(){ 
     List<Integer> numberList = new ArrayList<>(); 
     numberList.add(10); 
     numberList.add(11); 
     numberList.add(12); 
     numberList.add(13); 
     numberList.add(14); 
     numberList.add(15); 

     List<Integer> evenNumberListObj = numberList.stream().filter(i -> i%2 == 0).collect(Collectors.toList()); 
     System.out.println(evenNumberListObj); 
} 

uscita sarà:. [10, 12, 14]

Elenco evenNumberListObj = numberList.stream() filtrata (i -> i% 2 == 0) .Raccogliere (Collectors.toList ());

numberlist: si tratta di un oggetto ArrayList contiene un elenco di numeri.

java.util.Collection.stream(): flusso() otterrà il flusso di raccolta, che restituirà il flusso di Integer.

filtro: restituisce un flusso che corrisponde al predicato specificato. In base alla condizione data (i -> i% 2! = 0) restituisce il flusso corrispondente.

raccogliere: qualunque sia il flusso di filtro di Integer con sede alla condizione di filtro, quelli intero sarà messo in un elenco.