使用Collectors.toMap()映射原数组与旋转副本时未达预期结果的问题求助
问题分析与解决方案
嘿,我立刻就发现你问题的症结所在了!
你得到元素自映射的根本原因,是**Arrays.asList()返回的列表并没有创建新的元素集合,它只是原数组的一个“视图”**——简单说,这个列表和你一开始的splitAlphabet数组共享同一个底层数组空间。
咱们一步步拆解你的代码流程,就能看明白哪里出问题了:
- 你把
ALPHABET拆分成splitAlphabet数组,此时它的内容是[A,B,C,...,Z] - 调用
Arrays.asList(splitAlphabet)得到shiftedAlphabetList,这个列表并没有复制原数组的元素,只是直接引用了splitAlphabet的底层数组 - 执行
Collections.rotate(shiftedAlphabetList, -4)时,实际上是直接修改了原splitAlphabet数组的元素顺序!此时splitAlphabet已经变成了旋转后的[E,F,G,...,Z,A,B,C,D] - 最后把
shiftedAlphabetList转成shiftedAlphabet数组,其实它和splitAlphabet指向的是同一个数组对象!
所以当你用Collectors.toMap的时候,splitAlphabet[index]和shiftedAlphabet[index]取的是同一个数组里同一个位置的元素,自然得到的是元素到自身的映射。
两种可行的解决方法
方法1:创建独立的列表副本
在调用Arrays.asList()之后,用new ArrayList()包装一下,这样就会复制原数组的元素,生成一个独立的新列表,旋转操作就不会影响原数组了:
static String ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; String[] splitAlphabet = ALPHABET.split("(?!^)"); // 用ArrayList创建独立副本,不再共享底层数组 List<String> shiftedAlphabetList = new ArrayList<>(Arrays.asList(splitAlphabet)); Collections.rotate(shiftedAlphabetList, -4); String[] shiftedAlphabet = shiftedAlphabetList.toArray(new String[0]); // 此时再执行toMap就能得到预期结果 Map<String, String> mapping = IntStream.range(0, splitAlphabet.length) .boxed() .collect(Collectors.toMap(index -> splitAlphabet[index], index -> shiftedAlphabet[index]));
方法2:直接复制原数组再旋转
另一种思路是先复制splitAlphabet数组,然后对副本进行旋转操作,避免修改原数组:
static String ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; String[] splitAlphabet = ALPHABET.split("(?!^)"); // 复制原数组得到独立的副本 String[] shiftedAlphabet = Arrays.copyOf(splitAlphabet, splitAlphabet.length); // 对副本的视图进行旋转,修改的是副本数组 Collections.rotate(Arrays.asList(shiftedAlphabet), -4); // 生成映射 Map<String, String> mapping = IntStream.range(0, splitAlphabet.length) .boxed() .collect(Collectors.toMap(index -> splitAlphabet[index], index -> shiftedAlphabet[index]));
用这两种方法处理后,splitAlphabet会保持初始的字母顺序,shiftedAlphabet是旋转后的独立数组,你的toMap代码就能生成预期的A→E、B→F这类映射了。
内容的提问来源于stack exchange,提问作者yahyaharif
相关产品推荐
相关产品推荐

