2016-07-26 2 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

これはサーバー用です。サービスの1つは、あらゆる次元の配列から値の範囲を読み取ることです。配列はあらかじめ定義されておらず、ディミッションの制限もありません(Javaのディメンション上限のため255を書きました)。これは、サーバーの起動時に作成され、構成ファイルから生成されます。ところで、代替方法やアイデアは大歓迎です、ありがとうございます。 – gabun88

+0

データをパラメータとして次元を渡すことはできますか?呼び出し側のコードがそれを知っていれば(少なくともこの用法のために)、それを把握するアルゴリズムを書くのは意味がありません。 – Kurtymckurt

答えて

0

これを行う方法が見つかりました。多分誰かのためのsomepointで有用です。 私は小切手を入れていませんでした。

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]のようないくつかのようなことができることを意味します。つまり、この2つの間にあるすべての要素を読み取る必要があります。結果は、その範囲内にあるすべての値を持つ配列になります。簡単な例としては、[0] [0] [0] [0]から[0] [0] [0] [5] [0] [0] [0] [0] [0] [0] [0] [2] [0] [0] [0] [3] ]および[0] [0] [0] [5]を含む。 – gabun88

+0

@ gabun88 - 私たちが正しいロカトンを見つけるレベルで急いで構築された 'Iterator'を返すことによって、おそらくそれを行うことができますが、範囲が最も深いレベルにある場合に限ります。たとえば[0] [0] [0] [0]〜[0] [0] [5] [5] 'のようなことをするのは難しいでしょう。 – OldCurmudgeon

+0

@ gabun88 - 私は 'Iterator'を返す' readValues'を追加しました。 – OldCurmudgeon

関連する問題