2015-09-01 17 views
19

Mam listę ścieżek plików:.Jak usunąć elementy z listy z lambda na podstawie innej listy

List<Path> filePaths; //e.g. [src\test\resources\file\15\54\54_exampleFile.pdf] 

54 powyżej odnosi się do pliku identyfikatora

I wtedy otrzymać Set od String identyfikatorów, które moja aplikacja może obsługiwać w następujący sposób:

Set<String> acceptedIds = connection.getAcceptedIDs(); //e.g. elements [64, 101, 33] 

jaki sposób można użyć Java 8 lambdy do filter zewnątrz wszystkie elementy w filePaths, które nie zawierają żadnych akceptowanych identyfikatorów, które są zawarte w zestawie kolekcji acceptedIds.

Innymi słowy, chciałbym zachować w filePaths tylko te ścieżki, które mają identyfikatory, które są w zestawie acceptedIds. Na przykład 54 nie ma na powyższej liście, więc jest usuwany.

filePaths.stream().filter(...).collect(Collectors.toList()); 
+1

Czy możemy polegać na bezpośrednim katalogu nadrzędnym o nazwie o identyfikatorze? – Bohemian

+4

filePaths.removeIf (p ->! AcceptedIds.contains (p.getPath()) –

Odpowiedz

22

Najskuteczniejszym sposobem jest wyodrębnienie identyfikatora ze ścieżki, a następnie próbować odnaleźć go w zestawie, dzięki czemu każdy filtr wykonać w stałym czasie, tj O(1) dając ogólny O(n) gdzie n jest liczba ścieżek:

filePaths.stream() 
    .filter(p -> acceptedIds.contains(p.getParent().getFileName().toString())) 
    .collect(Collectors.toList()); 

Jeśli odwrotne podejście jest wykonane, gdzie każdy acceptedIds jest przeszukiwana w ścieżce (jak w innych odpowiedzi), a każdy filtr jest O(m*k), trakt Ponownie m jest numerem acceptedIds i k jest średnią długość ścieżki, co daje ogólną O(n * m * k), która będzie działać bardzo słabo nawet dla średnich rozmiarów kolekcji.

+0

jak mam "przycinać()" identyfikatory dla białych znaków podczas wyodrębniania? – user2781389

+0

Gdzie jest biała przestrzeń? W ścieżce, np. '' Src \ test \ resources \ file \ 15 \ 54 \ 54_exampleFile.pdf "' (nazwa katalogu to '" 54 "' - spacją) lub wartości zapisane w 'acceptedIds'? – Bohemian

+0

wartości przechowywane w 'acceptIds' – user2781389

3

można napisać:

filePaths.stream() 
     .filter(p -> acceptedIds.stream().anyMatch(id -> p.toString().contains(id))) 
     .collect(toList()); 

filtruje każdą ścieżkę tak, że co najmniej jeden z acceptedIds zawartych w reprezentacji ciąg ścieżki. W zależności od przypadku użycia (na przykład zgodnego z początkiem nazwy pliku) może zaistnieć potrzeba wprowadzenia czegoś lepszego niż contains.

anyMatch to operacja, która określa, czy co najmniej jeden element pasuje do podanego predykatu.

Należy zauważyć, że ta odpowiedź nie zawiera żadnych założeń dotyczących ścieżki do odfiltrowywania elementów. Jeśli możesz bezpiecznie powiedzieć, że w każdej ścieżce, katalog nadrzędny ma nazwę z identyfikatorem, zdecydowanie powinieneś iść z odpowiedzią @Bohemian, ze względu na wydajność.

+1

'p.toString(). Zawiera (id)' implikuje '" 54 ".contains (" 4 ")' lub '" 543 " .contains ("4") "Wątpię, żeby to pasowało do intencji OP – Holger

+0

@Holger Zgadzam się, dlatego powiedziałem, że może on chcieć zaimplementować coś lepszego (jak dopasowanie początku nazwy pliku). – Tunaki

1

tak:

List removeMissing(List l1, List l2) { 
    List ret = l1.stream() 
     .filter(o -> l2.contains(o)) //Keep if object o satisfies the condition "l2 contains a reference to this object" 
     .collect(Collectors.toList()); 
    return ret; 
} 
0

Jeśli twoja struktura nazw plików jest stała, użyłabym najpierw wyrażeń regularnych, aby wyodrębnić numer, a następnie sprawdzi, czy jest to jeden z pożądanych identyfikatorów.

final Set<String> acceptedIds = ... 
// Matches the number of the file, concluded with the underscore 
final Pattern extractor = Pattern.compile("\.*(?<number>\d+)_") 
filePaths.stream().filter(path -> { 
    final Matcher m = extractor 
     .matcher(path.getFileName().toString()); 
    m.find(); 
    return acceptedIds.contains(m.group("number")); 
}) 
... 
Powiązane problemy