Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > de.comp.lang.java > #13147 > unrolled thread

Element in TreeMap wird nicht gefunden

Started by"Christian H. Kuhn" <qno-news@qno.de>
First post2017-12-31 11:21 +0100
Last post2017-12-31 19:57 +0100
Articles 10 — 2 participants

Back to article view | Back to de.comp.lang.java


Contents

  Element in TreeMap wird nicht gefunden "Christian H. Kuhn" <qno-news@qno.de> - 2017-12-31 11:21 +0100
    Re: Element in TreeMap wird nicht gefunden Michael Paap <michael.paap@studium.fernuni-hagen.de> - 2017-12-31 13:40 +0100
      Re: Element in TreeMap wird nicht gefunden Michael Paap <michael.paap@studium.fernuni-hagen.de> - 2017-12-31 13:51 +0100
        Re: Element in TreeMap wird nicht gefunden Michael Paap <michael.paap@studium.fernuni-hagen.de> - 2017-12-31 13:55 +0100
          Re: Element in TreeMap wird nicht gefunden "Christian H. Kuhn" <qno-news@qno.de> - 2017-12-31 16:42 +0100
            Re: Element in TreeMap wird nicht gefunden Michael Paap <michael.paap@studium.fernuni-hagen.de> - 2017-12-31 19:54 +0100
              Re: Element in TreeMap wird nicht gefunden "Christian H. Kuhn" <qno-news@qno.de> - 2018-01-01 13:25 +0100
                Re: Element in TreeMap wird nicht gefunden Michael Paap <michael.paap@studium.fernuni-hagen.de> - 2018-01-01 14:31 +0100
      Re: Element in TreeMap wird nicht gefunden "Christian H. Kuhn" <qno-news@qno.de> - 2017-12-31 16:54 +0100
        Re: Element in TreeMap wird nicht gefunden Michael Paap <michael.paap@studium.fernuni-hagen.de> - 2017-12-31 19:57 +0100

#13147 — Element in TreeMap wird nicht gefunden

From"Christian H. Kuhn" <qno-news@qno.de>
Date2017-12-31 11:21 +0100
SubjectElement in TreeMap wird nicht gefunden
Message-ID<fars12Fubj6U1@mid.individual.net>
Hallo Gemeinde,

Mal wieder ein Problem, das auf einer „ganz einfachen“ Ausgangsfrage
beruht. Mein Bruder fragte mich: „Auf welchem Wege baue ich im
Browser-Spiel Travian in einem Getreidedorf alle Felder am schnellsten
auf Level n aus?“

Vereinfachende Annahmen: Die Zeit für den Ausbau selbst wird mit 0
angenommen („Goldclub“). Es gibt keine Lieferungen von außen. Es wird
nur der Rohstoff Getreide betrachtet. Sollten andere Rohstoffe benötigt
werden, werden sie aus Getreide im Verhältnis 1:1 „umgegoldet“ und
verschwinden so aus dem Modell. Andere Gebäude werden zur Zeit nicht
betrachtet (in eine spätere Erweiterung des Modells werden auch Mühle
und Bäckerei aufgenommen, die die Produktivität steigern). Die
Speicherkapazität wird mit unendlich angenommen (in eine spätere
Erweiterung des Modells werden auch Speicherbauten aufgenommen). Es
werden weder Truppen noch Angriffe betrachtet; das produzierte Getreide
wird ausschließlich durch Ausbau verbraucht.

Modellierung: Ein Knoten repräsentiert einen Zustand. Es gibt 15 Felder,
die die Level 0 bis n annehmen können. Die Felder sind beliebig
austauschbar. Der Zustand wird also durch ein int[n+1] dargestellt, bei
dem als Randbedingung die Summe der Einträge 15 sein muss. Eine Kante
repräsentiert einen Bauschritt. Ein Bauschritt erhöht genau ein Feld um
genau einen Level. Die Zeit für den Bauschritt entspricht im Modell nur
der Produktionszeit des benötigten Getreides, t = getreide /
produktivität. Mit dem Bauschritt erhöht sich die Produktivität des Dorfes.

In einem ersten Ansatz beinhaltete der Zustand auch die für alle zu
diesem Zustand führenden Bauschritte benötigte Zeit. Die Zahl der Knoten
nahm dadurch derart zu, dass die Warteschlange bei einer Breitensuche
bereits bei n=2 nicht mehr genügend Speicher fand. Eine Tiefensuche für
n=2 war in wenigen Sekunden abgeschlossen, n=3 dauerte mehrere Tage, der
angestrebte Wert n=17 war nicht zu erreichen.

Nach mehreren nicht zielführenden Versuchen erinnerte ich mich dann an
den Algorithmus von Dijkstra. Die Knoten erhalten noch den Abstand und
den Vorgänger als Felder. Zwei Knoten gelten als gleich, wenn die
enthaltenen int[] die gleichen Werte enthalten und n gleich ist.

Ich erzeuge zuerst ein TreeSet mit den möglichen Zuständen. Daher habe
ich für die Knoten equals() und compareTo() implementiert. Die Zustände
werden alle mit Abstand unendlich (ok, Double.MAX_VALUE) initialisiert.
Der Startzustand wird gelöscht und mit Abstand 0 wieder eingefügt.

Theoretisch. Praktisch wird er es nicht, obwohl ich ihn im TreeSet sehe.
Irgendwas habe ich falsch gemacht, und ich finde den Fehler nicht. Sieht
jemand mehr?

lg
QNo

Die Quellen sind auf
http://www.qno.de/gitweb/?p=qtraviancornoptimator.git;a=snapshot;h=d1393662bb73951ec59684008e9baa138522bd26;sf=tgz
oder zum direkten Lesen hier:

package de.qno.travian;

import java.util.Set;
import java.util.TreeSet;

/**
 * Performs the Dijkstra Algorithmus onto a graph of Travian Positions
to find the shortest build.
 *
 * @author QNo
 *
 */
public class QTravianDijkstra {

    private final int maxCropLevel;

    private int[] cropFieldsPerLevel;

    private Set<QTravianLightCropTown> visited;
    private TreeSet<QTravianLightCropTown> notVisited;

    /**
     * Private Constructor to avoid instantiation
     */
    public QTravianDijkstra(final int _maxCropLevel) {
        maxCropLevel = _maxCropLevel;
        visited = new TreeSet<QTravianLightCropTown>();
        notVisited = new TreeSet<QTravianLightCropTown>();
        cropFieldsPerLevel = new int[maxCropLevel + 1];
        createNextLevel(0, 0);
    }

    private void createNextLevel(final int _level, final int
_alreadyBuilt) {
        int stillToBuild = 15 - _alreadyBuilt;
        if (maxCropLevel == _level) {
            cropFieldsPerLevel[_level] = stillToBuild;
            notVisited.add(new QTravianLightCropTown(maxCropLevel,
cropFieldsPerLevel));
        } else {
            for (int i = stillToBuild; i >= 0; i--) {
                cropFieldsPerLevel[_level] = i;
                createNextLevel(_level + 1, _alreadyBuilt + i);
            }
        }
    }

    private void dijkstra(final QTravianLightCropTown _targetTown) {

    }

    public static void main(String[] args) {

        QTravianDijkstra test = new QTravianDijkstra(1);

        final QTravianLightCropTown startTown = new
QTravianLightCropTown(test.maxCropLevel);
        startTown.setStartTown();
        System.out.println(test.notVisited.contains(startTown));
        test.notVisited.remove(startTown);
        test.notVisited.add(startTown);
        int[] targetArray = new int[test.maxCropLevel + 1];
        targetArray[test.maxCropLevel] = 15;
        final QTravianLightCropTown targetTown = new
QTravianLightCropTown(test.maxCropLevel, targetArray);

        test.dijkstra(targetTown);

    } // main

} // class

=========================================================================================

package de.qno.travian;

import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;

/**
 * This class represents a village with 15 crop fields and only 1 field
of every other resource. ATM, there are no other fields or buildings
 * supported, but that might change.
 *
 * <p>
 * This implementation knows about the number of crop fields per level
and about the build moves that constructed the actual status of village.
 * </p>
 *
 * <p>
 * This implementation is not thred-safe. In normal use, thread safety
might be achievable if calls of build...(), townProductivity(),
 * isMaxDeveloped(), setAge(), getAge(), and getAllowedBuildMoves() are
synchronized by the client. Using evaluate(boolean) is thread-hostile,
because
 * it stores it’s results in static variables.
 * </p>
 *
 * @author QNo
 *
 */
public final class QTravianLightCropTown implements
Comparable<QTravianLightCropTown> {

    private static final int[] PRODUCTIVITY = { 4, 7, 13, 21, 31, 46,
70, 98, 140, 203, 280, 392, 525, 693, 889, 1120, 1400, 1820, 2240, 2800,
3430 };

    private static boolean goldClub = true;
    private static boolean hero = true;

    private transient int maxCropLevel;

    private transient int[] cropFieldsPerLevel;

    private QTravianLightCropTown predecessor;
    private double distance = Double.MAX_VALUE;

    /**
     * Public Standard Constructor. Provides a new undeveloped town.
     */
    public QTravianLightCropTown() {
        this(20);
    }

    /**
     * Public Constructor with maxCropLevel. Provides a new undeveloped
town.
     *
     * @param _maxCropLevel
     *            Level which Crop Fields are maximally developed to.
     */
    public QTravianLightCropTown(final int _maxCropLevel) {
        maxCropLevel = _maxCropLevel;

        cropFieldsPerLevel = new int[maxCropLevel + 1];
        cropFieldsPerLevel[0] = 15;
        for (int i = 1; i <= maxCropLevel; i++) {
            cropFieldsPerLevel[i] = 0;
        }

        distance = Double.MAX_VALUE;
    }

    /**
     * Public Constructor with development. Provides a developed town.
     *
     * @param _maxCropLevel
     *            Level which Crop Fields are maximally developed to.
     * @param _cropFieldsPerLevel
     *            Development status: how many fields per level.
     */
    @SuppressWarnings("PMD.UseVarargs") // Stupid proposition
    public QTravianLightCropTown(final int _maxCropLevel, final int[]
_cropFieldsPerLevel) {
        this(_maxCropLevel);

        cropFieldsPerLevel = _cropFieldsPerLevel.clone();
    }

    /**
     * Copy constructor.
     *
     * @param _original
     *            the village to copy
     */
    public QTravianLightCropTown(final QTravianLightCropTown _original) {
        this(_original.maxCropLevel);
        cropFieldsPerLevel = _original.cropFieldsPerLevel.clone();
    }

    /**
     * Calculates crop productivity of a village.
     *
     * <p>
     * This implementation uses a table of crop productivity by crop
field level and some modificators (atm goldclub only). It is given in
crop per
     * hour.
     * </p>
     *
     * @return crop productivity of this village.
     */
    private double townProductivity() {
        int actualProductivity = 0;

        for (int i = 0; i <= maxCropLevel; i++) {
            actualProductivity += cropFieldsPerLevel[i] * PRODUCTIVITY[i];
        }
        return (goldClub ? actualProductivity * 1.25 :
actualProductivity) + (hero ? 360 : 0);
    }

    /**
     * Tests if all crop fields are developed up to maxCropLevel.
     *
     * @return true, if all crop fields are developed up to
maxCropLevel; false otherwise
     */
    private boolean isMaxDeveloped() {
        return cropFieldsPerLevel[maxCropLevel] == 15;
    }

    /**
     * Gets a list of all allowed update or build actions.
     *
     * @return a list of all allowed update or build actions
     */
    private List<QTravianBuildMoves> getAllowedBuildMoves() {
        final List<QTravianBuildMoves> allowedMoves = new
LinkedList<QTravianBuildMoves>();

        for (int i = 0; i < maxCropLevel; i++) {
            if (0 != cropFieldsPerLevel[i]) {
                allowedMoves.add(QTravianBuildMoveCrop.getInstance(i));
            }
        }

        return allowedMoves;
    }

    /**
     * Executes a List of QTravianBuildMoves on this village. Build
moves are executed in the order of the list iterator.
     *
     * @param _moves
     *            a list of build moves
     */
    public void buildTown(final List<QTravianBuildMoves> _moves) {
        for (final QTravianBuildMoves move : _moves) {
            if (move instanceof QTravianBuildMoveCrop) {
                buildCropField(((QTravianBuildMoveCrop)
move).getFromLevel());
            }
        }
    }

    /**
     * Upgrades a crop field from _fromLevel by one level.
     *
     * @throws IllegalArgumentException
     *             if _fromLevel is not an int from 0 to 19.
     * @param _fromLevel
     *            the level of the crop field before updating. An int
from 0 to 19.
     */
    private void buildCropField(final int _fromLevel) {
        if (0 > _fromLevel || maxCropLevel < _fromLevel) {
            throw new IllegalArgumentException("Only Crop Builds allowed
between level 0 and " + maxCropLevel + ".");
        }
        cropFieldsPerLevel[_fromLevel]--;
        cropFieldsPerLevel[_fromLevel + 1]++;
    }

    /**
     * Getter for Distance.
     *
     * @return the distance
     */
    public double getDistance() {
        return distance;
    }

    /**
     * Setter for distance.
     *
     * @param _distance
     *            the distance to set
     */
    public void setDistance(final double _distance) {
        this.distance = _distance;
    }

    /**
     * Getter for predecessor.
     *
     * @return the predecessor
     */
    public QTravianLightCropTown getPredecessor() {
        return predecessor;
    }

    /**
     * Setter for predecessor.
     *
     * @param _predecessor
     *            the predecessor to set
     */
    public void setPredecessor(final QTravianLightCropTown _predecessor) {
        this.predecessor = _predecessor;
    }

    /**
     * Sets distance = 0, marking this town as start town for dijkstra
algorithm.
     */
    public void setStartTown() {
        distance = 0;
    }

    /**
     * Returns a brief description of this Town. The exact details of
the representation are unspecified and subject to change.
     *
     * @return a brief description
     */
    @Override
    public String toString() {
        final StringBuilder returnString = new StringBuilder(600);
        returnString.append("This town:\n   15 Corn Fields:\n");
        for (int i = 0; i <= maxCropLevel; i++) {
            if (cropFieldsPerLevel[i] > 0) {
                returnString.append("   " + cropFieldsPerLevel[i] + " of
level " + i + "\n");
            }
        }
        returnString.append("The Town needs " +
QTravianCropTown.formatToTimeDiff(distance) + " from Start Town.");
        return returnString.toString();
    }

    /*
     * (non-Javadoc)
     *
     * @see java.lang.Object#hashCode()
     */
    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + Arrays.hashCode(cropFieldsPerLevel);
        return result;
    }

    /*
     * (non-Javadoc)
     *
     * @see java.lang.Object#equals(java.lang.Object)
     */
    @Override
    public boolean equals(final Object _obj) {
        boolean equals = true;

        if (_obj == null) {
            equals = false;
        } else {
            if (_obj instanceof QTravianLightCropTown) {
                final QTravianLightCropTown other =
(QTravianLightCropTown) _obj;
                if (!Arrays.equals(cropFieldsPerLevel,
other.cropFieldsPerLevel) || maxCropLevel != other.maxCropLevel) {
                    equals = false;
                }
            } else {
                equals = false;
            }
        }
        return equals;
    }

    @Override
    @SuppressWarnings("PMD.AvoidThrowingNullPointerException")
    public int compareTo(final QTravianLightCropTown _obj) {
        if (null == _obj) {
            throw new NullPointerException();
        }
        int returnValue = -1;
        if (this.equals(_obj)) {
            returnValue = 0;
        } else {
            if (distance < _obj.distance) {
                returnValue = -1;
            } else if (distance > _obj.distance) {
                returnValue = 1;
            } else {
                for (int i = maxCropLevel; i < 0; i--) {
                    if (cropFieldsPerLevel[i] <
_obj.cropFieldsPerLevel[i]) {
                        returnValue = -1;
                        break;
                    } else if (cropFieldsPerLevel[i] >
_obj.cropFieldsPerLevel[i]) {
                        returnValue = 1;
                        break;
                    }
                }
            }
        }
        return returnValue;

    }

    public static void main(String... _args) {
        final QTravianLightCropTown townOne = new QTravianLightCropTown(3);
        QTravianLightCropTown townTwo = new QTravianLightCropTown(3);
        System.out.println(townOne.equals(townTwo));
        townOne.buildCropField(0);
        System.out.println(townOne.equals(townTwo));
        System.out.println(townOne.compareTo(townTwo));
        int[] arrayTwo = { 14, 1, 0, 0 };
        townTwo = new QTravianLightCropTown(3, arrayTwo);
        System.out.println(townOne.equals(townTwo));
    }
}

[toc] | [next] | [standalone]


#13148

FromMichael Paap <michael.paap@studium.fernuni-hagen.de>
Date2017-12-31 13:40 +0100
Message-ID<p2alr9$94p$1@news-cypress.fernuni-hagen.de>
In reply to#13147
Am 31.12.2017 um 11:21 schrieb Christian H. Kuhn:

> Hallo Gemeinde,

Naja. Hallo.

> Mal wieder ein Problem, das auf einer „ganz einfachen“ Ausgangsfrage
> beruht. Mein Bruder fragte mich: „Auf welchem Wege baue ich im
> Browser-Spiel Travian in einem Getreidedorf alle Felder am schnellsten
> auf Level n aus?“

Genereller Hinweis:

Reduziere dein Problem auf ein minimales Beispiel. Gerade, wenn es ich
um so etwas Triviales handelt, wie das, was der Betreff andeutet, wird
kein Mensch Lust haben, sich mit dem ganzen Kontext zu beschäftigen, der
nichts zur Sache tut.

Dasselbe gilt für Beispielcode. Bau etwas Minimales, Compilierbares und
Ausführbares, was dein Problem demonstriert und lass alles weg, was
nichts zur Sache tut.

[Lauter vermutlich irrelevantes Zeug entfernt]

> Ich erzeuge zuerst ein TreeSet mit den möglichen Zuständen. Daher habe
> ich für die Knoten equals() und compareTo() implementiert. Die Zustände
> werden alle mit Abstand unendlich (ok, Double.MAX_VALUE) initialisiert.
> Der Startzustand wird gelöscht und mit Abstand 0 wieder eingefügt.
> 
> Theoretisch. Praktisch wird er es nicht, obwohl ich ihn im TreeSet sehe.
> Irgendwas habe ich falsch gemacht, und ich finde den Fehler nicht. Sieht
> jemand mehr?

[Hunderte Zeilen Code entfernt]

Das wird sich vermutlich kein Mensch für lau und freiwillig näher
ansehen. Aber meine Glaskugel sagt:

Das Problem hat irgendas mit TreeSet und Map zu tun und es werden
Elemente in der Map nicht gefunden. Ursache: Maps arbeiten nicht mit
equals() sondern mit hashCode(). Überschreibe die Methode hashCode() so,
dass sie analog zu equals() arbeitet und es funktioniert.

Lesestoff:
http://www.xyzws.com/javafaq/why-always-override-hashcode-if-overriding-equals/20
https://docs.oracle.com/javase/8/docs/api/java/lang/Object.html#hashCode--
https://docs.oracle.com/javase/8/docs/api/java/lang/Object.html#equals-java.lang.Object-

Gruß,
Michael

[toc] | [prev] | [next] | [standalone]


#13149

FromMichael Paap <michael.paap@studium.fernuni-hagen.de>
Date2017-12-31 13:51 +0100
Message-ID<p2amh4$rku$1@news-cypress.fernuni-hagen.de>
In reply to#13148
Am 31.12.2017 um 13:40 schrieb Michael Paap:

> Das Problem hat irgendas mit TreeSet und Map zu tun und es werden
> Elemente in der Map nicht gefunden. Ursache: Maps arbeiten

... teilweise

> nicht mit
> equals() sondern mit hashCode(). Überschreibe die Methode hashCode() so,
> dass sie analog zu equals() arbeitet und es funktioniert.
> 
> Lesestoff:
> http://www.xyzws.com/javafaq/why-always-override-hashcode-if-overriding-equals/20
> https://docs.oracle.com/javase/8/docs/api/java/lang/Object.html#hashCode--
> https://docs.oracle.com/javase/8/docs/api/java/lang/Object.html#equals-java.lang.Object-

Nachtrag: Falls Hashing in deinem Kontext keine Rolle spielen sollte,
wäre eine denkbare Ursache, dass du die in deiner Collection vorhandenen
Elemente veränderst und zwar dergestalt, dass der veränderte Key nicht
mehr "gleich" dem alten Key ist.

Gruß,
Michael Paap

[toc] | [prev] | [next] | [standalone]


#13150

FromMichael Paap <michael.paap@studium.fernuni-hagen.de>
Date2017-12-31 13:55 +0100
Message-ID<p2amoj$11ej$1@news-cypress.fernuni-hagen.de>
In reply to#13149
Am 31.12.2017 um 13:51 schrieb Michael Paap:

> Nachtrag: Falls Hashing in deinem Kontext keine Rolle spielen sollte,
> wäre eine denkbare Ursache, dass du die in deiner Collection vorhandenen
> Elemente veränderst und zwar dergestalt, dass der veränderte Key nicht
> mehr "gleich" dem alten Key ist.

Zitat aus der Doku zu java.util.Map:

Note: great care must be exercised if mutable objects are used as map
keys. The behavior of a map is not specified if the value of an object
is changed in a manner that affects equals comparisons while the object
is a key in the map.

Gruß,
Michael

[toc] | [prev] | [next] | [standalone]


#13151

From"Christian H. Kuhn" <qno-news@qno.de>
Date2017-12-31 16:42 +0100
Message-ID<faserkF454gU1@mid.individual.net>
In reply to#13150
Am 31.12.2017 um 13:55 schrieb Michael Paap:
> Note: great care must be exercised if mutable objects are used as map
> keys. The behavior of a map is not specified if the value of an object
> is changed in a manner that affects equals comparisons while the object
> is a key in the map.

Dafür ein Extradank :-) Steht so auch für Set in der API Doc. Ich hätte
es überlesen, und beim nächsten Schritt hätte ich genau den Fehler
gemacht: Knoten gesucht, verändert, TreeSet.first() aufgerufen und
falsche Ergebnisse bekommen. Jetzt weiß ich: Knoten suchen, aus Set
löschen, verändern, neu in Set reinschreiben.

Du kannst mir nicht zufällig von noch ein paar Stellen vorher sagen,
dass ich erstmal reinfalle? :-D

lg
QNo

[toc] | [prev] | [next] | [standalone]


#13153

FromMichael Paap <michael.paap@studium.fernuni-hagen.de>
Date2017-12-31 19:54 +0100
Message-ID<p2bbpp$l7o$1@news-cypress.fernuni-hagen.de>
In reply to#13151
Am 31.12.2017 um 16:42 schrieb Christian H. Kuhn:

> Du kannst mir nicht zufällig von noch ein paar Stellen vorher sagen,
> dass ich erstmal reinfalle? :-D

Sorry, nee. Die Ideen mit hashCode() und mit veränderlichen Objekten
eben ur waren Schnellschüsse bzgl. der zwei typischen Standardfehler
beim Hantieren mit Maps.

In welches Loch du als nächstes reinfällst, weiß meine Kristallkugel
nicht. ;-)

Aber einen Tipp habe ich noch. Der verhindert nicht, dass du in die
nächste Falle tappst, aber er macht es leichter, wieder rauszukommen,
egal ob mit oder ohne Hilfe:

"Forsche nicht am Patienten, sondern im Reagenzglas".

Ausführlicher: Wenn du dich mit für dich neuem Zeug beschäftigst, also
quasi "Forschung" betreibst, dann mach das nicht an deinem eigentlichen
Projekt, sondern erst mal in einer Testumgebung, bis du verstanden hast,
was du machst. Am besten völlig abstrakt ohne Verwendung von Begriffen
aus deiner Probemdomäne.

Schrittweise vortasten. Test schreiben. Wenn dann irgendwas schief geht
und du nicht alleine rauskriegst, was, dann muss sich ein potentiell
Hilfswilliger nicht mit deinem eigentlichen Thema beschäftigen (von dem
er vielleicht nicht die mindeste Ahnung hat), sondern kann sich
vergleichsweise simplen Code anschauen, der ein abstraktes Thema
bearbeitet, das ihm vielleicht bekannt ist.

Und es gibt nun mal mit Sicherheit viel mehr Leute, die mit Maps schon
auf die Schnauze gefallen sind und draus gelernt haben, als Leute, die
wissen oder auch nur wissen wollen, was zur Hölle das Browser-Spiel
Travian ist. ;-)

Gruß,
Michael

[toc] | [prev] | [next] | [standalone]


#13155

From"Christian H. Kuhn" <qno-news@qno.de>
Date2018-01-01 13:25 +0100
Message-ID<faunlhFjq6vU1@mid.individual.net>
In reply to#13153
Am 31.12.2017 um 19:54 schrieb Michael Paap:
> "Forsche nicht am Patienten, sondern im Reagenzglas".

Eine Regel, die beim Problem des Ausgangspostings berechtigt war und
deren Beachtung zur Lösung geführt hat.

Allerdings erfasst man im Reagenzglas nicht unbedingt allen
Forschungsbedarf. Den erkennt man erst bei der Arbeit am Patienten. Und
bis man da den Fehler soweit eingegrenzt hat, dass man das einfache
Modell zur Untersuchung isolieren kann, hat man den Fehler schon gelöst.

Aktuelles Beispiel: Ab einem bestimmten Punkt wurden im
Dijkstra-Algorithmus Knoten nicht mehr aktualisiert. Ich habe einen
Knoten außerhalb der Menge der noch nicht besuchten Knoten errechnet,
die Distanz bestimmt und ggf. den Knoten in der Menge ausgewechselt.
Diese Menge wird durch eine TreeMap<E,E> repräsentiert. Und bei
bestimmten Knoten klappte das Auswechseln nicht, obwohl der neue und der
alte Knoten mit equals() und compareTo() gleich waren. ABER durch das
Ändern der Distanz änderte sich der Weg zum gesuchten Knoten in der
Menge, und da war die alte Version halt nicht. Denkfehler. Lösung: Alten
Knoten in Menge suchen, bevor Distanz geändert wird. War ein Problem,
das ich im Reagenzglas nicht mal vermutet hatte, weil es zufällig bei
den Testfällen nicht auftrat.

> Und es gibt nun mal mit Sicherheit viel mehr Leute, die mit Maps schon
> auf die Schnauze gefallen sind und draus gelernt haben, als Leute, die
> wissen oder auch nur wissen wollen, was zur Hölle das Browser-Spiel
> Travian ist. ;-)

Im Kontext dieser Gruppe sind alle Aussagen mit „viel mehr Leute“ a
priori falsch :-)

lg
QNo

[toc] | [prev] | [next] | [standalone]


#13156

FromMichael Paap <michael.paap@studium.fernuni-hagen.de>
Date2018-01-01 14:31 +0100
Message-ID<p2dd7v$1duu$1@news-cypress.fernuni-hagen.de>
In reply to#13155
Am 01.01.2018 um 13:25 schrieb Christian H. Kuhn:

> Allerdings erfasst man im Reagenzglas nicht unbedingt allen 
> Forschungsbedarf. Den erkennt man erst bei der Arbeit am Patienten.

Richtig, aber wenn man vorher im Reagenzglas hinreichend experimentiert
hat, kann man eine ganze Menge Ursachen dann schon mal ausschließen.

> Und bis man da den Fehler soweit eingegrenzt hat, dass man das
> einfache Modell zur Untersuchung isolieren kann, hat man den Fehler
> schon gelöst.

Das ist dann ja auch gut so. ;-)

> War ein Problem, das ich im Reagenzglas
> nicht mal vermutet hatte, weil es zufällig bei den Testfällen nicht
> auftrat.

Ok, die Wahl geeigneter Testfälle ist eine Kunst für sich.

>> Und es gibt nun mal mit Sicherheit viel mehr Leute, die mit Maps
>> schon auf die Schnauze gefallen sind und draus gelernt haben, als
>> Leute, die wissen oder auch nur wissen wollen, was zur Hölle das
>> Browser-Spiel Travian ist. ;-)
> 
> Im Kontext dieser Gruppe sind alle Aussagen mit „viel mehr Leute“ a 
> priori falsch :-)

Wie man's nimmt. Auf 100% aller Mitleser, die dir geantwortet haben,
trifft meine Aussage zu. ;-)

Gruß,
Michael

[toc] | [prev] | [next] | [standalone]


#13152

From"Christian H. Kuhn" <qno-news@qno.de>
Date2017-12-31 16:54 +0100
Message-ID<fasfi5F49k4U1@mid.individual.net>
In reply to#13148
Grmpf. Beitrag verloren gegangen, weil Internet sich verschluckt hat.
Also nochmal.

Am 31.12.2017 um 13:40 schrieb Michael Paap:
> Reduziere dein Problem auf ein minimales Beispiel.

Solange das Beispiel einfach ist, funktioniert es. Der Fehler tritt auf,
wenn es anfängt, komplex zu werden. Ich lerne: nicht nur von test driven
development reden, sondern machen, dann bleiben die Probleme einfach.

> Das Problem hat irgendas mit TreeSet und Map zu tun und es werden
> Elemente in der Map nicht gefunden. 
Ja.

> Ursache: Maps arbeiten nicht mit
> equals() sondern mit hashCode(). 

Das konnte ich nicht verifizieren. Die API Docs von Set und Map sprechen
eindeutig von equals(), solange die Implementierung nicht was anderes
macht; hashCode() wird nur als Beispiel erwähnt. Die benutzten
Implementierungen sind TreeSet (und damit TreeMap), die bleiben bei
equals() und benutzen außerdem noch Comparable.compareTo(), das
konsistent zu equals() implementiert werden muss. hashCode() wird nicht
benutzt. Eclipse erzeugt zu equals(), was ich verändert habe, auch
hashCode(), da habe ich einen Breakpoint gesetzt, der im Debugger nie
erreicht wird.

Der Fehler war ein < statt > in den Tiefen von compareTo(). Gefunden
habe ich ihn, nachdem ich mal Tests für equals() und compareTo()
geschrieben habe.

lg
QNo

[toc] | [prev] | [next] | [standalone]


#13154

FromMichael Paap <michael.paap@studium.fernuni-hagen.de>
Date2017-12-31 19:57 +0100
Message-ID<p2bbvh$qcc$1@news-cypress.fernuni-hagen.de>
In reply to#13152
Am 31.12.2017 um 16:54 schrieb Christian H. Kuhn:

>> Ursache: Maps arbeiten nicht mit
>> equals() sondern mit hashCode(). 
> 
> Das konnte ich nicht verifizieren.

Stimmt, da habe ich allgemeiner formuliert, als ich wollte, siehe mein
Nachtragsposting.

> Der Fehler war ein < statt > in den Tiefen von compareTo(). Gefunden
> habe ich ihn, nachdem ich mal Tests für equals() und compareTo()
> geschrieben habe.

Ok. Prachtbeispiel für meinen Hinweis im anderen Posting von wegen
Patient vs. Reagenzglas. ;-)

Gruß,
Michael

[toc] | [prev] | [standalone]


Back to top | Article view | de.comp.lang.java


csiph-web