我用Java编写了一个复杂的程序,我需要管理许多包含整数值的大型稀疏矩阵。 例如:
int A[][][][];
int B[][][];
int C[][];
为了节省内存,空间等,我决定将这些数据存储在TreeMap中。我知道有很多库可以做得更好,但我会尝试实现我的个人解决方案。 首先,我创建了一个类Index,用于标识此数组的indeces而不知道它们有多少。
public class Index implements Comparable<Index> {
private final int[] index;
public Index(int ... index) {
this.index = index;
}
@Override
public int toCompare(Index i) {
...
}
}
显然我已经用这个类以这种方式定义了我的三个地图:
Map <Index, Integer> mapA = new TreeMap <> ();
Map <Index, Integer> mapB = new TreeMap <> ();
Map <Index, Integer> mapC = new ...
现在,我需要将之前创建的矩阵中的数据存储到这些地图中。最简单的方法是使用4/3/2 / ..循环,但我很高兴地接受其他解决方案。
for(int s = 0; s < s_max; s++) {
for(int c = 0; c < c_max; c++) {
for(int o = 0; o < o_max; o++) {
for(int d = 0; d < d_max; d++) {
mapA.put(new Index(s,c,o,d), A[s][c][o][d]);
}
}
}
}
问题的焦点是当我需要检索数据时,让我解释一下。这些映射之间通常的操作是乘法和加法,将它们视为矩阵或数组。我不能每次执行6(..)嵌套循环,我需要执行以下操作(我无法插入图像,因为我的声誉仍然很低):
http://postimg.org/image/7m8v0kiwn/
我的问题是:
答案 0 :(得分:0)
请注意,您无需创建Index
类;您需要的类型already exists。
来自IntBuffer.compareTo
的文档:
通过按字典顺序比较剩余元素的序列来比较两个int缓冲区,而不考虑每个序列在其相应缓冲区内的起始位置。
因此,如果你wrap整数数组保存索引并将位置和限制保持为默认值,那么缓冲区将提供所需的行为。
以一般方式执行数组映射转换是有效的,如果您在Java中考虑,每个多维数组也是Object[]
的实例,而不管它们的基类型。即,类型int[][]
是Object[]
的子类型,其元素是int[]
的实例,它是Object
的子类型。此外,Object[][]
是Object[]
的子类型,其元素属于Object[]
类型,是Object
的子类型。
因此,您可以使用与Object[]
相同的方式处理所有维度以遍历它,只需关注 last 维度的实际类型,该维度始终为int[]
对于任何 n - 维int
数组:
/** accepts all int arrays from one to 255 dimensions */
public static TreeMap<IntBuffer,Integer> toMap(Object array) {
int dim=1;
for(Class<?> cl=array.getClass(); ; cl=cl.getComponentType())
if(Object[].class.isAssignableFrom(cl)) dim++;
else if(cl==int[].class) break;
else throw new IllegalArgumentException(array.getClass().getSimpleName());
TreeMap<IntBuffer,Integer> map=new TreeMap<>();
fill(map, new int[dim], 0, array);
return map;
}
private static void fill(TreeMap<IntBuffer, Integer> map, int[] i, int ix, Object array) {
int next=ix+1;
i[ix]=0;
if(next<i.length)
for(Object part: (Object[])array) {
if(part!=null) fill(map, i, next, part);
i[ix]++;
}
else
for(int val: (int[])array) {
if(val!=0) map.put(IntBuffer.wrap(i.clone()), val);
i[ix]++;
}
}
此解决方案递归处理维度,尽管原则上可以使用非递归维度。但是,递归深度自然限于阵列/矩阵的维数。
它只会将非零值放入地图中,并且还会跳过任何null
子数组,因此它不介意数组表示是否已经稀疏。
示例用法可能类似于
int[][][][] array=new int[5][5][5][5];
array[1][2][3][4]=42;
array[4][3][2][1]=1234;
TreeMap<IntBuffer, Integer> sparse=toMap(array);
sparse.forEach((index,value)-> {
for(int ix:index.array()) System.out.print("["+ix+']');
System.out.println("="+value);
});
将打印:
[1][2][3][4]=42
[4][3][2][1]=1234
另一个例子:
int[][] id = {
{1},
{0, 1},
{0, 0, 1},
{0, 0, 0, 1},
{0, 0, 0, 0, 1},
{0, 0, 0, 0, 0, 1},
{0, 0, 0, 0, 0, 0, 1},
};
TreeMap<IntBuffer, Integer> idAsMap = toMap(id);
System.out.println(idAsMap.size()+" non-zero values");
idAsMap.forEach((index,value)-> {
for(int ix:index.array()) System.out.print("["+ix+']');
System.out.println("="+value);
});
将打印:
7 non-zero values
[0][0]=1
[1][1]=1
[2][2]=1
[3][3]=1
[4][4]=1
[5][5]=1
[6][6]=1