前提・実現したいこと
JavaでFiles.readAlllines
で読み込んだ設定ファイルをstreamApiでリストに出来ないかと悩んでいます。
読みこむファイルは以下のようなファイルです。
# コメント行 <No1, hoge,hoge, fuga,fuga, >,, <No2, piyo,piyo, foo,foo, >,, <No3, hello,hello, >,,
実現したいリストは、以下のようなリストのリストにしたいと思っています。
java
1[["No1","hoge","fuga"], ["No2", "piyo", "foo"], ["No3", "hello", ""]]
現在このような、処理に続けて、streamApiの中で実現できればいいなと考えています。
java
1Files.readAlllines(path, StandardCharsets.UTF_8 2.stream() 3.filter( //必要ないコメント行などを消す )
できなければ、一度、全行、配列にして、ループで<
から始まる行から>
で始まる行までを配列に詰め直す処理を考えていますが、
もっといい方法が無いか考えております。
気になる質問をクリップする
クリップした質問は、後からいつでもMYページで確認できます。
またクリップした質問に回答があった際、通知やメールを受け取ることができます。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
回答2件
0
java.util.LinkedHashSet
要素が挿入された順序を保持し重複を許さないコレクションはLinkedHashSet
です。これを利用するのは<
から>
まで(1行分)です。複数行はDeque<Set<String>>に格納します。
Java
1static Deque<Set<String>> readLines(String fileName) { 2 Deque<Set<String>> result = null; 3 try (BufferedReader fr = new BufferedReader(new FileReader(fileName))) { 4 result = 5 fr.lines() 6 .filter(s -> !s.matches("^#.*")) // コメント除去 7 .flatMap(s -> Stream.of(s.split(",+"))) 8 .filter(s -> !s.isEmpty()) 9 .collect( 10 ArrayDeque<Set<String>>::new, 11 (acc, s) -> { 12 if (s.matches("^<.*$")) { // 行の開始 13 Set<String> hs = new LinkedHashSet<>(); 14 hs.add(s.substring(1)); 15 acc.addLast(hs); 16 } else if (!s.matches(".*>$")) { 17 (acc.getLast()).add(s); // 要素の追加、重複除去 18 } 19 }, 20 Deque::addAll); 21 } catch (IOException e) { 22 e.printStackTrace(); 23 } 24 return result; 25}
Streamを使ってみたけれど、whileでループさせてもほぼ同じコードになります。
Stream.itearate()/limit()
リストの要素数を揃えるには末尾に""
を追加しなければなりません。そのためにiterate()を使います。ただし、最長のListに長さを揃えるのか、定数を与えて揃えるのかでやり方が異なります。以下は要素数を定数3に固定したコード例です。
Java
1static Function<Integer, Stream<String>> fillSpace = h -> Stream.iterate("", s -> s).limit(3 - h); 2 3public static void main(String[] args) { 4 Deque<Set<String>> list = readLines(FILE_NAME); 5 list.stream().map( 6 row -> Stream.concat(row.stream(),fillSpace.apply(row.size())).collect(Collectors.toList()) 7 ).forEach(System.out::println); 8}
fillSpaceという関数が""
を必要なだけ追加します。全体に冗長です。もっと簡潔に書けると思います。Streamを使う練習だと思ってチャレンジしてみてください。
完全版(追記)
コメント行除去を追加しました。結果をList<List<String>>に変更。
Java
1import java.io.BufferedReader; 2import java.io.FileReader; 3import java.io.IOException; 4import java.util.ArrayDeque; 5import java.util.Deque; 6import java.util.LinkedHashSet; 7import java.util.List; 8import java.util.Set; 9import java.util.stream.Collectors; 10import java.util.stream.Stream; 11 12public class SettingsToList { 13 14 static String FILE_NAME = "... /settings.txt"; 15 static final int ARRAY_SIZE = 3; 16 17 public static void main(String[] args) { 18 Deque<Set<String>> list = readLines(FILE_NAME); 19 //list.forEach(System.out::println); 20 List<List<String>> result = 21 list.stream() 22 .map( r -> Stream.concat( 23 r.stream(), 24 Stream.iterate("", s -> s).limit(ARRAY_SIZE - r.size()) 25 ).collect(Collectors.toList())) 26 .collect(Collectors.toList()); 27 System.out.println(result); 28 } 29 30 static Deque<Set<String>> readLines(String fileName) { 31 Deque<Set<String>> result = null; 32 try (BufferedReader fr = new BufferedReader(new FileReader(fileName))) { 33 result = 34 fr.lines() 35 .filter(s -> !s.matches("^#.*")) // コメント除去 36 .flatMap(s -> Stream.of(s.split(",+"))) 37 .filter(s -> !s.isEmpty()) 38 .collect( 39 ArrayDeque<Set<String>>::new, 40 (acc, s) -> { 41 if (s.matches("^<.*$")) { // 行の開始 42 Set<String> hs = new LinkedHashSet<>(); 43 hs.add(s.substring(1)); 44 acc.addLast(hs); 45 } else if (!s.matches(".*>$")) { 46 (acc.getLast()).add(s); // 要素の追加、重複除去 47 } 48 }, 49 Deque::addAll); 50 } catch (IOException e) { 51 e.printStackTrace(); 52 } 53 return result; 54 } 55}
Streamを使う意義はご自分で考えてください。
投稿2020/04/24 10:45
編集2020/04/26 16:06総合スコア1090
あなたの回答
tips
太字
斜体
打ち消し線
見出し
引用テキストの挿入
コードの挿入
リンクの挿入
リストの挿入
番号リストの挿入
表の挿入
水平線の挿入
プレビュー
質問の解決につながる回答をしましょう。 サンプルコードなど、より具体的な説明があると質問者の理解の助けになります。 また、読む側のことを考えた、分かりやすい文章を心がけましょう。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。