3

私は言葉のリストを持っています。

List<String> words = Arrays.asList("Hello alan i am here where are you"+  
  "and what are you doing hello are you there");

リストで複数回繰り返される上位 7 つの単語を降順で取得するにはどうすればよいですか? そして、単一のエントリの単語をアルファベット順に並べる必要があります。したがって、上記の出力は上位 7 語になります。

you (3)
are (2)
hello (2)
alan (1)
am (1)
and (1)
doing (1)

ストリーム、ラムダを使用してJava 8でこれを行うことを検討しています。

私はこのように努力しています。最初にリストを並べ替えます。次に、単語のリスト内の単語数を使用して単語のマップを取得します。

List<String> sortedWords = Arrays.asList("Hello alan i am here where are you and what are you doing hello you there".split(" "))
            .stream().sorted().collect(toList());

Map<String, Long> collect = 
            sortedWords.stream().collect(groupingBy(Function.identity(), counting()));
4

5 に答える 5

9

一番難しいのは仕分けです。結果から最初の 7 つの要素のみを保持し、マップをその値で並べ替えたいため、すべての結果のマップを作成し、並べ替えてから 7 つの結果を保持する必要があります。

次のコードでは、すべての単語が小文字化され、単語ごとにグループ化され、出現回数がカウントされます。次に、このマップを並べ替えて、エントリに対して Stream を作成し、値に従って (降順で) 並べ替え、次にキーに従って並べ替える必要があります。最初の 7 つの要素は保持され、それらのキー (単語に対応する) にマップされて にまとめられ、List出現順序が維持されます。

public static void main(String[] args) {
    String sentence = "Hello alan i am here where are you and what are you doing hello are you there";
    List<String> words = Arrays.asList(sentence.split(" "));

    List<String> result = 
            words.stream()
                 .map(String::toLowerCase)
                 .collect(groupingBy(identity(), counting()))
                 .entrySet().stream()
                 .sorted(Map.Entry.<String, Long> comparingByValue(reverseOrder()).thenComparing(Map.Entry.comparingByKey()))
                 .limit(7)
                 .map(Map.Entry::getKey)
                 .collect(toList());

    System.out.println(result);
}

出力:

[are, you, hello, alan, am, and, doing]

必要な出力を間違えたことに注意してください。"are"実際には3回表示"you"されるので、前にあるはずです

注意: このコードは、多くの静的インポートを想定しています。つまり、次のとおりです。

import static java.util.Comparator.reverseOrder;
import static java.util.function.Function.identity;
import static java.util.stream.Collectors.counting;
import static java.util.stream.Collectors.groupingBy;
import static java.util.stream.Collectors.toList;
于 2015-11-22T14:05:09.167 に答える
4

@Tunaki ソリューションは素晴らしいですが、興味深いのは、私の StreamEx ライブラリを使用して、単一のストリーム パイプラインで問題を解決できることです (単一のターミナル操作が呼び出されるまで、実際の操作は実行されません)。

Map<String, Long> map = StreamEx.of(words)
    .map(String::toLowerCase)
    .sorted() // sort original words, so now repeating words are next to each other
    .runLengths() // StreamEx feature: squash repeating words into Entry<String, Long>
    .sorted(Entry.<String, Long> comparingByValue().reversed()
                 .thenComparing(Entry.comparingByKey()))
    .limit(7) // Sort and limit
    .toCustomMap(LinkedHashMap::new); // Single terminal operation: store to LinkedHashMap

または、単語のみが必要な場合:

List<String> list =StreamEx.of(words)
    .map(String::toLowerCase)
    .sorted() // sort original words, so now repeating words are next to each other
    .runLengths() // StreamEx feature: squash repeating words into Entry<String, Long>
    .sorted(Entry.<String, Long> comparingByValue().reversed()
                 .thenComparing(Entry.comparingByKey()))
    .limit(7) // Sort and limit
    .keys() // Drop counts leaving only words
    .toList(); // Single terminal operation: store to List
于 2015-11-22T14:33:21.593 に答える
1

私は単純な人なので、Map<String, Integer>最初に各単語を数えるために a を使用します。次にTreeSet、カウントごとに を作成し、それらを に保存しTreeMap<Integer, TreeSet>ます。そこからはかなり簡単なはずです。

于 2015-11-22T13:55:55.120 に答える
0

2 段階の解決策: group/count、次にcount の降順で処理する

List<String> words = Arrays.asList("Hello alan i am here where are you and what are you doing hello you there".split(" "));

Map<String, Long> collect = words.stream()
        .map(String::toLowerCase) // convert to lower case
        .collect( // group and count by name
                Collectors.groupingBy(Function.identity(), Collectors.counting()));

collect.keySet().stream()
        .sorted( // order by count descending, then by name
                Comparator
                        .comparing(collect::get)
                        .reversed()
                        .thenComparing(Collator.getInstance()))
        .map(k -> k + " (" + collect.get(k) + ")") // map to name and count string
        .limit(7) // only first 7 entries
        .forEach(System.out::println); // output
于 2016-10-06T11:56:19.457 に答える