用整型数组key过滤TreeMap并进行算术运算

Filter TreeMap with integer array key and perform arithmetic operations

我在 Java 中编写了一个复杂的程序,我需要在其中管理许多包含整数值的大型稀疏矩阵。 示例:

int A[][][][];
int B[][][];
int C[][];

为了节省内存,space等,我决定将这些数据存储在TreeMap中。我知道有很多图书馆做得更好,但我会尝试实施我的个人解决方案。 首先,我创建了一个 class 索引来标识这个数组的索引,但不知道它们有多少。

public class Index implements Comparable<Index> {
    private final int[] index;

    public Index(int ... index) {
        this.index = index;
    }

    @Override
    public int toCompare(Index i) {
        ...
    }
}

显然我已经使用这个 class 以这种方式定义我的三个地图:

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/

我的问题是:

  1. 如何从键中过滤我的值?
  2. 有没有办法(也许使用 lambda 表达式)来执行这种类型的操作?
  3. 关于这个问题有什么建议吗?

请注意,您不需要创建 Index class;您需要的类型 already exists.

来自 IntBuffer.compareTo 的文档:

Two int buffers are compared by comparing their sequences of remaining elements lexicographically, without regard to the starting position of each sequence within its corresponding buffer.

因此,如果您 wrap 包含索引的整数数组并将位置和限制保持在默认值,缓冲区将提供所需的行为。


以一般方式执行数组到映射的转换是可行的,如果您考虑在 Java 中,每个多维数组也是 Object[] 的实例,无论它们的基类型如何。即,类型 int[][]Object[] 的子类型,其元素是 int[] 的实例,而 int[]Object 的子类型。此外,Object[][]Object[] 的子类型,其元素属于 Object[] 类型,而 Object[]Object.

的子类型

因此您可以像 Object[] 一样处理所有维度来遍历它,只需要关心 最后一个 维度的实际类型,它总是int[] 对于任何 nint 数组:

/** 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]++;
        }
}

该解决方案以递归方式处理维度,尽管原则上可以使用非递归方式。但是,递归深度自然受限于array/matrix.

的维数

它只会将非零值放入映射中,并且还会跳过任何 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