Collections Daten in Dreiecksform

padde479

Bekanntes Mitglied
Ich habe eine Frage zu einer Dreiecksform. Ich habe in einer Datei Zahlen in Dreiecksform stehen, z. B.
Code:
 1;  2;  3;  4;  5;  6;  7;  8;  9; 10;
11; 12; 13; 14; 15; 16; 17; 18; 19;   ;
20; 21; 22; 23; 24; 25; 26; 27;   ;   ;
28; 29; 30; 31; 32; 33; 34;   ;   ;   ;
35; 36; 37; 38; 39; 40;   ;   ;   ;   ;
41; 42; 43; 44; 45;   ;   ;   ;   ;   ;
46; 47; 48; 49;   ;   ;   ;   ;   ;   ;
50; 51; 52;   ;   ;   ;   ;   ;   ;   ;
53; 54;   ;   ;   ;   ;   ;   ;   ;   ;
55;   ;   ;   ;   ;   ;   ;   ;   ;   ;
Diese Datei kann mal mehr mal weniger Zeilen/Spalten haben. Ich wollte das erst über Array lösen, die sind mir aber zu wenig dynamisch. Jetzt habe ich das über eine HashMap/TreeMap gelöst:
Java:
import java.io*;
import java.text.*;
import java.util.*;

public class Triangle {

    public static void main(String[] args) {
        Map<String, Double> triangle = new HashMap<>();

        String filename = "triangle.csv";
        File file = new File(filename);
        try {
            FileReader fileReader = new FileReader(file);
            BufferedReader bufferedReader = new BufferedReader(fileReader);

            String line;
            int index = 1;
            int year= 1;
            while ((line = bufferedReader.readLine()) != null) {
                String[] items = line.split("\\s*;\\s*");
                for (String string : items) {
                    triangle.put(year+ "-" + index, Double.parseDouble(string));
                    index += 1;
                }
                year += 1;
                index = 1;
            }
            bufferedReader.close();
        } catch (IOException e) {
            e.printStackTrace();
        }

        // format output
        DecimalFormat format = new DecimalFormat("#,##0.00");

        Map<String, Double> treeMap = new TreeMap<String, Double>(triangle);
        Set<Entry<String, Double>> set = treeMap.entrySet();
        Iterator<Entry<String, Double>> iterator = set.iterator();
        while (iterator.hasNext()) {
            Map.Entry<String, Double> entry = (Map.Entry<String, Double>) iterator.next();
            String key = entry.getKey();
            Double val = entry.getValue();
            System.out.printf("%-" + 10 + "." + 10 + "s %12s%n", key, format.format(val));
        }
    }
}
Allerdings wird bei der Ausgabe nicht richtig sortiert. So steht in der Ausgabe folgendes:
Code:
1-1       1
1-10      10
1-2       2
...
Der von mir zusammengesetzte Schlüssel repräsentiert also Zeile/Spalte. Wie erhalte ich die korrekte Reihenfolge, also
Code:
1-1       1
1-2       2
1-3       3
...
Bin auch für andere Lösungsvorschlage als Map/HashMap/TreeMap dankbar. Es sollte also Matrix-Repräsentation sein.
 
Was genau willst du denn überhaupt tun?
Du bist von "ich habe hier die Datei" zu "ich habe das versucht so und so zu lösen" gesprungen, ohne dabei den Teil dazwischen zu benennen: Was genau willst du mit der Datei denn machen? Was ist denn das Ziel?
Für jemanden wie uns, die das eigentlich zu lösende Problem bzw. die Anforderung nicht kennen, ist es schwer, nur anhand der Datei nachzuvollziehen, was du eigentlich machen willst.
 
Ich möchte die Daten der Datei als Matrix speichern (10x10 oder 12x12 oder wie groß die Daten in der Datei auch immer sind) und dann mit den Daten Berechnungen anstellen. So möchte ich z. B. die Summe der zweiten Spalten der Matrix durch die Summe der ersten Spalte dividieren, die Summe der dritten Spalte durch die Summe der zweiten Spalte usw.
 
Also erst einmal zu dem Punkt der Sortierung:
TreeMap nutzt die natürliche Reihenfolge so kein Comparator mit angegeben wurde. Und bei Strings ist 1.1* vor 1.2.
Da die Reihenfolge der entspricht, in der Du Werte einfügst, wäre ggf. die LinkedHashMap etwas, das Du nutzen willst.

Die Speicherung mit Strings als Key ist aber dann auch schlecht. Da macht es evtl. mehr Sinn, einen eigenen Datentyp zu erstellen mit gewünschter Sortierung und so.

Ich wollte das erst über Array lösen, die sind mir aber zu wenig dynamisch.
Was ist Dir denn da zu wenig dynamisch?

Generell solltest Du aber auf jeden Fall einen eigenen Datentyp haben, der das dann kapselt.

Ich möchte die Daten der Datei als Matrix speichern (10x10 oder 12x12 oder wie groß die Daten in der Datei auch immer sind) und dann mit den Daten Berechnungen anstellen. So möchte ich z. B. die Summe der zweiten Spalten der Matrix durch die Summe der ersten Spalte dividieren, die Summe der dritten Spalte durch die Summe der zweiten Spalte usw.
Wenn das die Anforderung ist, dann hast Du doch gar kein Bedarf an einer dynamischen Änderung.
 
Wenn es die Dreieckform hat mit immer 1 Element weniger pro Zeile, dann weisst Du nach dem Lesen der Zeile die Größe. Du siehst ja an den Beispielen: Die Anzahl der Zeilen ist gleich der Anzahl der Spalten.

Aber evtl. ist das eine Regel, die nicht gilt? Dann wäre die List aus meiner Sicht das, was das Array meistens ersetzt. Hat dann auch den Vorteil, dass man mit Streams vieles vereinfachen kann.

Das Einlesen einer Datei und dann die Verarbeitung wird dann relativ einfach:
Java:
    public List<List<Double>> parseFile(final String fileName) throws IOException {
        return Files.lines(Paths.get(fileName))
                .map(line -> parseLine(line))
                .collect(Collectors.toList());
    }

parseLine ist dann ebenso etwas wie:
Java:
    public static List<Double> parseLine(final String line) {
        return Arrays.stream(line.split("\\s*;\\s*"))
                .map(Double::parseDouble)
                .collect(Collectors.toList());
    }

Wobei hier dann natürlich auch das Thema Boxing / Unboxing zu erwähnen ist und @Robert Zenz uns dazu bestimmt noch einen Link geben wird (Den muss ich mir dann mal einspeichern für die Zukunft)

Das wäre dann eine Idee.

Dabei ist aber noch wichtig: So Typen wie List<List<Double>> sind nicht schön. Das gehört zumindest gekapselt. Und man sollte überlegen, ob man da nicht evtl. eigene Klassen einführen sollte. MatrixRow z.B.
Da würde dann auch die parse Methode rein passen und man hätte dann nur noch etwas wie List<MatrixRow> als Typ in der Klasse Matrix ...
Aber passt Matrix? Denn Matrizen sind ja doch nxm groß ...

Aber das sind dann Überlegungen, die abseits der genannten technischen Probleme sind und auf das Design eingehen.
 
Wobei hier dann natürlich auch das Thema Boxing / Unboxing zu erwähnen ist und @Robert Zenz uns dazu bestimmt noch einen Link geben wird (Den muss ich mir dann mal einspeichern für die Zukunft)
Das Geheimnis ist, einmal d'rauf geklickt zu haben damit man den aus der Browser-Geschichte wieder kopieren kann.

Diese Datei kann mal mehr mal weniger Zeilen/Spalten haben. Ich wollte das erst über Array lösen, die sind mir aber zu wenig dynamisch.
Das ist doch ueberhaupt kein Problem mit etwas Fantasie. Etwas Pseudo-Code dazu:

Java:
double[][] data = new double[0][];

int currentDataIndex = 0;

for (String line : lines) {
    double[] lineData = splitToArray(line);
    
    if (currentDataIndex >= data.length) {
        data = increaseDataSize(data);
    }
    
    data[currentDataIndex] = data;
    
    currentDataIndex++;
}

Damit erhaeltst du eine 2D-Array (Matrix) welche genau deine Daten abbildet. Die einzelnen Zeilen koennen sogar unterschiedlich grosz sein. Betreten kannst du die Daten dann ganz einfach:

Java:
data[3][2] + data[3][3];

Operationen auf Bloecken davon sind dann einfach nur for Schleifen.
 
Java:
package ???;

import java.util.Arrays;

/**
 *
 */
public class IntArrayList
implements IntIterable //, Cloneable
{
    public static final int INITIAL_SIZE = 8;

    public static final int INCREASING_SIZE = 8;

    private int[] intArr;

    private int size;

    public IntArrayList()
    {
        this.intArr = new int[ INITIAL_SIZE ];
    }

    public IntArrayList(
            final int initialSize )
    {
        this.intArr = new int[ initialSize ];
    }

    public void clear()
    {
        this.size = 0;
    }

    
    public void add(
            final int valueToAdd )
    {
        if ( size >= intArr.length )
        {
            increaseInnerArr();
        }

        this.intArr[ this.size++ ] = valueToAdd;
    }

    private void increaseInnerArr()
    {
        // TODO use Arrays#copyOf
        final int[] newIntArr = new int[ this.intArr.length + INCREASING_SIZE ];

        System.arraycopy(
                //src
                this.intArr ,
                //srcPos
                0 ,
                //dest
                newIntArr ,
                //destPos
                0 ,
                //length
                this.intArr.length );

        this.intArr = newIntArr;
    }

    public void addAll(
            final int[] valueToAddArr )
    {
        for ( final int valueToAdd : valueToAddArr)
        {
            this.add( valueToAdd );
        }
    }

    public int size()
    {
        return this.size;
    }

    public void setSize(
            final int sizeToSet )
    {
        this.size = sizeToSet;
    }

    public int get(
            final int index )
    {
        if ( index >= this.size )
        {
            throw new IndexOutOfBoundsException( index );
        }

        return this.intArr[ index ];
    }

    public boolean contains(
            final int valueToCheck )
    {
        for ( int i = 0 ; i < this.size ; ++i )
        {
            if ( this.intArr[ i ] == valueToCheck )
            {
                return true;
            }
        }
        return false;
    }

    public boolean containsAll(
            final IntArrayList listToCheck )
    {
        for ( int i = 0 ; i < listToCheck.size ; ++i )
        {
            if ( ! this.contains( listToCheck.intArr[ i ] ) )
            {
                return false;
            }
        }

        return true;
    }

    public int[] toArray()
    {
        // TODO use Arrays#copyOf
        final int[] resultIntArr = new int[ this.size ];

        System.arraycopy(
                //src
                this.intArr ,
                //srcPos
                0 ,
                //dest
                resultIntArr ,
                //destPos
                0 ,
                //length
                this.size );

        return resultIntArr;
    }

    //@Override
    //public IntArrayList clone() throws CloneNotSupportedException
    public IntArrayList createClone()
    {
        //return super.clone();
        final IntArrayList clone = new IntArrayList();

        clone.intArr = this.intArr.clone();

        clone.size = this.size;

        return clone;
    }

    @Override
    public IntIterator iterator()
    {
        return new IntIterator()
        {
            private int index;

            @Override
            public boolean hasNext()
            {
                return this.index < IntArrayList.this.size;
            }

            @Override
            public int next()
            {
                return IntArrayList.this.intArr[ this.index++ ];
            }
        };
    }

    @Override
    public String toString()
    {
        return Arrays.toString( Arrays.copyOf( this.intArr , size ) );
    }

}
 
Java:
package ???

/**
 *
 */
public interface IntIterator
{
    public boolean hasNext();

    public int next();
}
 
Bei meiner History findet man nichts mehr 🙂 Aber ich habe in der Favoritenleiste ein Ordner nur für Foren und da dann ein Unterordner mit wichtigen Links und so ... Da ist das dann mit drin 🙂
🙂

Wollte ich nicht mal ein Skript machen um solche Sachen direkt einfuegen zu koennen in den Beitrag? Und ich muss das ohnehin auch noch ausbauen um Gleitkommazahlen und Threading. Sind auch Themen die hier im Forum relativ oft vorkommen.
 
Ich habe eine Frage zu einer Dreiecksform. Ich habe in einer Datei Zahlen in Dreiecksform stehen, z. B.
Code:
1; 2; 3; 4; 5; 6; 7; 8; 9; 10;
11; 12; 13; 14; 15; 16; 17; 18; 19; ;
20; 21; 22; 23; 24; 25; 26; 27; ; ;
28; 29; 30; 31; 32; 33; 34; ; ; ;
35; 36; 37; 38; 39; 40; ; ; ; ;
41; 42; 43; 44; 45; ; ; ; ; ;
46; 47; 48; 49; ; ; ; ; ; ;
50; 51; 52; ; ; ; ; ; ; ;
53; 54; ; ; ; ; ; ; ; ;
55; ; ; ; ; ; ; ; ; ;
Diese Datei kann mal mehr mal weniger Zeilen/Spalten haben. Ich wollte das erst über Array lösen, die sind mir aber zu wenig dynamisch. Jetzt habe ich das über eine HashMap/TreeMap gelöst:
Falls deine Daten immer so aufgebaut sind muss man da gar nichts speichern das lässt sich berechnen.

Java:
public static int getTriangleValue(int lineSize, int x, int y) {
        if (x < 0 || (x - 1 > lineSize - y) || y < 0 || y > lineSize)
            throw new IndexOutOfBoundsException("(" + x + "," + y + ")");
        return (lineSize * (y - 1)) - ((y - 1) * (y - 2)) / 2 + x;
    }
 

Zurück
Oben