2017-07-01 20 views
9

Tôi có mã sau lặp lại qua các kết hợp mẫu "E".."EEEE""M".."MMMM" của Java DateTimeFormatter.Kết hợp các luồng của các đoạn nối

Câu hỏi của tôi là, có cách thức thành ngữ (hoặc chỉ 'thành ngữ hơn') để sử dụng Luồng Java trong trường hợp này không?

import java.time.LocalDateTime; 
import java.time.format.DateTimeFormatter; 
import java.util.stream.IntStream; 
import java.util.stream.Stream; 

public class DateTimeFormattingStackOverflow { 
    static LocalDateTime dateTime = LocalDateTime.now(); 

    static Stream<String> substrings(String str) { 
     return IntStream.range(1, str.length() + 1) 
       .mapToObj(i -> str.substring(0, i)); 
    } 

    static void printDateTime(String pattern) { 
     DateTimeFormatter dtf = DateTimeFormatter.ofPattern(pattern); 
     System.out.println(pattern + ", " + dtf.format(dateTime)); 
    } 

    public static void main(String[] args) { 
     Stream<String> patterns = substrings("EEEE") 
       .flatMap(e -> substrings("MMMM").map(m -> e + " " + m)) 
       .map(em -> em + " d"); 

     patterns.forEach(DateTimeFormattingStackOverflow::printDateTime); 
    } 
} 

Output

E M d, Sat 7 1 
E MM d, Sat 07 1 
E MMM d, Sat Jul 1 
E MMMM d, Sat July 1 
EE M d, Sat 7 1 
EE MM d, Sat 07 1 
EE MMM d, Sat Jul 1 
EE MMMM d, Sat July 1 
... 
+0

Bạn có cần nó với luồng hoặc nó có thể là một cách * thành ngữ khác không? –

+0

Tôi đặc biệt quan tâm đến việc cố gắng thực hiện điều này trong 'cách phát trực tuyến', nhưng bạn chính xác rằng các phiên bản không phải dòng của mã này có thể là Java bình thường hơn, và tôi cảm ơn bạn đã đề xuất của bạn. –

Trả lời

0

tôi sẽ thay đổi cách thức mà bạn tạo ra lặp đi lặp lại chạy của một nhân vật: hơn là xây dựng chuỗi dài nhất bằng tay, và sau đó lặp lại các tiền tố của nó, tôi sẽ xây dựng chạy với Collection.nCopies , như sau:

static Stream<String> repeatedRuns(String c, int start, int end) { 
    return IntStream 
     .rangeClosed(start, end) 
     .mapToObj(len -> 
      Collections.nCopies(len, c).stream().collect(Collectors.joining("")) 
     ); 
} 

Sau đó, bạn sẽ thay thế substrings("EEEE") bằng repeatedRuns("E", 1, 4).

Demo.

0

Tôi không biết nếu đó là thành ngữ hơn, nhưng tôi sẽ bóp rằng đến một phương pháp duy nhất (nó có thể chỉ cho tôi ...)

public static Stream<String> combinations(String first, String second, String d, LocalDateTime dateTime) { 

     Stream<String> s = IntStream.range(0, first.length()) 
       .mapToObj(i -> first.substring(0, i + 1)) 
       .flatMap(x -> IntStream.range(0, second.length()) 
         .mapToObj(i -> second.substring(0, i + 1)) 
         .map(m -> String.join(" ", x, m)) 
         .map(res -> res + " d") 
         .peek(System.out::print) 
         .map(DateTimeFormatter::ofPattern) 
         .map(dtf -> dtf.format(dateTime))); 
     return s; 
    } 

    combinations("EEEE", "MMMM", " d", LocalDateTime.now()).forEach(x -> System.out.println(", " + x)); 
+0

Tôi không xem xét 'String.join (" ", x, m)' là tốt hơn so với chỉ 'x +" "+ m', nhưng bất kỳ kiểu nào bạn thích, nó không phù hợp để sử dụng quyền khác trong dòng tiếp theo với '.map (res -> res +" d ")'. Đặc biệt là bạn có thể làm điều đó trong một thao tác, 'String.join (" ", x, m," d ")' hoặc 'x +" "+ m +" d "' ... – Holger

+0

@ Holger bạn đúng ... cảm ơn bạn – Eugene

1

Bạn đang sử dụng IntStream đến lái xe chuỗi. Đó là một cách để làm điều đó, và đây là hai cách khác:

static Stream<String> substrings(String str) { 
    return str.length() == 1 ? Stream.of(str) : 
      Stream.concat(Stream.of(str), substrings(str.substring(1))); 
} 

này tạo ra một Stream đệ quy, trong khi con đường khác sẽ như sau:

static Stream<String> substrings2(String str) { 
    return Stream.iterate(str, s -> s.substring(1)).limit(str.length()); 
} 

này áp dụng các chức năng trao cho các kết quả trước đó. Vì nó tạo ra một dòng vô tận, bạn phải sử dụng limit.

Tôi đã chút thay đổi phương pháp main của bạn, để bạn tránh được một map hoạt động:

substrings("EEEE") 
    .flatMap(e -> substrings("MMMM").map(m -> e + " " + m + " d")) 
    .forEach(DateTimeFormattingStackOverflow::printDateTime); 

Tôi thực sự không biết nếu những cách trên đều ít nhiều thành ngữ hơn theo cách của bạn, nhưng nếu bạn hỏi tôi, cách thành ngữ nhất để làm nhiệm vụ này là với một vòng lặp lồng nhau:

String e = "EEEE"; 
String m = "MMMM"; 

for (int i = 0; i < e.length(); i++) 
    for (int j = 0; j < m.length(); j++) 
     printDateTime(e.substring(i) + " " + m.substring(j) + " d"); 

Và điều này có thể được dịch sang Java 8 như sau:

IntStream.range(0, e.length()).boxed() 
    .flatMap(i -> IntStream.range(0, m.length()) 
     .mapToObj(j -> e.substring(i) + " " + m.substring(j) + " d")) 
    .forEach(DateTimeFormattingStackOverflow::printDateTime); 
0

Tôi sẽ không truyền qua tất cả.Nó đủ để dòng qua một cái gì đó đại diện cho các kết hợp mười sáu và để xây dựng chuỗi định dạng trong một hoạt động:

Stream<String> patterns = IntStream.range(0, 16).map(i -> 15-i) 
    .mapToObj(i -> "EEEE".substring(i>>2)+" "+"MMMM".substring(i&3)+" d"); 

Thực tế rằng đây là những bốn lần bốn tổ hợp làm cho đủ điều kiện tính toán cho chút số học giá rẻ, nhưng về nguyên tắc, bất kỳ n × m kết hợp có thể bằng cách truyền 0-n × m và sử dụng i/ni%n để lựa chọn phần tử (như thực hiện các hoạt động substring). Bước .map(i -> 15-i) trước đó chỉ đảo ngược thứ tự để đối sánh nó với mã ban đầu của bạn; bạn có thể bỏ qua nó nếu thứ tự không quan trọng.

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