配列をソートせずに、配列内の整数のグループをカウントするには?

ハーシュ・パテル:

私の目標は、アレイ内の同じ整数のグループをカウントすることができることです。例えば、これ等の配列で、{1, 1, 1, 2, 2, 3, 1, 1}存在する4基は

  • 少なくともサイズ1:3基
  • 1つの群:少なくとも2サイズの
  • 少なくともサイズの3

私は配列をソートせずにこれを達成する問題を抱えています。それがソートされますと、それは1つの他のグループの横に配置されますので、私は失う、配列の末尾に2の1のグループのカウント。

int result = (int) Stream.of(1, 1, 1, 2, 1, 1, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 5, 4, 4, 4, 6)
        .collect(Collectors.groupingBy(i -> i))
        .entrySet().stream()
        .filter(entry -> entry.getValue().size() >= 1) // specify the size
        .count()

return result;

次のように各サイズのため、この予想される出力は次のようになります。

size 1 count == 8

size 2 count == 5

size 6 count == 1

size 8 count == 1

次のように実際の出力は次のようになります。

size 1 count == 6

size 2 count == 3

size 6 count == 2

size 8 count == 1

違いは、前に行われて、カウントにソートされた配列の結果です。これを実現する方法はありますか?

編集: A群は、本質的に同じ整数の反復は、異なる値の整数まで、先にそれの任意の場所です。5(両端を含む)、インデックス6 - - 15(包括的、指数16 -ので、このコードでは、このサイズで2のグループは、(包括的)2に対するインデックス0、インデックス4にいずれかである18(包括的、及びインデックス20 -22 (包括的)。少なくとも2サイズ5のカウントが返されるべきである5つのグループが存在するので。

私の目標のためのコードの不可欠なスタイル。

Scanner key = new Scanner("1 1 1 2 1 1 3 3 3 3 3 3 3 3 3 3 4 4 4 5 4 4 4 6");

        int cnt = 0;
        int counter = 0;
        int i = 0;

            while(key.hasNextInt()) {   
                int next = key.nextInt();

                if(next == array[i]) {
                    counter++;
                }

                if(i + 1 < array.length && i -1 >= 0 
                   && counter >=size  
                   && next != array[i + 1] 
                   && next == array[i-size + 1]) {
                    cnt++;
                    counter = 0;
                }
                i++;
            }
        return cnt;

このため期待リターンは上記と同じです。

実際のリターンは次のとおりです。

size 1 count == 7

size 2 count == 5

size 6 count == 3

size 8 count == 1

このループの問題は、私はそれが最初の部分とのアレイのエンドピースを飛ばしていると信じています。

私は、同じソートの問題を持っていないよストリーム方法。

理想的には、これは任意の必要としない外部のユーティリティ/ライブラリを

サミュエル・フィリップ:

まず、私はすべてのサブグループを見つけるためにお勧めします。このためには使用することができStream.collect()、カスタムコレクターで:

List<List<Integer>> sublists = IntStream.of(1, 1, 1, 2, 1, 1, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 5, 4, 4, 4, 6)
        .collect(ArrayList::new, (lists, value) -> {
            if (lists.isEmpty() || lists.get(lists.size() - 1).stream().noneMatch(e -> e == value)) {
                lists.add(new ArrayList<>());
            }
            lists.get(lists.size() - 1).add(value);
        }, (l1, l2) -> {
            throw new RuntimeException("not supported for parallel streams");
        });

結果は次のとおりです。

[[1, 1, 1], [2], [1, 1], [3, 3, 3, 3, 3, 3, 3, 3, 3, 3], [4, 4, 4], [5], [4, 4, 4], [6]]

今、あなたは、リストのサイズグループにこれを使用することができます。

Map<Integer, Long> result = sublists.stream()
        .collect(Collectors.groupingBy(List::size, Collectors.counting()));
result.forEach((size, count) -> System.out.println(String.format("size %s count %s", size, count)));

これは、すべての既存のグループのサイズとプリントを検索します。

size 1 count 3
size 2 count 1
size 3 count 3
size 10 count 1

あなたが使用できる分の長さですべてのグループをカウントするには:

Map<Integer, Long> result = IntStream.rangeClosed(1, sublists.stream().mapToInt(List::size).max().orElse(0)).boxed()
        .collect(Collectors.toMap(Function.identity(), i -> sublists.stream().filter(l -> l.size() >= i).count()));
result.forEach((size, count) -> System.out.println(String.format("size %s count %s", size, count)));

この版画:

size 1 count 8
size 2 count 5
size 3 count 4
size 4 count 1
size 5 count 1
size 6 count 1
size 7 count 1
size 8 count 1
size 9 count 1
size 10 count 1

サイズの唯一の定義済みのセットを取得するには(例えば1, 2, 6, 8)あなたは最後の解決策を変更することができます。

Map<Integer, Long> result = IntStream.of(1, 2, 6, 8).boxed()
        .collect(Collectors.toMap(Function.identity(), i -> sublists.stream().filter(l -> l.size() >= i).count()));
result.forEach((size, count) -> System.out.println(String.format("size %s count %s", size, count)));

この結果は次のとおりです。

size 1 count 8
size 2 count 5
size 6 count 1
size 8 count 1

おすすめ

転載: http://43.154.161.224:23101/article/api/json?id=180151&siteId=1