2016-12-27 5 views
0

sagen, dass ich eine Gleichung haben:Java - Funktion/Methode, die sowohl skalare und Vektorargumente akzeptiert?

out = Math.exp(x); 

wo x ein double ist.

sagen, dass ich es 10.000 mal tun, so werfe ich es in einer Funktion:

public double doMath(double x) { 
    return Math.exp(x); 
} 

einfach genug. Ich kann jeden Skalar es passieren:

double in = 1.1234; 

out = doMath(in); 

// Outputs something like: 1.1313368652 

aber versucht, einen Vektor, um es (1D-Array, 2D-Array, und so weiter ...) zu passieren alle möglichen Probleme verursacht:

double[] in = {0.1234, 5.6789}; 

out = doMath(in); 

// Outputs something like: IT DOESN'T OUTPUT! CRASH CRASH CRASH! 

Was ich möchte, ist in der Lage zu sein, jedes Doppel (Skalar, 1D, 2D, 3D, usw.) zu übergeben und die gleiche Größe wie die Eingabe zurückzugeben, nachdem es die Gleichung durchlaufen hat, wobei die Arithmetik auf jedes Element angewendet wird.

Testfälle

double in = 0.1234; 

/* 
1.1313368652 
*/ 

double[] in = {0.1234, 5.6789}; 

/* 
[ 1.1313368652, 292.6273627191 ] 
*/ 

double[][] in = {{0.1234, 5.6789}, 
       {0.9876, 5.4321}}; 

/* 
[ [ 1.1313368652, 292.6273627191 ] 
    [ 2.6847832542, 228.6288622608 ] ] 
*/ 

double[][][] in = {{{0.1234, 5.6789}, {0.9876}}, 
        {{5.4321}}, 
        {{0}, {1}}}; 

/* 
[ [ [ 1.1313368652 292.6273627191 ] [ 2.6847832542 ] ] 
    [ [ 228.6288622608 ] ] 
    [ [ 1 ] [ 2.7182818285 ] ] ] 
*/ 

Der einzige Weg, ich jetzt overloading haben verwendet:

public double doMath(double x) 

public double[] doMath(double[] x) 

public double[][] doMath(double[][] x) 

public double[][][] doMath(double[][][] x) 

Aber das ist langweilig. Kann eine einzelne Funktion geschrieben werden, um irgendeine Dimension des Arguments aufzunehmen und etwas Ähnliches wie die Beispiele zu liefern, die ich zur Verfügung gestellt habe?

Vielleicht gibt es einen Namen dafür, und ich weiß es einfach nicht? Dies sind alles nur Arrays, aber ich behandle sie (und mache andere Operationen an ihnen), als wären sie Matrizen unterschiedlicher Größe.

Edit # 1 - Zusätzlich ...

habe ich versucht, so etwas wie:

public double doMath(int... x) 

Und es funktionierte für skalare und 1D, aber nichts mit höheren Dimensionen.

Edit # 2

Ist es möglich, eine benutzerdefinierte Klasse zu schreiben, das automatisch erledigt dies für mehrere Funktionen?

Zum Beispiel, sagen, ich habe drei verschiedene Funktionen bekommen:

public mysteryClass firstFunct(mysteryClass x) { 
    return Math.pow(x, 2); 
} 

public mysteryClass secondFunct(mysteryClass x) { 
    return Math.exp(x); 
} 

public mysteryClass thirdFunct(mysteryClass x) { 
    return (1 + x)/2; 
} 

Und jede Funktion verwendet werden kann - als ist - mit einer beliebigen Anzahl von Dimensionen? mysteryClass würde dann jedes Element automatisch rekursiv durch die Funktionen laufen lassen, ohne die Funktionen ändern zu müssen oder jedes Element manuell durchlaufen zu müssen? Nicht sicher, ob es für ein Objekt möglich ist, zu wissen, wie es verwendet wird, und entsprechend anzupassen.

Vielen Dank im Voraus.

+0

Das ist kein Polymorphismus. Es ist überladen. – ajb

+0

@ajb danke, machte die Änderung. – Birrel

Antwort

1

Ich weiß nicht, von einem integrierten Weg, dies zu tun, aber ich habe so etwas wie dies funktioniert:

public static Object applyAll(Object x) { 
    if (x instanceof Double) { 
     return doFunc((Double) x); 
    } 
    else if (x instanceof Object[]) { 
     List<Object> result = new ArrayList<>(); 
     for (Object element : (Object[])x) { 
      result.add(applyAll(element)); 
     } 
     return result.toArray(new Object[0]); 
    } 
    else { 
     throw new RuntimeException("Unexpected class: " + x.getClass()); 
    } 
} 

applyAll Arbeiten entweder auf einen Double oder einen Array, und wenn es ein Array , ruft es sich rekursiv über die Elemente auf und erstellt ein Ergebnisarray. Das Endergebnis ist, dass die Array-Struktur des Endergebnisses mit der Struktur des äußersten Arguments übereinstimmt. Wenn jedoch ein Element ein anderes Element als Double oder ein Array ist, wird eine Ausnahme ausgelöst. doFunc ist eine Methode, die ein double oder Double Argument akzeptiert und eine double oder Double zurückgibt. Sie könnten die Funktion einfach als Argument übergeben (über eine Java 8-Funktionsschnittstelle), anstatt doFunc zu definieren. In Ihrem Beispiel würde doFuncMath.exp auf sein Argument zurückgeben.

Dies ist möglicherweise nicht der beste Code, aber es funktioniert. Sie müssen nicht wirklich eine Liste erstellen und dann in ein Array konvertieren, da die Größe des Arrays bereits bekannt ist. Ich habe jedoch nicht versucht, es zu verfeinern. Sie können diese nach Bedarf verbessern oder ändern.

+0

Ich sehe nicht warum. Ich habe das Problem wahrscheinlich nicht richtig verstanden und dachte, dass die Argumente wie '{1.0, {2.0, 3.0}, 4.0}' gemischt werden könnten; Mein Code behandelt diesen Fall, aber es ist möglicherweise nicht notwendig. Aber diese Antwort behandelt auch eine unbegrenzte Anzahl von Dimensionen. Selbst wenn die Anforderungen sind, dass es ein n-dimensionales Array sein muss und "n" ziemlich klein ist (z. B. <= 3), sehe ich nicht, warum Sie gegen diese Antwort Einwände erheben würden. Jede Leistung, die dadurch entsteht, dass sie allgemeiner wird, wird zwangsläufig sehr gering ausfallen. – ajb

+0

Was meinen Sie mit "Sie müssen immer noch einen Fall für jede Anzahl von Dimensionen implementieren"? Dieser Code funktioniert auf n-dimensionalen Arrays beliebigen Grades. – ajb

+0

Entschuldigung, habe den Code falsch gelesen. Kommentar entfernen –

2
class IncompatibleMultiDoubleException extends RuntimeException { 
} 

class MultiDouble { 
    private double[] data; 
    private int[] dims; 

    public MultiDouble(int...dimensions) { 
    dims = dimensions; 
    int tot = 1; 
    for (int d : dimensions) { 
     tot *= d; 
    } 
    data = new double[tot]; 
    } 

    // multiply matrix by value 
    void cMul(double c) { 
    for (int i=0; i<data.length; i++) { 
     data[i] *= c; 
    } 
    } 

    // add two matrices together 
    void add(MultiDouble other) { 
    for(int i=0; i<other.dims.length; i++) { 
     if (dims[i] != other.dims[i]) { 
     throw new IncompatibleMultiDoubleException(); 
     } 
    } 
    } 
    // return the index in the data array corrisponding to the 
    // given multidim coordinates 
    private int index(int...coords) { 
    int res = 0; 
    for(int i=0; i<coords.length; i++) { 
     int tmp = coords[i]; 
     for(int j=i+1; j<coords.length; j++) { 
     tmp *= dims[j]; 
     } 
     res += tmp; 
    } 
    return res; 
    } 

    public void set(double value, int...coords) { 
    data[index(coords)] = value; 
    } 

    public double get(int...coords) { 
    return data[index(coords)]; 
    } 
+0

Mit dem 1D-Array, das Sie einrichten ('double [] data'), ist es extrem schwierig, etwas wie' A * B' (Matrixmultiplikation) zu machen, wenn die Spalten und Zeilen nicht klar definiert sind. – Birrel

+0

warum? Der Konstruktor empfängt und speichert alle Dimensionen, sodass alle Operationen diese Informationen verwenden können, um Indizes für die verschiedenen Dimensionen in den Index im Array zu mappen. Ich kann den Code für bidim hinzufügen. Multiplikation bei Bedarf –

+0

@Birrle es ist nicht wirklich schwierig. Wenn Sie ein 2D-Array _A_ ​​mit _r_ Zeilen und _c_ Spalten als 1D Vektor _V_ mit _rc_ Elementen darstellen, dann greifen Sie auf 'A [m, n]' zu, indem Sie auf 'V [cm + n]' zugreifen. In Sprachen mit echten mehrdimensionalen Arrays (Java gehört nicht dazu) werden 2D-Arrays vom Compiler gehandhabt (und verallgemeinert zu mehrdimensionalen Arrays). – ajb

Verwandte Themen