使用整数数组键过滤TreeMap并执行算术运算

时间:2015-04-19 13:33:40

标签: java dictionary lambda java-8 sparse-matrix

我用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/

我的问题是:

  1. 如何从键中过滤我的值?
  2. 有一种方法(可能使用lambda表达式)来执行这种类型的操作吗?
  3. 有关此问题的任何建议吗?

1 个答案:

答案 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