Create java collection with n clones of an object

后端 未结 4 1490
借酒劲吻你
借酒劲吻你 2020-12-11 05:30

In Java, is there a one-line way to create a collection that is initialized with n clones of an object?

I\'d like the equivalent of this:

相关标签:
4条回答
  • 2020-12-11 05:40

    If you're using Java 8 you could use its streams:

    Stream.generate(ArrayList<Integer>::new)
        .limit(10).collect(Collectors.toList());
    

    The Stream.generate() method takes a Supplier that knows how to produce a value and generates an infinite stream of those values (each value is obtained by calling the supplier again, so they are all different, unlike Collections.nCopies()). Placing a limit() on the stream and then collecting the results to a list thus yields a list of distinct entries.

    0 讨论(0)
  • 2020-12-11 05:48

    For those who want to pass in constructor arguments (which is not possible with the accepted answer and suppliers as mentioned here) - you can use the following (I do not know if there is a better solution but it at least fulfilled my needs):

    final List<MyObject> result = IntStream.range(0, n)
       .mapToObj(index -> new MyObject(...))
       .collect(Collectors.toList());
    

    whereas you would replace n by the number of elements you want to fill the list with and MyObject and new MyObject(...) with your type and ctor-call respectively.

    This creates a stream of integers ranging from 0 to n (n exclusive), maps every "index" to any object returned by the lambda-expr. in mapToObj and finally converts the stream to a list which will contain n distinct instances of MyObject.

    0 讨论(0)
  • 2020-12-11 05:49
    • vector<vector<int> > = new vector<vector<int> >(10); Is not syntactically correct but lets say you meant vector<vector<int> > foo(10);. You are using the fill constructor which will initialize the container size and then initialize each element to a copy of the value_type parameter (or the default constructor if you didn't specify anything). This will use a loop.

    • [ [] for i in range(10) ] and Array.new(10) { [] } are just doing the looping on 1 line and copying an empty list type structure in.

    As you indicated the nCopies method is not equivalent because the result is immutable and you are not creating copies (or clones). The reference to the same element is used when every index is accessed. See the openjdk copies implementation for reference.

    Some of the difficulties with java is there is no guarantee of a default constructor like in C++ and the syntax is a bit different than most scripting languages. This may be a good opportunity to take a second and understand what is going on under the covers to ensure your solution is not doing more work than necessary. Some follow up questions to ask yourself:

    • What other construct (besides a loop did you have in mind)? I believe there will be a loop at some level.
    • How do you really want to be initializing the ArrayList objects inside the outer ArrayList? For example what size do you want them to be? Should they be initially populated with anything? How big do you expect them to grow? Do they need to be uniform size or does it makes sense for some to be bigger/smaller? Does it make sense to lazily initialize these lists?

    To help answer these questions it may be good practice to write your own generic static initializer for your use case. After you get the simple case down if your use case varies it may make your solution more generic to use the Factory Pattern to initialize your inner lists. As you can see there is a good deal of issues to consider and in the simple case you may just end up with something like:

    public static <T> List<List<T>> newListofLists(int outerSize, int innerSize, T value) {
        List<List<T>> outer = new ArrayList<List<T>>(outerSize);
        for (int i = 0; i < outer.size(); ++i) {
            List<T> inner = new ArrayList<T>(innerSize);
            outer.add(inner);
            for (int j = 0; j < inner.size(); ++j) {
                inner.add(value);
            }
        }
        return outer;
    }
    

    This can then be used to initialize your lists in one line like:

    List<List<Integer>> myList = newListofLists(10, 5, -1);
    
    0 讨论(0)
  • 2020-12-11 05:52

    Even with the introduction of Java 8 Supplier, there is unfortunately not a succinct one-liner like nCopies. To be honest, I don't know why. (Though @DavidConrad has shown that Stream can do this.)

    You can easily create one yourself, for example:

    public static <E, L extends List<? super E>> L fill(
            L list, Supplier<E> sup, int n) {
        for(; n > 0; --n)
            list.add(sup.get());
        return list;
    }
    

    Call like:

    List<List<Integer>> list = ArrayUtils.fill(
        new ArrayList<>, ArrayList<Integer>::new, 10
    );
    

    For arrays, there is the new method Arrays#setAll:

    Integer[] oneToTen = new Integer[10];
    Arrays.setAll(oneToTen, i -> i + 1);
    List<Integer> asList = Arrays.asList(oneToTen);
    

    But it is a void method so it can't be used in a single statement. (Personal remark: why can't Java API be fluid?)

    Prior to Java 8 there is not a library method to do this and it is more cumbersome to create one. Since clone is protected, it cannot be invoked generically. Reflection can do it but reflection is pretty cumbersome.

    0 讨论(0)
提交回复
热议问题