2016-07-26 55 views
0

我正在寻找一种方式来读取未知维度(不是长度)的数组中的一系列元素。阅读数组中值的范围与未知尺寸

客户端可以发送对象的读取请求并指定要读取的范围。例如,输入字符串可以是这样的:“1:2:3:2,2:3:1:4”。这意味着他想要读取数组[1] [2] [3] [2]到[2] [3] [1] [4]中的元素。

读书,我创造了这个功能的混凝土构件:

public Object readValue(Object obj,int[] positions) { 
    Object value = null; //Result 
    int objDimension = getDimension(obj); //Dimesion of the array 
    System.out.println("Dimension: " + objDimension); 
    try { 
     Object[] aux = (Object[]) obj; 
     for (int i = 0; i < objDimension - 1; i++) { 
      int pos = positions[i]; 
      aux = (Object[]) aux[pos]; 
     } 
     value = aux[positions[objDimension - 1]]; 
     System.out.println("Result: " + value); 
    } catch (ArrayIndexOutOfBoundsException e) { 
     // TODO: Send a fault to the client. 
     System.out.println("Error: "+e.getMessage()); 
    } 
    return value; 
} 

public static int getDimension(Object value) { 
    Class<?> clazz = value.getClass(); 
    String className = clazz.getName(); 
    int dimension = 0; 
    for (int i = 0; i < className.length(); i++) { 
     if (className.charAt(i) != '[') { 
      dimension = i; 
      break; 
     } 
    } 
    return dimension; 
} 


//Example. 
public static void main(String[] args) { 
    // TODO code application logic here 
    TestMultiDimensioNRead test = new TestMultiDimensioNRead(); 
    Integer[][][][] testSubject = new Integer[5][2][4][]; 

    testSubject[0][0][2] = new Integer[8]; 
    testSubject[0][0][0] = new Integer[15]; 
    testSubject[0][0][1] = new Integer[20]; 
    testSubject[0][0][3] = new Integer[2]; 
    testSubject[1][1][2] = new Integer[7]; 
    testSubject[1][1][2][0] = 80; 
    test.readValue(testSubject,new int[]{1, 1, 2, 0}); 
} 

我在想一个好办法可以计算每个维度的长度之间的differens。

如果任何人都可以有一个好主意,我真的很感激。

在此先感谢。

编辑1:在这个问题中发布的代码的确读取了未知维数组中给定位置的值。我的问题是读取介于给定点之间的所有元素。这在最初的问题中可能不太清楚。

+1

这可能不是建议的方法,原因很多。我能问你想要完成什么吗?我可能会重新考虑你在解决问题的方式。 – Kurtymckurt

+0

对于服务器来说,其中一项服务是从任何维数的数组中读取一系列值。数组没有预定义,并且没有角度限制(我写了255,因为来自Java的维度上限)。这是在服务器启动时创建的,并来自配置文件。顺便说一下,欢迎任何替代方式或想法,谢谢。 – gabun88

+0

您可以将数据中的维数作为参数传入吗?如果调用代码知道它(至少对于这种用法),编写一个算法来解决这个问题毫无意义。 – Kurtymckurt

回答

0

找到了解决问题的方法,也许这对某人来说是有帮助的。 我没有包含任何检查,这是更多的测试用例,看看是否有用。

public class TestReadMultiDimensionArray { 

private int[] startPosition;    //Start position. 
private int[] endPosition;     //End position. 
private boolean inRange = false;   //If the current position is in range. 
private List<Object> result;    //List to store the values we find. 

public TestReadMultiDimensionArray() { 
    result = new ArrayList<>(); 
} 

public static void main(String[] args) { 
    TestReadMultiDimensionArray test = new TestReadMultiDimensionArray(); 
    Integer[][][][] testSubject = new Integer[2][2][4][]; 
    //(0,0,y,z) 
    testSubject[0][0][0] = new Integer[]{1};         //(0,0,0,0) 
    testSubject[0][0][1] = new Integer[]{2};         //(0,0,1,0) 
    testSubject[0][0][2] = new Integer[]{3};         //(0,0,2,0) 
    testSubject[0][0][3] = new Integer[]{4};         //(0,0,3,0) 
    //(0,1,y,z) 
    testSubject[0][1][0] = new Integer[]{5};         //(0,1,0,0) 
    testSubject[0][1][1] = new Integer[]{6};         //(0,1,1,0) 
    testSubject[0][1][2] = new Integer[]{7, 8, 9};        //(0,1,2,0) (0,1,2,1) (0,1,2,2) 
    testSubject[0][1][3] = new Integer[]{10};         //(0,1,3,0) 
    //(1,0,y,z) 
    testSubject[1][0][0] = new Integer[]{11, 12};        //(1,0,0,0).. 
    testSubject[1][0][1] = new Integer[]{13, 14, 15}; 
    testSubject[1][0][2] = new Integer[]{16, 17, 18}; 
    testSubject[1][0][3] = new Integer[]{19, 20, 21};       //..(1,0,3,2) 
    //(1,1,y,z) 
    testSubject[1][1][0] = new Integer[]{22, 23};        //(1,1,0,0).. 
    testSubject[1][1][1] = new Integer[]{24, 25, 26}; 
    testSubject[1][1][2] = new Integer[]{27, 28, 29, 30, 31, 32, 33, 34}; 
    testSubject[1][1][3] = new Integer[]{35, 36};        //..(1,1,3,1) 
    //Launch the test. 
    test.readValue(testSubject); 
} 

/** 
* 
* @param obj The Array from where we want to get the data. 
*/ 
public void readValue(Object obj) { 
    //Where should it start. 
    startPosition = new int[]{0, 1, 0, 0}; 
    //Where should it stop. 
    endPosition = new int[]{1, 1, 1, 2}; 
    System.out.println("Start Position:" + Arrays.toString(startPosition) + " End Position:" + Arrays.toString(endPosition)); 
    int[] currentPosition = new int[]{-1, -1, -1, -1}; 

    //Call to the method. 
    testRead((Object[]) obj, 0, currentPosition); 
    //Result to array. 
    Object[] arrayToReturn = result.toArray(new Object[0]); 
    System.out.println("Result: " + Arrays.toString(arrayToReturn)); 
} 

/** 
* Recursive method that looks for the values in a multi-dimensional array, in a given range. /!\ No checks are implemented here, wrong input can end in a 
* StackOverFlow. 
* 
* @param obj The array in Object[] form. 
* @param currentDimension The dimension we are currently in. 
* @param result The reference to the list that will store all the values we found. 
* @param currentPosition The current position we are in. 
*/ 
private void testRead(Object[] obj, int currentDimension, int[] currentPosition) { 
    for (int i = 0; i < obj.length; i++) { 
     currentPosition[currentDimension] = i; 
     if (Arrays.equals(startPosition, currentPosition) && currentDimension == (currentPosition.length - 1)) { 
      //Found the start position. 
      System.out.println("############ START ############"); 
      inRange = true; 
     } 

     if ((i >= startPosition[currentDimension] && i <= endPosition[currentDimension]) || inRange == true) { 
      //We are in the write track to get to the values we are looking for. 
      if (obj[i] instanceof Object[]) { 
       //The data contained in the cell is an array. 
       testRead((Object[]) obj[i], currentDimension + 1, currentPosition); 
      } else { 
       //The data contained in the cell is a scalar. This is what we where looking for. 
       System.out.println(Arrays.toString(currentPosition) + " Data: " + obj[i]); 
       result.add(obj[i]); 
      } 
     } 

     if (Arrays.equals(endPosition, currentPosition) && currentDimension == (currentPosition.length - 1)) { 
      //Found the end position. 
      System.out.println("############ END ############"); 
      inRange = false; 
     } 
    } 
} 

} 

任何问题或想法,以更好的代码是值得欢迎的。

1

你可以使用一个递归解决方案:

public class Test { 
    private class TestMultiDimensioNRead { 
     public Integer readValue(Object testSubject, int[] coordinates) { 
      return readValue(testSubject, coordinates, 0); 
     } 

     private Integer readValue(Object testSubject, int[] coordinates, int which) { 
      if (testSubject instanceof Object[]) { 
       Object[] subject = (Object[]) testSubject; 
       if (coordinates.length > which + 1) { 
        return readValue(subject[coordinates[which]], coordinates, which + 1); 
       } else { 
        return (Integer) subject[coordinates[which]]; 
       } 
      } else { 
       // Throw some sort of exception? 
       return -1; 
      } 
     } 

     public Iterator<Integer> readValues(Object testSubject, int[] coordinates, int count) { 
      return readValues(testSubject, coordinates, count, 0); 
     } 

     private Iterator<Integer> readValues(Object testSubject, int[] coordinates, int count, int level) { 
      if (testSubject instanceof Object[]) { 
       Object[] subject = (Object[]) testSubject; 
       if (coordinates.length > level + 1) { 
        return readValues(subject[coordinates[level]], coordinates, count, level + 1); 
       } else { 
        return new Iterator<Integer>() { 
         int i = 0; 
         Integer[] intSubject = (Integer[]) subject; 

         @Override 
         public boolean hasNext() { 
          return i <= count; 
         } 

         @Override 
         public Integer next() { 
          return intSubject[coordinates[level] + (i++)]; 
         } 
        }; 
       } 
      } else { 
       // Throw some sort of exception? 
       return null; 
      } 
     } 

    } 

    public void test() { 
     TestMultiDimensioNRead test = new TestMultiDimensioNRead(); 
     Integer[][][][] testSubject = new Integer[5][2][4][]; 

     testSubject[0][0][2] = new Integer[8]; 
     testSubject[0][0][0] = new Integer[15]; 
     testSubject[0][0][1] = new Integer[20]; 
     testSubject[0][0][3] = new Integer[2]; 
     testSubject[1][1][2] = new Integer[7]; 
     testSubject[1][1][2][0] = 80; 
     testSubject[1][1][2][1] = 79; 
     testSubject[1][1][2][2] = 78; 
     Iterator<Integer> them = test.readValues(testSubject, new int[]{1, 1, 2, 0}, 3); 
     for (Integer x = them.next(); them.hasNext(); x = them.next()) { 
      System.out.println(x); 
     } 
     System.out.println(); 

    } 

    public static void main(String args[]) { 
     try { 
      new Test().test(); 
     } catch (Throwable t) { 
      t.printStackTrace(System.err); 
     } 
    } 
} 

打印80预期。

在理智检查方面可能还有更多的工作要做,但这似乎有效。

+0

我明白你的意思,但真正的问题是要读取范围。我的意思是范围可以是这样的:从元素[0] [0] [0] [0]到[4] [1] [1] [0]读取。这意味着你必须阅读这两者之间的所有元素。结果将是一个包含该范围内所有值的数组。一个简单的例子可以是:从[0] [0] [0] [0]到[0] [0] [0] [5]读取,这将是[0] [0] [0] [0], [0] [0] [0] [1],[0] [0] [0] [2],[0] [0] [0] [3],[0] [0] [0] [4 ]和[0] [0] [0] [5]。 – gabun88

+0

@ gabun88 - 你也许可以通过在我们找到正确位置的级别返回一个仓促构造的'Iterator'来做到这一点,但只有当范围处于最深层时才可以。例如,执行诸如'[0] [0] [0] [0]至[0] [0] [5] [5]'的操作将很困难。 – OldCurmudgeon

+0

@ gabun88 - 我添加了一个'readValues',它返回一个'Iterator' - 希望有帮助。 – OldCurmudgeon