2016-10-13 21 views
5

Tôi có luồng Java lambda phân tích tệp và lưu trữ kết quả vào bộ sưu tập, dựa trên một số bộ lọc cơ bản.Luồng Java Lambda vào các bộ sưu tập khác nhau

Tôi chỉ học lambdas nên chịu với tôi ở đây nếu điều này là ridiculously xấu. Nhưng xin vui lòng chỉ ra những sai lầm của tôi.

Đối với một tập tin đưa ra:

#ignored 
this 
is 
#ignored 
working 
fine 

Mã:

List<String> matches; 

Stream<String> g = Files.lines(Paths.get(givenFile)); 

matches = g.filter(line -> !line.startsWith("#")) 
      .collect(Collectors.toList()); 

["this", "is", "working", "fine"] 

Bây giờ, làm thế nào tôi sẽ đi về thu thập các dòng bỏ qua vào một danh sách thứ hai trong cùng một dòng này? Một cái gì đó như:

List<String> matches; 
List<String> ignored; // to store lines that start with # 

Stream<String> g = Files.lines(Paths.get(exclusionFile.toURI())); 

matches = g.filter(line -> !line.startsWith("#")) 
      // how can I add a condition to throw these 
      // non-matching lines into the ignored collection? 
      .collect(Collectors.toList()); 

Tôi nhận thấy nó khá tầm thường để mở luồng mới, thay đổi logic một chút và .collect() các dòng bị bỏ qua đủ dễ dàng. Nhưng tôi không muốn phải lặp qua tệp này hai lần nếu tôi có thể làm tất cả trong một luồng.

+0

nó phải giống như 'g.filter (..). Bản đồ (t-> t :: toString)) thu thập (.. toList())' –

+0

Xem ví dụ cuối cùng trong tài liệu Oracle: https: //docs.oracle.com/javase/8/docs/api/java/util/stream/Collectors.html – Gene

Trả lời

13

Thay vì hai con suối, bạn có thể sử dụng partitioningBy trong Collector

List<String> strings = Arrays.asList("#ignored", "this", "is", "#ignored", "working", "fine"); 
Map<Boolean, List<String>> map = strings.stream().collect(Collectors.partitioningBy(s -> s.startsWith("#"))); 
System.out.println(map); 

đầu ra

{false=[this, is, working, fine], true=[#ignored, #ignored]} 

ở đây tôi sử dụng chủ chốt như Boolean nhưng bạn có thể thay đổi nó thành một chuỗi có ý nghĩa hoặc enum

EDIT

Nếu chuỗi có thể bắt đầu với một số ký tự đặc biệt khác mà bạn có thể sử dụng groupingBy

List<String> strings = Arrays.asList("#ignored", "this", "is", "#ignored", "working", "fine", "!Someother", "*star"); 
    Function<String, String> classifier = s -> { 
     if (s.matches("^[[email protected]#$%^&*]{1}.*")) { 
      return Character.toString(s.charAt(0)); 
     } else { 
      return "others"; 
     } 
    }; 
    Map<String, List<String>> maps = strings.stream().collect(Collectors.groupingBy(classifier)); 
    System.out.println(maps); 

Output

{!=[!Someother], #=[#ignored, #ignored], *=[*star], others=[this, is, working, fine]} 

bạn cũng có thể tổ groupingBypartitioningBy

+1

Điều này làm việc rất tốt, cảm ơn. – AWT

1

Tôi nghĩ gần nhất có thể đến đây một cách tiếp cận chung cho điều này sẽ là một cái gì đó giống như peek:

g.peek(line -> if (line.startsWith("#")) { 
    ignored.add(line); 
}) 
.filter(line -> !line.startsWith("#")) 
// how can I add a condition to throw these 
// non-matching lines into the ignored collection? 
.collect(Collectors.toList()); 

Tôi đề cập đến nó vì không giống với phân vùng Collector bạn có thể, ít nhất là về mặt lý thuyết, thay đổi với nhau theo số lượng peek mà bạn muốn - nhưng, như bạn thấy, bạn phải lặp lại logic, vì vậy nó không lý tưởng.

Các vấn đề liên quan