我有一个String[]
,其值必须放入String[][]
,每个“行”由当前索引和前一个数组的值组成。迭代解决方案如下所示:
String[] vals = getValsFromSomewhere();
String[][] targetArray = new String[vals.length][];
for (int i = 0; i < targetArray.length; i++) {
targetArray[i] = new String[]{
Integer.toString(i), vals[i]
};
}
我目前尝试将其更改为流以避免临时变量并在我的方法中摆脱for循环,但到目前为止我提出的最佳解决方案是:
String[] vals = getValsFromSomewhere();
String[][] targetArray = IntStream.range(0, vals.length)
.mapToObj(index -> new String[]{
Integer.toString(index), vals[index]
})
.toArray(String[][]::new);
这是一个有流的解决方案,好吧。但是,我的原始目标的一部分,即摆脱临时变量(在这种情况下为vals
),是没有实现的。搜索Stream
中的可用方法并没有提出任何看起来有用的东西,但我可能错过了一些东西。这就是为什么我在这里问;-)指出我正确的方向是非常感谢。
答案 0 :(得分:0)
删除临时变量 vals 意味着您无法在创建Stream之前知道要处理的元素数量,因此无法使用 range() 。我无法看到如何消除所有临时变量,但作为替代方案,我引入了一个 AtomicInteger ,它在流处理中递增以支持索引。
我当然不会声称这是一种比你更好的方法,如果除了 range()之外还有其他任何方法可以使用流进行索引,我感兴趣 AtomicInteger (仅使用标准Java)。
以下是代码:
String[] getValsFromSomewhere() {
return new String[]{"The", "rain", "in", "Spain", "stays", "mainly", "in", "the", "plain!"};
}
void test() {
AtomicInteger ai = new AtomicInteger(0);
String[][] target = Stream.of(getValsFromSomewhere())
.map(e -> new String[]{e, String.valueOf(ai.getAndIncrement())})
.toArray(String[][]::new);
for(int row=0; row<target.length; row++) {
for(int element=0; element<target[row].length; element++) {
System.out.println("target[" + row +"] [" + element + "] = " + target[row][element]);
}
}
}
答案 1 :(得分:0)
为什么不写自己的Collector
(或者更好的说让我给你写一个)?似乎可能有点矫枉过正,但这可以使用:
class Array2DCollector implements Collector<String, Map<Integer,String>, String[][]>{
private final AtomicInteger index = new AtomicInteger(0);
@Override
public Supplier<Map<Integer, String>> supplier(){
return HashMap::new;
}
@Override
public BiConsumer<Map<Integer, String>, String> accumulator(){
return (map, string) -> map.put(index.getAndIncrement(), string);
}
@Override
public BinaryOperator<Map<Integer, String>> combiner(){
return (map1, map2) -> {
map1.putAll(map2);
return map1;
};
}
@Override
public Function<Map<Integer, String>, String[][]> finisher(){
return map -> {
final String[][] array = new String[index.get()][2];
for(int i = 0; i < map.size(); i++){
array[i][0] = String.valueOf(i);
array[i][1] = map.get(i);
}
return array;
};
}
@Override
public Set<Characteristics> characteristics(){
return EnumSet.noneOf(Characteristics.class);
}
}
然后可以很容易地使用如下
final String[][] target = Arrays.stream(vals).collect(new Array2DCollector());
说明:简而言之,收集器有一个内部变量index
,仅用于计数。对于流中的每个元素,此变量都会增加,并且元素将保存在hashMap中。最后,hashmap被转换为2D-Array。
重要提示:此收集器基于HashMap
,无法执行并发且已订购。
最后注意事项:如上所述,这有点矫枉过正,但为什么不尝试一下;)