在Java中,是否有一种单行方式来创建使用对象的 n 克隆初始化的集合?
我喜欢这相当于:
foo = vector<vector<int> >(10);
c ++,创建10个不同的空向量[ [] for i in range(10) ]
Python,一个由10个不同的空数组组成的数组Array.new(10) { [] }
Ruby,与Python相同在Java中,我只找到了
new ArrayList<ArrayList<Integer> >(Collections.nCopies(10, new ArrayList<Integer>()))
但是, 等同于其他示例,因为列表别名。
有没有办法在不使用for循环的情况下创建不同对象克隆的数组,最好不要诉诸external libraries?
答案 0 :(得分:7)
如果您使用的是Java 8,则可以使用其流:
Stream.generate(ArrayList<Integer>::new)
.limit(10).collect(Collectors.toList());
Stream.generate()
方法需要Supplier
知道如何生成值并生成这些值的无限流(每个值都是通过再次调用供应商获得的,因此它们都是不同的,不像Collections.nCopies()
)。在流上放置limit()
,然后将结果收集到列表中,从而生成不同条目的列表。
答案 1 :(得分:2)
对于那些想要传递构造函数参数的人(accepted answer和供应商提及here不可能) - 你可以使用以下内容(我这样做)不知道是否有更好的解决方案,但它至少满足了我的需求):
final List<MyObject> result = IntStream.range(0, n)
.mapToObj(index -> new MyObject(...))
.collect(Collectors.toList());
然而,您要将n
替换为要填充列表的元素数量,并将MyObject
和new MyObject(...)
分别替换为您的类型和ctor-call。
这将创建一个从0到n(n不包括)的整数流,映射每个&#34;索引&#34;到lambda-expr返回的任何对象。在mapToObj
中,最后将流转换为包含n
个MyObject
个img
实例的列表。
答案 2 :(得分:1)
即使引入了Java 8 Supplier
,遗憾的是还没有像nCopies
那样简洁的单行代码。说实话,我不知道为什么。 (虽然@DavidConrad表明Stream
可以做到这一点。)
您可以自己创建一个,例如:
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;
}
请致电:
List<List<Integer>> list = ArrayUtils.fill(
new ArrayList<>, ArrayList<Integer>::new, 10
);
对于数组,有新方法Arrays#setAll
:
Integer[] oneToTen = new Integer[10];
Arrays.setAll(oneToTen, i -> i + 1);
List<Integer> asList = Arrays.asList(oneToTen);
但它是void
方法,因此不能在单个语句中使用。 (个人评论:为什么Java API不能流畅?)
在Java 8之前,没有一种库方法可以做到这一点,创建一个更麻烦。由于clone
受到保护,因此无法一般性地调用它。反思可以做到,但反思非常麻烦。
答案 3 :(得分:0)
vector<vector<int> > = new vector<vector<int> >(10);
在语法上不正确,但可以说你的意思是vector<vector<int> > foo(10);
。您正在使用fill constructor 初始化容器大小,然后将每个元素初始化为value_type
参数的副本(如果未指定任何内容,则初始化为默认构造函数)。这将使用循环。
[ [] for i in range(10) ]
和Array.new(10) { [] }
只是在1行上进行循环并复制空列表类型结构。
如您所示,nCopies
方法不相同,因为结果是不可变的,您不会创建副本(或克隆)。访问每个索引时使用对同一元素的引用。请参阅openjdk copies implementation以供参考。
java的一些困难是无法保证像C ++中那样的默认构造函数,并且语法与大多数脚本语言略有不同。这可能是一个很好的机会,可以花一点时间了解正在进行的工作,以确保您的解决方案不会做更多的工作。一些跟进问题要问自己:
为了帮助回答这些问题,最好为您的用例编写自己的通用静态初始化程序。如果您的用例不同,在您获得简单案例后,可能会使您的解决方案更通用,以使用Factory Pattern来初始化您的内部列表。正如您所看到的,需要考虑很多问题,在简单的情况下,您最终可能会遇到类似的问题:
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;
}
然后可以使用它来在一行中初始化列表,如:
List<List<Integer>> myList = newListofLists(10, 5, -1);