2016-01-23 51 views
1

我想使用Java 8流和lambda表達式從我的List<String> list中只提取數字。首先我需要做的是從文件加載列表中加載字符串。之後,我過濾流獲得包含「PL」的字符串。使用流和lambda表達式從文件中提取數字

我的文件:

Jan Kowalski PL 35000 
Jiri Prohazka CZ 28000 
Anna Malinowska PL 52000 
Jozef Bak PL 49999 
Helmut Schnittke DE 45000 
Kleofas Oginski PL 45000 
John Bull US 74000 
Lukasz Zolw PL 9400 
Franz Beckenbauer DE 83000 
Frantisek Kupka CZ 32000 

代碼:

List<String> list = new ArrayList<>(); 
try (Stream<String> stream = Files.lines(Paths.get("file"),Charset.defaultCharset())) { 
    list = stream 
     .filter(line -> line.contains("PL")) 
     .peek(System.out::println) 
     .collect(Collectors.toList()); 
} 

我認爲最好的辦法,現在是去除從字符串中的所有字母,只留下小數,但我有問題,我應該怎麼辦它。 最終的結果應該讓我把列表的元素解析爲整數,對它們進行排序,並得到前三個元素的總和。 我已經做到了,但我敢肯定有更好的方式來做到這一點(例如只使用一個列表)

List<Integer> iList = new ArrayList<Integer>(); 
     list.forEach(s-> 
     { 
      s = s.replaceAll("\\D+",""); 
      iList.add(Integer.parseInt(s)); 
     }); 
     Collections.sort(iList); 
     Collections.reverse(iList); 
     int sum = 0; 
     for(int i=0;i<3;i++){ 
      sum=sum+iList.get(i); 
     } 

任何想法如何做到這一點,而無需使用任何額外的名單?

回答

3

您可以在單個Stream流水線中執行此操作。要提取號碼,您可以使用Pattern併爲該號碼創建一個capturing group。在這種情況下,該模式將是"(\\d+)"

這是通過創建與Pattern.matcher(input)的幫助下Matcher,與Matcher.find()再次過濾,實際上包含了一些線條,並與Matcher.group(group)提取獲取的號碼來完成。在此情況下,數目是第一捕獲元件,因此它在組1

此流被轉換成與Stream<Integer>Stream.map(mapper):這裏的映射器是返回從每一行解析的Integer值的功能。最後,爲了將三個最大元素求和,按照與前三個元素(limit(3))相反的順序(sorted(comparator),其中比較器爲reverseOrder())對流進行排序,並且將這些元素相加(sum(),首先將Stream<Integer>轉換成, )。

public static void main(String[] args) throws IOException { 
    Pattern pattern = Pattern.compile("(\\d+)"); 
    try (Stream<String> stream = Files.lines(Paths.get("file"))) { 
     int sum = 
      stream.filter(line -> line.contains("PL")) 
        .map(pattern::matcher) 
        .filter(Matcher::find) 
        .map(m -> Integer.valueOf(m.group(1))) 
        .sorted(Comparator.reverseOrder()) 
        .limit(3) 
        .mapToInt(Integer::intValue) 
        .sum(); 
     System.out.println(sum); 
    } 
} 

對於你的問題的例子中,輸出是146999.


如果您確信該文件中,則"PL"標識將前面的數字提取,你甚至可以刪除第一次過濾操作並使用模式".*PL.*?(\\d+)":該模式將匹配包含"PL"的行並捕獲相應的編號。

+0

謝謝!這正是我想要做的。 –

+2

尋找文件樣本,似乎''。* PL \\ s +(\\ d +)「'正則表達式會更加健壯。在這種情況下,用'Matcher :: matches'替換'Matcher :: find'也是很好的選擇。 –

+1

這種方法是有狀態的。首先創建一個匹配器,然後調用它的'find'和'group'方法。幸運的是,在Java 9中,會有一個'results'方法,所以'.filter(Matcher :: find)'可以用'.flatMap(Matcher :: results)'替換。甚至可以在一行中找到更多結果時使用。請參閱http://download.java.net/jdk9/docs/api/java/util/regex/Matcher.html#results-- – user140547

相關問題