2011-08-19 11 views
36

Jak mogę wypełnić tablicę wielowymiarową w Javie bez użycia pętli? Próbowałem:Arrayys.fill z wielowymiarową tablicą w Javie

double[][] arr = new double[20][4]; 
Arrays.fill(arr, 0); 

Wynika to w java.lang.ArrayStoreException: java.lang.Double

Dzięki z góry!

+2

ale dlaczego nie użyć pętli? –

+2

@Caroline: Jeśli próbujesz zainicjować tablicę 2d za pomocą 0, nie musisz tego robić, ponieważ jest ona już zainicjalizowana przez 0 podczas przydzielania tablicy i nie możesz zainicjować żadnej tablicy bez użycia pętli.Możesz po prostu ukryć zapętla się w funkcji podobnie jak w pliku Arrays.fill. – Emil

+1

Hej, nie przesadzajcie teraz. Wszystko, czego chciał, to jakaś metoda w Java API, która inicjuje wielowymiarowe tablice do pewnej wartości domyślnej w jednym kroku. To właśnie chciał powiedzieć bez pętli. –

Odpowiedz

48
double[][] arr = new double[20][4]; 
Arrays.fill(arr[0], 0); 
Arrays.fill(arr[1], 0); 
Arrays.fill(arr[2], 0); 
Arrays.fill(arr[3], 0); 
Arrays.fill(arr[4], 0); 
Arrays.fill(arr[5], 0); 
Arrays.fill(arr[6], 0); 
Arrays.fill(arr[7], 0); 
Arrays.fill(arr[8], 0); 
Arrays.fill(arr[9], 0); 
Arrays.fill(arr[10], 0); 
Arrays.fill(arr[11], 0); 
Arrays.fill(arr[12], 0); 
Arrays.fill(arr[13], 0); 
Arrays.fill(arr[14], 0); 
Arrays.fill(arr[15], 0); 
Arrays.fill(arr[16], 0); 
Arrays.fill(arr[17], 0); 
Arrays.fill(arr[18], 0); 
Arrays.fill(arr[19], 0); 
+3

Hi. Jestem tylko ciekawostką, aby wiedzieć, dlaczego sugerujesz to rozwiązanie, a nie klasyczne "za". Czy istnieje motywacja? Dzięki! – Maverik

+61

Z powodu następujących słów w pytaniu: "bez użycia pętli". Moje rozwiązanie jest po prostu śmieszne, ale poprawnie odpowiada na pytanie. – trojanfoe

+2

Przepraszam, brakowało mi "bez użycia pętli" z OP: usunąłem moje głosowanie. Być może powinieneś zauważyć w swojej odpowiedzi, że sugestia nie powinna być traktowana zbyt poważnie. –

69

To dlatego double[][] jest tablicą double[] których nie można przypisać do 0.0 (to będzie jak robi double[] vector = 0.0). W rzeczywistości Java nie ma prawdziwych wielowymiarowych tablic.

Jak to się dzieje, 0.0 jest wartością domyślną dla deblu w Javie, więc matryca rzeczywiście już być wypełnione zerami gdy je dostać od new. Jeśli jednak chcesz go wypełnić, powiedzmy, 1.0, możesz wykonać następujące czynności:

Nie sądzę, że interfejs API zapewnia metodę rozwiązania tego problemu bez użycia pętli. Jest to jednak dość proste, aby zrobić to za pomocą pętli for-each.

double[][] matrix = new double[20][4]; 

// Fill each row with 1.0 
for (double[] row: matrix) 
    Arrays.fill(row, 1.0); 
+0

To też wystarcza 'Arrays.fill (arr, 0d);' lub 'Arrays.fill (arr, (double) 0);' –

+2

Dostaję ' Wyjątek w wątku "main" java.lang.ArrayStoreException: java.lang.Double', chyba że przejdę przez te wiersze. – aioobe

+0

Dlaczego nie próbujesz zrozumieć tej odpowiedzi? W java (i C i C++) nie ma tablic wielowymiarowych !!! Twoja macierz jest prostą jednowymiarową tablicą, gdzie każde "pole" jest ponownie jedną tablicą dimensinów. Twoje połączenie z Arrays.fill() próbuje umieścić _int_ (mieć podwójny zapis 0.0, a nie tylko 0) w "macierzy", co nie działa. –

3

jak mogę wypełnić tablicę wielowymiarową w Javie bez użycia pętli?

Tablice wielowymiarowe są tylko tablice tablic i fill(...) nie sprawdza typ tablicy a wartością Ci przepustkę (odpowiedzialność ta spoczywa na dewelopera).

Dzięki temu nie można w wystarczającym stopniu wypełnić tablicy wielowymiarowej bez użycia pętli.

Należy pamiętać, że w przeciwieństwie do języków takich jak C lub C++, tablice Java są obiektami, a w wielowymiarowych tablicach wszystkie oprócz ostatniego poziomu zawierają odwołania do innych obiektów Array. Nie jestem w 100% pewny co do tego, ale najprawdopodobniej są one rozprowadzane w pamięci, więc nie można po prostu wypełnić sąsiedniego bloku bez pętli, jak na przykład C/C++.

7

OP zapytał, jak rozwiązać ten problem bez pętli! Z jakiegoś powodu modne jest obecnie unikanie pętli. Dlaczego to? Prawdopodobnie istnieje świadomość, że używanie map, reduce, filter i znajomych oraz metod takich jak each ukrywa pętle i obcina programową wersję i jest w porządku. To samo dotyczy naprawdę słodkich rurociągów Uniksa. Lub kod jQuery. Wszystko wygląda świetnie bez pętli.

Ale czy Java ma metodę map? Niezupełnie, ale możemy zdefiniować jeden z interfejsem Function za pomocą metody eval lub exec. Nie jest to zbyt trudne i byłoby dobrym ćwiczeniem. To może być kosztowne i nie używane w praktyce.

Innym sposobem wykonania tego jest bez pętli jest użycie rekursji ogonowej. Tak, jest to trochę głupie i nikt nie używałby go w praktyce, ale okazuje się, że w tym przypadku pętle są w porządku.Niemniej jednak, po prostu pokazać „kolejny przykład” pętli darmo i baw się dobrze, tutaj jest:

import java.util.Arrays; 
public class FillExample { 
    private static void fillRowsWithZeros(double[][] a, int rows, int cols) { 
     if (rows >= 0) { 
      double[] row = new double[cols]; 
      Arrays.fill(row, 0.0); 
      a[rows] = row; 
      fillRowsWithZeros(a, rows - 1, cols); 
     } 
    } 

    public static void main(String[] args) { 
     double[][] arr = new double[20][4]; 
     fillRowsWithZeros(arr, arr.length - 1, arr[0].length); 
     System.out.println(Arrays.deepToString(arr)); 
    } 
} 

Nie jest ładna, ale w odpowiedzi na pytanie OP, nie ma jednoznacznychpętle.

+0

+1, nie dla rozwiązania, ale za naprawdę dobrą odpowiedź – Dragon8

+0

Dziękujemy za wszystkie rozwiązania! Powód, dla którego nie chcę używać pętli? Szukałem prostego rozwiązania do generowania macierzy zer zerowej jak w MATLAB. – Caroline

+0

Może to nadal powodować przepełnienie stosu, ponieważ Java nie obsługuje rekurencji ogona, więc w pętli zdecydowanie> rekurencja. – mc10

1

Jako rozszerzenie odpowiedzi, znalazłem ten post, ale chciałem wypełnić czterowymiarową tablicę. Oryginalny przykład to tylko tablica dwuwymiarowa, ale pytanie mówi "wielowymiarowy". Nie chciałem dodawać nowego pytania ...

Możesz użyć tej samej metody, ale musisz zagnieździć je, aby w końcu dostać się do tablicy jednowymiarowej.

fourDArray = new float[10][10][10][1]; 
// Fill each row with null 
for (float[][][] row: fourDArray) 
{ 
    for (float[][] innerRow: row) 
    { 
     for (float[] innerInnerRow: innerRow) 
     { 
     Arrays.fill(innerInnerRow, -1000); 
     } 
    } 
}; 
-5
Arrays.fill(arr, new double[4]); 
+1

Ta linia powoduje, że każdy wiersz odnosi się do tego samego bloku pamięci, tj. Zmiana arr [1] [5] również zmieni arr [100] [5]. –

0

Nie wszyscy czasami szkoda, że ​​nie było
<T>void java.util.Arrays.deepFill(T[]…multiDimensional). Problemy zaczynają się
Object threeByThree[][] = new Object[3][3];
threeByThree[1] = null; i
threeByThree[2][1] = new int[]{42}; jest całkowicie legalne.
(Jeśli tylko Object twoDim[]final[] była legalna i dobrze zdefiniowane ...)
(przy użyciu jednej z metod publicznych od dołu przechowuje pętle od wywołującego kodu źródłowego.
Jeśli upierasz się przy użyciu żadnych pętli w ogóle zastąpić pętle i połączenia do Arrays.fill() (!) za pomocą rekursji.)

/** Fills matrix {@code m} with {@code value}. 
* @return {@code m}'s dimensionality. 
* @throws java.lang.ArrayStoreException if the component type 
* of a subarray of non-zero length at the bottom level 
* doesn't agree with {@code value}'s type. */ 
public static <T>int deepFill(Object[] m, T value) { 
    Class<?> components; 
    if (null == m || 
     null == (components = m.getClass().getComponentType())) 
     return 0; 
    int dim = 0; 
    do 
     dim++; 
    while (null != (components = components.getComponentType())); 
    filler((Object[][])m, value, dim); 
    return dim; 
} 
/** Fills matrix {@code m} with {@code value}. 
* @throws java.lang.ArrayStoreException if the component type 
* of a subarray of non-zero length at level {@code dimensions} 
* doesn't agree with {@code value}'s type. */ 
public static <T>void fill(Object[] m, T value, int dimensions) { 
    if (null != m) 
     filler(m, value, dimensions); 
} 

static <T>void filler(Object[] m, T value, int toGo) { 
    if (--toGo <= 0) 
     java.util.Arrays.fill(m, value); 
    else 
     for (Object[] subArray : (Object[][])m) 
      if (null != subArray) 
       filler(subArray, value, toGo); 
} 
0
public static Object[] fillArray(Object[] arr,Object item){ 
    Arrays.fill(arr, item); 
    return arr; 
} 
Character[][] maze = new Character[10][10]; 
    fillArray(maze, fillArray(maze[0], '?')); 

    for(int i = 0;i<10;i++){ 
     System.out.println(); 
     for(int j = 0;j<10;j++){ 
      System.out.print(maze[i][j]); 
     } 
    } 

mam nadzieję, że dobrze

0

Korzystanie Java 8, można zadeklarować i zainicjować dwuwymiarową tablicę bez użycia (Explicit) Pętli, jak następuje:

int x = 20; // first dimension 
int y = 4; // second dimension 

double[][] a = IntStream.range(0, x) 
         .mapToObj(i -> new double[y]) 
         .toArray(i -> new double[x][]); 

to zainicjować tablic z wartościami domyślnymi (0.0 w przypadku double).

w przypadku chcesz, aby wyraźnie określić wartość wypełnienia, który będzie używany, można dodać w DoubleStream:

int x = 20; // first dimension 
int y = 4; // second dimension 
double v = 5.0; // fill value 

double[][] a = IntStream 
     .range(0, x) 
     .mapToObj(i -> DoubleStream.generate(() -> v).limit(y).toArray()) 
     .toArray(i -> new double[x][]);