質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.35%
Java

Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

Q&A

2回答

867閲覧

JavaでFiles.readAlllinesで読み込んだ設定ファイルをstreamApiでリストに出来ないかと悩んでいます。

yuji_teshi

総合スコア12

Java

Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

0グッド

0クリップ

投稿2020/04/24 02:29

前提・実現したいこと

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ページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答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
xebme

総合スコア1090

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

根本的な話として、Files.linesで一発でStreamとして引っ張れます。しかし、お望みの処理はStreamでやるには不向きです。順番に依存する処理のため、Streamのほとんどの中間処理に求められる要件を満たしませんし、どうしても副作用を必要とする処理を噛ませないと難しそうです。

「全行配列にして〜」ということですが、そもそもreadAllLinesの結果がListで返ってくるので、配列化の必要はないはずです。

投稿2020/04/24 02:42

swordone

総合スコア20669

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.35%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問