有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java如何有效地将两种不同类型的多维集合转换为多维列表

我有以下哈希集,需要将树集作为元素:

HashSet<TreeSet<Integer>> hash=new HashSet<TreeSet<Integer>>(); 

我希望能够将有序元素存储到树集合中,顺序也很重要,因此需要选择树集合。这些元素本身需要排序,但不一定要排序。但我必须返回:

List<List<Integer>>

在性能方面,将我的散列转换为整数列表的最有效方法是什么

多谢各位


共 (2) 个答案

  1. # 1 楼答案

    您仍然需要迭代集合,并将内部集合转换为列表。虽然如果性能是最重要的,考虑使用一些第三方库,它提供一些优化。

    1。基准

    我使用JMH编写了两个简单的基准测试,将它们与vanilla java解决方案进行比较:

    public class Set2ListTest {
    
        private static final int SMALL_SET_SIZE = 10;
        private static final int LARGE_SET_SIZE = 1000;
    
        public static void main(String[] args) throws RunnerException {
            Options options = new OptionsBuilder()
                    .include(Set2ListTest.class.getSimpleName())
                    .forks(1)
                    .threads(8)
                    .warmupIterations(1)
                    .measurementIterations(1)
                    .build();
            new Runner(options).run();
        }
    
        @State(Scope.Benchmark)
        public static class Provider {
    
            Set<Set<Integer>> smallSet = new HashSet<>(SMALL_SET_SIZE);
            Set<Set<Integer>> largeSet = new HashSet<>(LARGE_SET_SIZE);
    
            @Setup
            public void setup() {
                fillSet(smallSet, SMALL_SET_SIZE);
                fillSet(largeSet, LARGE_SET_SIZE);
            }
    
            private void fillSet(Set<Set<Integer>> set, int count) {
                Random random = new Random();
                for (int i = 0; i < count; i++) {
                    Set<Integer> innerSet = new TreeSet<>();
                    for (int j = 0; j < count; j++) {
                        innerSet.add(random.nextInt(Integer.MAX_VALUE));
                    }
                    set.add(innerSet);
                }
            }
    
        }
    
        @Benchmark
        public void small_plainJava(Provider provider, Blackhole blackhole) {
            List<List<Integer>> list = new ArrayList<>(SMALL_SET_SIZE);
            for (Set<Integer> set : provider.smallSet) {
                list.add(new ArrayList<>(set));
            }
            blackhole.consume(list);
        }
    
        @Benchmark
        public void large_plainJava(Provider provider, Blackhole blackhole) {
            List<List<Integer>> list = new ArrayList<>(LARGE_SET_SIZE);
            for (Set<Integer> set : provider.largeSet) {
                list.add(new ArrayList<>(set));
            }
            blackhole.consume(list);
        }
    
        @Benchmark
        public void small_guava(Provider provider, Blackhole blackhole) {
            List<List<Integer>> list = new ArrayList<>(SMALL_SET_SIZE);
            for (Set<Integer> set : provider.smallSet) {
                list.add(com.google.common.collect.Lists.newArrayList(set));
            }
            blackhole.consume(list);
        }
    
        @Benchmark
        public void large_guava(Provider provider, Blackhole blackhole) {
            List<List<Integer>> list = new ArrayList<>(LARGE_SET_SIZE);
            for (Set<Integer> set : provider.largeSet) {
                list.add(com.google.common.collect.Lists.newArrayList(set));
            }
            blackhole.consume(list);
        }
    
        @Benchmark
        public void small_commons(Provider provider, Blackhole blackhole) {
            List<List<Integer>> list = new ArrayList<>(SMALL_SET_SIZE);
            for (Set<Integer> set : provider.smallSet) {
                List<Integer> innerList = new ArrayList<>(SMALL_SET_SIZE);
                CollectionUtils.addAll(innerList, set);
                list.add(innerList);
            }
            blackhole.consume(list);
        }
    
        @Benchmark
        public void large_commons(Provider provider, Blackhole blackhole) {
            List<List<Integer>> list = new ArrayList<>(LARGE_SET_SIZE);
            for (Set<Integer> set : provider.largeSet) {
                List<Integer> innerList = new ArrayList<>(LARGE_SET_SIZE);
                CollectionUtils.addAll(innerList, set);
                list.add(innerList);
            }
            blackhole.consume(list);
        }
    
        @Benchmark
        public void small_eclipse(Provider provider, Blackhole blackhole) {
            List<List<Integer>> list = FastList.newList();
            for (Set<Integer> set : provider.smallSet) {
                list.add(FastList.newList(set));
            }
            blackhole.consume(list);
        }
    
        @Benchmark
        public void large_eclipse(Provider provider, Blackhole blackhole) {
            List<List<Integer>> list = FastList.newList();
            for (Set<Integer> set : provider.largeSet) {
                list.add(FastList.newList(set));
            }
            blackhole.consume(list);
        }
    
    }
    

    2。结果

    结果如下:

    Benchmark                      Mode  Cnt        Score   Error  Units
    Set2ListTest.large_commons    thrpt           183.205          ops/s
    Set2ListTest.large_eclipse    thrpt           219.068          ops/s
    Set2ListTest.large_guava      thrpt           178.478          ops/s
    Set2ListTest.large_plainJava  thrpt           148.058          ops/s
    Set2ListTest.small_commons    thrpt       2140560.198          ops/s
    Set2ListTest.small_eclipse    thrpt       2619862.935          ops/s
    Set2ListTest.small_guava      thrpt       2720692.868          ops/s
    Set2ListTest.small_plainJava  thrpt       2472748.566          ops/s
    

    3。讨论

    使用两种不同大小的Set来测量性能:10组大小为10的元素(100个元素)和1000组大小为1000的元素(1.000.000个元素)

    对于小型的Set,eclipse集合的性能优于其他工具。纯java似乎是最慢的解决方案

    对于较大的Set,番石榴的效果最好

    显然,馆藏的规模对性能有很大的影响,并且可以影响这些库中的最佳选择。我不知道你的数据有多大,但我的目标不是为你提供最好的藏书库,而是为你提供一个找到藏书的工具

    4。其他注意事项

    <>我不认为自己是任何一个集合框架的专家,可能有更好的方法来使用它们。

    如果这些结果不令人满意,可以使用原始集合,这样就可以分配更少的内存。这将带来巨大的性能提升

    请注意,如果您想使用提供的基准测试进行实验,重要的是,您要相互比较实现,而不是对比我得到的结果,因为这可能与硬件有关

  2. # 2 楼答案

    为了有效地进行测试,您必须使用JMH来测试它们。我可以给你转换的方法,但它们也应该执行:

    你有普通的java循环,例如:

    HashSet<TreeSet<Integer>> hash=new HashSet<TreeSet<Integer>>(); 
    List<List<Integer>> list = new ArrayList<>(hash.size());
    for (Set<Integer> a : hash) {
      list.add(new ArrayList<>(a));
    }
    

    这需要O(n²)

    你有一个使用Stream的,也就是O(n²)

    hash.stream()
        .map(ArrayList::new)
        .collect(toList());
    

    第二个版本的不同之处在于,您最终可能会使用^{}并行化^{}:这是您可能获得性能的地方(但仍然需要使用JMH进行测试)