2
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

HashSet<>を配列にするのは、どのやり方が速い?

Posted at

HashSetを配列にする方法はいろいろあるかと思います。

toArrayを使う場合はこんな感じでしょうか。

toArray
hashSet -> hashSet.toArray(new Integer[hashSet.size()])

for文で実直に回す場合は、ちょっと長いですね。

enhancedFor
hashSet -> {
    final Integer[] result = new Integer[hashSet.size()];
    int i = 0;

    for (Integer v : hashSet) {
        result[i++] = v;
    }
}

streamはこんなんでしょうか。

stream
hashSet -> hashSet.stream().toArray(size -> new Integer[size])

ここでは上記3つの方法を比較してみました。

ソース全体

要素10000個のHashSetを100万回配列にして、その平均時間を出力します。

com.example.HashSet2Array.java
package com.example;

import java.util.HashSet;
import java.util.function.Consumer;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import java.util.stream.Stream;

/**
 *
 * @author sengoku
 */
public class HashSet2Array {

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        final int examCount = 1000000;
        final int hasSize = 10000;

        final Consumer<HashSet<Integer>> toArray
                = hashSet -> hashSet.toArray(new Integer[hashSet.size()]);
        
        final Consumer<HashSet<Integer>> enhancedFor = hashSet -> {
            final Integer[] result = new Integer[hashSet.size()];
            int i = 0;

            for (Integer v : hashSet) {
                result[i++] = v;
            }
        };

        final Consumer<HashSet<Integer>> stream
                = hashSet -> hashSet.stream().toArray(size -> new Integer[size]);

        new HashSet2Array("toArray", examCount, hasSize, toArray);
        new HashSet2Array("enhanced for", examCount, hasSize, enhancedFor);
        new HashSet2Array("stream", examCount, hasSize, stream);
    }

    public HashSet2Array(
            final String message,
            final int examCount,
            final int hashSize,
            final Consumer<HashSet<Integer>> consumer) {

        final HashSet<Integer> hashSet = createHashSet(hashSize);

        final Double result = Stream
                .iterate(1, x -> x + 1)
                .limit(hashSize)
                .collect(Collectors.averagingLong(x -> execAndMeasure(consumer, hashSet)));

        System.out.println(message + " result: " + result);
    }

    private HashSet<Integer> createHashSet(final int size) {
        final HashSet<Integer> hashSet = new HashSet<>();

        IntStream.range(1, size).forEach(i -> hashSet.add(i));

        return hashSet;
    }

    private long execAndMeasure(final Consumer<HashSet<Integer>> consumer, final HashSet<Integer> hashSet) {
        final long start = System.nanoTime();

        consumer.accept(hashSet);

        return System.nanoTime() - start;
    }
}

実行環境

Java(TM) SE Runtime Environment (build 1.8.0_66-b17)
Java HotSpot(TM) 64-Bit Server VM (build 25.66-b17, mixed mode)

実行結果

結果の数値は実行時間です。数値が小さいほど速いです。

toArray result: 168829.2181
enhanced for result: 114511.2577
stream result: 159047.3653

意外にtoArrayが遅いのは、結構複雑なことしてるせいですね。

https://github.com/openjdk-mirror/jdk7u-jdk/blob/master/src/share/classes/java/util/AbstractCollection.java#L173

単純にfor文回すのが一番速くなるのも納得です。

考察

よっぽどシビアなパフォーマンス要件でない限り、一番読みやすいやり方を選んだほうがよさげです。

2
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?