# Array - Wert am nächsten zur vollen Sekunde



## Thomas21 (29. Jan 2016)

Hallo,
ich soll ein Java-Programm schreiben, welches aus einer CSV-Datei Werte ausließt und in einer Array speichert.
Die Maximal- und Minimalwerte aus einigen Spalten sollen ausgegeben werden, was auch schon funktioniert.
Jetzt komme ich an dieser Stelle nicht weiter:
Es ist eine eine Spalte mit Zeitstempeln vorhanden. Es soll nun für einige Zeilen aus dem Array der Wert herausgesucht werden, der näher an der vollen Sekunde liegt.

Ich bin für jede Hilfe dankbar

P.S. Mein Professor hat 2 Klassen vorgegeben, die System.Out. und das Daten einlesen ändern. Also nicht verwirren lassen^^


```
import java.io.IOException;

import de.hs_osnabrueck.iui.input_output.DateiInput;
import de.hs_osnabrueck.iui.input_output.IO;

public class Hausarbeit
{
    public static void main(String[] args)
    {
        try
        {
            DateiInput leser = new DateiInput("A05_INP_Sensordaten.csv");
            String Zeile = null;
            double[] Maxwert = new double[3];
            double[] Minwert = { 1, 1, 1 };
            double Wert;
            // Spaltennamen ignorieren
            leser.leseZeile();
            while ((Zeile = leser.leseZeile()) != null)
            {
                String[] Wertefeld = Zeile.split(";");
                // X Wert Max
                Wert = Double.parseDouble(Wertefeld[19]);
                if (Wert > Maxwert[0])
                {
                    Maxwert[0] = Wert;
                } // X Wert Min
                if (Wert < Minwert[0])
                {
                    Minwert[0] = Wert;
                }
                // Y Wert Max
                Wert = Double.parseDouble(Wertefeld[20]);
                if (Wert > Maxwert[1])
                {
                    Maxwert[1] = Wert;
                }
                // Y Wert Min
                if (Wert < Minwert[1])
                {
                    Minwert[1] = Wert;
                }
                // Z Wert Max negativ
                Wert = Double.parseDouble(Wertefeld[21]);
                if (Math.abs(Wert) > Maxwert[2])
                {
                    Maxwert[2] = Wert;
                }
                // Z Wert Min
                if (Wert < Minwert[2])
                {
                    Minwert[2] = Wert;
                } 
                //Wert = Double.parseDouble(Wertefeld[18]);
                //double Zeit = (double) Math.round (Wert);
                //IO.println (Zeit);
            }
            leser.schliesseDatei();
            IO.println("Maximal Werte:");
            IO.print("Maximaler X Wert: ");
            IO.println(Maxwert[0]);
            IO.print("Maximaler Y Wert: ");
            IO.println(Maxwert[1]);
            IO.print("Maximaler Z Wert: ");
            IO.println(Maxwert[2]);
            IO.println("Minimal Werte:");
            IO.print("Minimaler X Wert: ");
            IO.println(Minwert[0]);
            IO.print("Minimaler Y Wert: ");
            IO.println(Minwert[1]);
            IO.print("Minimaler Z Wert: ");
            IO.println(Minwert[2]);
            IO.println("Zeit:");
            IO.print("Näher an voller Sekunde: ");
         
        } catch (IOException e)
        {
            IO.println("Fehler beim Lesen der Datei!" + e.getLocalizedMessage());
            System.exit(1);
        }
    }
}
```


----------



## Jardcore (29. Jan 2016)

Kannst du vielleicht einen Eintrag der csv Datei posten?
Welches Format hat zum Beispiel der Zeitstempel?



Thomas21 hat gesagt.:


> Es ist eine eine Spalte mit Zeitstempeln vorhanden. Es soll nun für einige Zeilen aus dem Array der Wert herausgesucht werden, der näher an der vollen Sekunde liegt.


Für einige Zeilen ist ein wenig unspezifisch 

Beste Grüße,
Jar


----------



## Thomas21 (29. Jan 2016)

Zum Beispiel wurde ein Datensatz zum Zeitpunkt 79083.99795400001 aufgenommen und ein anderer um 79084.007643
Der erste Satz würde näher zur vollen Sekunde liegen.
Ich meine mit "einigen Zeilen", dass die CSV-Datei viele Spalten hat, ich aber nur mit einigen Spalten arbeiten muss
Ich kann die CSV Datei leider nicht hochladen


----------



## Jardcore (29. Jan 2016)

Kopiere mal bitte eine Zeile aus der CSV und füge sie hier ein.


----------



## Joose (29. Jan 2016)

Mir fehlt eine konkrete Frage. Wo genau liegt dein Problem nun?
Geht es darum den richtigen Wert zu finden (welcher näher an der Sekunde ist) oder um das Filtern der Zeilen?

Wenn es dir um den richtigen Wert geht .... welche Zeile wird mit welcher verglichen? Oder geht es darum von den X Zeilen die EINE zu finden?


----------



## Thomas21 (31. Jan 2016)

loggingTime loggingSample locationTimestamp_since1970 locationLatitude locationLongitude locationAltitude locationSpeed locationCourse locationVerticalAccuracy locationHorizontalAccuracy locationFloor locationHeadingTimestamp_since1970 locationHeadingX locationHeadingY locationHeadingZ locationTrueHeading locationMagneticHeading locationHeadingAccuracy accelerometerTimestamp_sinceReboot accelerometerAccelerationX accelerometerAccelerationY accelerometerAccelerationZ gyroTimestamp_sinceReboot gyroRotationX gyroRotationY gyroRotationZ motionTimestamp_sinceReboot motionYaw motionRoll motionPitch motionRotationRateX motionRotationRateY motionRotationRateZ motionUserAccelerationX motionUserAccelerationY motionUserAccelerationZ motionAttitudeReferenceFrame motionQuaternionX motionQuaternionY motionQuaternionZ motionQuaternionW motionGravityX motionGravityY motionGravityZ motionMagneticFieldX motionMagneticFieldY motionMagneticFieldZ motionMagneticFieldCalibrationAccuracy IP_en0 IP_pdp_ip0 deviceOrientation state
10.07.2015 10:26 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 79.083.085.072 0.028228759765625 0.038360595703125 -0.99737548828125 7.908.308.008.300.000 0.4469950773710417 -0.5616524180983321 -0.04667615916138278 79.083.065.099 309.125.708.547.211 0.05564074035369208 -0.04683326189206986 -0.1052720919251442 -0.1092088893055916 -0.0002046981826424599 0.007071012631058693 -7,85E+10 -0.02025096863508224 XArbitraryZVertical -0.0283893491525067 -0.02269819721105627 0.9990061147069346 0.02579960224965382 0.05555105954408646 0.0468161441385746 -0.9973576664924622 0 0 0 -1 0.0.0.0 10.34.89.50 5 0


es geht um die Spalte "accelerometerTimestamp_sinceReboot". Hier sollen die Werte gefunden werden die jeweils am nächsten zur vollen Sekunde sind. Dann sollen die Werte in den Spalten:
"accelerometerAccelerationX;accelerometerAccelerationY;accelerometerAccelerationZ" zu diesem Zeitpunkt, bzw in dieser Zeile, ausgegeben werden.


----------



## Meniskusschaden (31. Jan 2016)

Bin nicht sicher, ob ich die Aufgabenstellung richtig verstanden habe und wiederhole sie deshalb mit meinen Worten:

Es gibt eine Datei mit einer großen Menge von Sensordaten. Zielsetzung ist es, die Datenmenge so zu reduzieren, daß nur noch eine Zeile pro Sekunde als Ergebnis geliefert wird. Dazu soll jeweils die Zeile verwendet werden, deren Zeitstempel der Sekunde am nächsten liegt.

Ich nehme an, die Datei ist bereits nach Zeitstempeln sortiert. Dann kannst du es vielleicht versuchen, indem du mit vorläufigen Ergebnissen arbeitest. Du liest die Datei zeilenweise durch und vergleichst bei jeder Iteration die neue Zeile (NZ) mit dem bisherigen vorläufigen Ergebnis (VE). Falls NZ "besser" als VE ist, wird NZ als neues VE festgelegt. Falls NZ schlechter ist, wird VE der endgültigen Ergebnismenge hinzugefügt und NZ wird als neues VE festgelegt, denn es könnte ja die beste Zeile für die nächste Sekunde sein.

Das ist natürlich nur ein Ansatz, bei dem noch Detailprobleme gelöst werden müssen, aber nach dem Prinzip müsste es doch funktionieren.


----------



## Thomas21 (1. Feb 2016)

Genau das ist die Aufgabenstellung
So wie es aussieht sind die Zeitstempel sortiert, haben aber unterschiedliche Nachkommastellen. Ich denke das die Werte zuerst gerundet werden müssen.
Vom Konzept her habe ich es mir auch so ähnlich vorgestellt aber ich bekomme die Umsetzung nicht hin.


----------



## Meniskusschaden (1. Feb 2016)

Die Zahlen kann ich nicht nachvollziehen. Die ersten beiden Beispiele aus Post #3 enthielten jeweils genau einen Dezimalpunkt. Da bin ich davon ausgegangen, dass der für das Komma steht und der ganzzahlige Anteil die Sekunden seit 1970 repräsentiert und der Nachkommateil den Sekundenbruchteil. In Post #6 und #8 gibt es aber nur noch Tausenderpunkte und keine Nachkommastellen. Da stimmt doch irgendetwas mit den Daten nicht.


----------



## Thomas21 (1. Feb 2016)

Ich finde die Zahlen auch sehr seltsam.
Die CSV ist leider so vorgegeben und darf nicht verändert werden.
In der Aufgabenstellung ist 79084 als "Beispielsekunde" angegeben.
79083085072 ist der erste Wert und 7911957783991660 der letzte. Der Zeitraum beträgt also 36 Sekunden, das passt soweit auch.
Die Punkte werden in Excel falsch dargestellt (Bild). Es ist einfach so das die Zahlen verschiedene Dezimalstellen haben aber die vollen Sekunden die 5te Stelle der Zahl sind.


----------



## Meniskusschaden (1. Feb 2016)

Okay, dann gibt es offenbar nur unterschiedlich viele Nachkommastellen. Das dürfte keine Rolle spielen. Wenn man sich noch die Überschriften ansieht stellt der Wert wohl die Sekunden seit dem letzten Reboot dar. Dann kann man die Werte ja einfach in double-Variablen einlesen und die Differenzen zur vollen Sekunde vergleichen: `if (Math.abs(Zeitstempel1 - Sekunde) < (Math.abs(Zeitstempel2 - Sekunde) { ... }`.

Ich würde noch einmal hinterfragen, ob es wirklich der zur vollen Sekunde nächstgelegene Wert sein muß, oder ob es genügt, den ersten Wert zu nehmen, der größer oder gleich der vollen Sekunde ist. Wenn man es sich leisten kann, die übrigen Zeilen weg zu lassen ist das ja nicht so abwegig und vereinfacht den Algorithmus. Man müßte dann nur die Zeilen ausgeben, für die `Math.floor(Zeitstempel) != Math.floor(vorigerZeitstempel)` gilt.

Falls man doch den nächstgelegenen Wert nehmen muß, würde ich meinen Ansatz aus Post #7 verfolgen. Mir ist aber nicht bewußt, ob bzw. wo es da noch hakt.


----------



## Thomas21 (2. Feb 2016)

Der erste Ansatz müsste der Richtige sein. Es gibt glaube ich keinen "glatten" Sekundenwert und ich benötige den Wert der am nächsten an der vollen Sekunde ist, also egal ob geringer oder hoher.

Ich habe einen Aufnahmezeitraum von 36 Sekunden. Muss ich 
if (Math.abs(Zeitstempel1 - Sekunde) < (Math.abs(Zeitstempel2 - Sekunde) { ... }.
36 mal anwenden? also für jede Sekunde?

Vielen Dank für die Hilfe bisher

P.S. Ich hätte eher an eine for Schleife gedacht, die die gesamte Spalte vom Array durchläuft und den Wert mit der geringsten Differenz ausgibt. Es hakt nur noch an der Umsetzung^^


----------



## Thomas21 (2. Feb 2016)

Ich bin nun etwas weiter gekommen und stehe hoffentlich nur noch vor einer Frage.
Ich habe die Zeitstempel Spalte in ein Array eingelesen. 

if (Math.abs(Zeitstempel1 - Sekunde) < (Math.abs(Zeitstempel2 - Sekunde)

Diese Zeile wäre für mich logisch wenn es sich tatsächlich nur um 2 Zahlen handeln würde. Ich muss die jeweilige Sekunde aber mit dem gesamten Array vergleichen. 

Hat jemand einen Tipp


----------



## Jardcore (2. Feb 2016)

Das Array einfach durch gehen wäre eine Möglichkeit, in etwa so:

```
long aktuellerZeitstempelDerNaeherAnDerSekundeLiegt;
for(String zeitstempelAusArray : gesamtesArray) {
    if (Math.abs(zeitstempelAusArray - Sekunde) < (Math.abs(aktuellerZeitstempelDerNaeherAnDerSekundeLiegt- Sekunde) {
        aktuellerZeitstempelDerNaeherAnDerSekundeLiegt = zeitstempelAusArray;
    }
}
```


----------



## Meniskusschaden (2. Feb 2016)

Ich denke, man kann das so machen, wie Jardcore schreibt. Aber wo kommt die Sekunde eigentlich her? Du mußt es doch nicht nur für eine Sekunde machen, sondern für den gesamten Zeitraum, den die Datei umfasst, oder? Dann müsstest du für jede Sekunde die gesamte Schleife verarbeiten und hättest eine Laufzeit von O(n*m), wenn n die Zeilenanzahl und m die Sekundenanzahl ist. Wenn du ausnutzt, dass die Datei chronologisch sortiert ist, musst du jede Zeile eigentlich nur einmal verarbeiten und kommst auf O(n). Aber vielleicht sind die Dateien so klein, dass es egal ist.


----------



## Thomas21 (3. Feb 2016)

Für den Code von Jardcore brauche ich ein 1D Array richtig?
Ich müsste dann nur noch aus Wertefeld[18] ein eigenes Array erstellen oder? Ich habe leider keine Ahnung wie ich das anstellen soll

ich denke das Wertefeld[18] quasi ein eigenes Array ist. Aber ich kann es in dieser Form nicht mit diesem Code verwenden.


----------



## Thomas21 (3. Feb 2016)

Ich müsste die gesplitteten Zeitstempel also zeilenweise in jeweils einen "Bereich" vom Array speichern. 
Bei ca. 4000 Werten ist das vielleicht nicht die eleganteste Methode, aber ich möchte das Programm einfach nur irgendwie zum laufen bekommen da morgen Abgabetermin ist.

Zeitstempel = Double.parseDouble(Wertefeld[18]);
double[] Zeitstempel = new double[5000];

Kann man die werte nicht jetzt mit einer for-schleife ins array speichern?


----------



## Meniskusschaden (3. Feb 2016)

Willst du im Array jetzt pro Zeile nur Wertefeld[18] speichern oder alle Wertefelder oder nur eine Auswahl (z.B. vier Wertefelder)?

Im ersten Fall wäre dein double-Array in Ordnung. Im zweiten und dritten Fall brauchst du ein zweidimensionales Array (im dritten Fall wären auch vier eindimensionale Arrays möglich, aber häßlich). Die erste Dimension für die Zeilen, die zweite für die Spalten.

Generell wäre aber für die Zeilenspeicherung z.B. eine ArrayList besser geeignet, weil die Zeilenzahl vorher nicht bekannt ist. Beim Array ist die statische Festlegung der Array-Größe dafür nicht so gut. Für die Spalten ist ein Array aber gut, weil die Spaltenzahl konstant ist.


----------



## Thomas21 (3. Feb 2016)

In dem Array sollen nur die Werte aus Wertefeld [18] gespeichert werden.
Also:
Zeitstempel[1]= 7911871355291660;
Zeitstempel[2]= 7911908256491660;
usw...
Die Anzahl der Werte ist ja bekannt.


----------



## Meniskusschaden (3. Feb 2016)

Okay, ich verstehe zwar nicht, woher die Anzahl bekannt ist, denn du hast ca. 4000 Werte vorliegen aber ein Array mit 5000 Elementen deklariert. Das sieht ja mehr nach einer vorsichtigen Schätzung aus und wenn doch mal 5100 Werte kommen, knallt's.

Jedenfalls genügt dann ein eindimensionales Array, wie du es in Post #17 deklariert hast. Ich würde es bei der while-Schleife aus dem ersten Post belassen. Du musst also einfach nur vor der Schleife dein Array deklarieren und dann in jeder Iteration ein Element hinzufügen. Die double-Konvertierung aus Post #17 ist ebenfalls okay. Du brauchst natürlich noch eine Variable für den Array-Index, die du bei jeder Iteration hoch zählen musst.

Du kannst auch eine for-Schleife verwenden und anstelle der zusätzlichen Variablen die Laufvariable als Array-Index benutzen. Zum Einlesen von Dateien ist normalerweise aber eine while-Schleife besser, weil es untypisch ist, dass man vorher die exakte Zeilenzahl kennt.

Eigentlich hast du bereits alles erwähnt, was du brauchst und musst es nur noch zusammenbauen.


----------



## Jardcore (4. Feb 2016)

```
String[] aktuelleZeile;
long aktuellerZeitstempelDerNaeherAnDerSekundeLiegt;

while((aktuelleZeile = record.next()) != null) {
   double zeitstempelAusArray = getValueAsDouble(aktuelleZeile[ZEITSTEMPEL_INDEX]);
   if(Math.abs(zeitstempelAusArray - Sekunde)<(Math.abs(aktuellerZeitstempelDerNaeherAnDerSekundeLiegt - Sekunde){
        aktuellerZeitstempelDerNaeherAnDerSekundeLiegt = zeitstempelAusArray;
   }
}
```

In Pseudocode würde man sowas ähnliches wohl machen.
Eine while Schleife die dir eine ganze Zeile der CSV Datei als Liste bzw. String Array zurückgibt.
Dann kannst du an der Stelle des Zeitstempels den Wert anschauen in Double umwandeln und diesen dann vergleichen.


----------

