Java Identifzierung eines Objektes innerhalb eines Array ohne Vergleich.

DefconDev

Commander
Registriert
Jan. 2008
Beiträge
2.601
Hallo zusammen,

ich bin gerade auf der Suche nach einer Möglichkeit, Objekte innerhalb eines Arrays zu identifizieren ohne Vergleich.

Ich erkläre euch ganz kurz was ich eigentlich umgehen möchte.


Ich habe eine Klasse namens Spieler, innerhalb dieser Klasse sind die "üblichen" Instanzattribute wie
String name;
int punkte;


Jetzt möchte ich ein paar Objekte dieser Klasse Spieler erstellen und in ein Spieler array[] speichern.

Anschließend möchte ich die Instanzattribute der jeweiligen Klasse individuell verändern.

Bisher habe ich das so gelöst.

Code:
[JAVA]
if(arraySpieler[i].name == "Theo")
{
//ändere Punkte von Spieler a;
}
else if(if(arraySpieler[i].name == "Jogi")
{
//ändere Punkte von Spieler b;
}
[/JAVA]

Also anhand des String name, den ich dem jeweiligen Objekt über den Konstruktor zu anfang vergeben habe.


Jetzt stellt sich mir aber die Frage ob es einen anderen Weg gibt ohne für jedes Objekt einen Vergleich aufzustellen. Es könnte der Fall auftreten dass ich 100 Objekte von der Klasse Spieler hätte, dann müsste ich 100 vergleiche aufschreiben.

Ich hoffe ihr konntet mir folgen.
 
Hades85 schrieb:
Jetzt stellt sich mir aber die Frage ob es einen anderen Weg gibt ohne für jedes Objekt einen Vergleich aufzustellen. Es könnte der Fall auftreten dass ich 100 Objekte von der Klasse Spieler hätte, dann müsste ich 100 vergleiche aufschreiben.

Wenn du für jedes Objekt einen eigenen Vergleich erstellen willst, dann hat das nichts mehr mit Objektorientierung zu tun.

Du musst, wie du es berits getan hast, eine Klasse mit den Klassenattributen anlegen. Daneben brauchst du dann noch zwingend einen Konstrukor, der eben bestimmt, was mit den Attributen geschieht. Und zu guter Letzt musst du dann halt noch eine Methode definieren, welche deine Anweisungen bezüglich des Arrays enthält.
 
Wenn Du unbedingt ein Array verwenden möchtest, dann schreibe Dir doch einfach eine Methode, die Dir die Indexposition eines bestimmten Spielers liefert.

Code:
int index = findIndexByName("Theo");
//ändere Punkte von Spieler a;
if (index > -1)
    arraySpieler[index].punkte = ...;
else
    ...
 
Du musst es variabel lösen:

Code:
public void aenderePunkte(String spielerName, int punkte) {
   for (int i: arraySpieler) {
      if (arraySpieler[i].name == spielerName) {
         (arraySpieler[i].punkte = punkte;
      }
   }
}
 
Zuletzt bearbeitet:
@The_Virus: Dein Beispiel klappt aber nicht, denn du übergibst keinen Index als Parameter an die Funktion.
Ich verstehe jedoch das genaue Problem nicht - möchtest du einfach nicht vergleichen? Irgendwie musst du das Objekt was du manipulieren möchtest identifizieren.
 
@SymA:
Habs korregiert. Hab nur die for-Schleife vergessen. Aber die war im Code-Beispiel oben auch nicht. ;)
 
Alternative ab Java 8:
Code:
        Player player1 = new Player("Player1");
        Player player2 = new Player("Player2");
        Player[] players = new Player[]{player1, player2};
        Player searchedPlayer = Stream.of(players).filter(p -> player1.name.equals("Player1")).findFirst().get();
        searchedPlayer.points++;
        System.out.println(searchedPlayer.name + " has " + searchedPlayer.points + " point(s)");

Ansonsten unterstütze ich DonnyDepps Vorschlag, da der händische Vergleich hier überflüssig scheint.
 
Zuletzt bearbeitet: (schöne neue J8-Welt)
Erst mal vielen Dank für die Vorschläge.

Ich werde mal Versuchen ein paar Ideen umzusetzen.

Ich glaube die Idee von Virus wird mir nicht weiterhelfen denn ich lese die Daten aus einer JList bzw aus einem DefaultListModel und es wäre ziemlich umständlich jedes mal die spielerNamen zu übergeben.


Das Problem welches ich eigentlich habe, ich lese gewisse Sachen während der Laufzeit aus einem .ods Dokument. Und die einzelnen Zellen anzusprechen geht nur über fixe Zahlen, jedenfalls habe ich noch keine Idee wie ich das umgehen kann.

Evtl eine eigene Klasse die die fixen Zahlen im Zusammenhang mit dem jeweiligen Spieler speichert.
 
Zuletzt bearbeitet:
Klingt für mich, als solltest du statt deiner Ods-Konstruktion eigentlich eine (in-memory) DB verwenden. Da ist der Datenzugriff dann wesentlich einfacher anhand welchem Spaltenwert auch immer.
 
Und was spricht nun gegen eine HashMap? Von Java hab ich keine Ahnung, aber dort kann man doch sicher einzelne Objekte über einen eindeutigen Identifier, der ein String sein kann, rausziehen?
 
voodoo44 schrieb:
Und was spricht nun gegen eine HashMap? Von Java hab ich keine Ahnung, aber dort kann man doch sicher einzelne Objekte über einen eindeutigen Identifier, der ein String sein kann, rausziehen?

Nichts spricht erst mal dagegen, ich muss mir das aber erst mal anschauen, weil ich mich damit noch nie beschäftigt habe.
 
Map<String, Player> klingt eigentlich genau nach dem, was du suchst, wenn die Spielernamen eindeutig sind.

Angenommen du hast eine

Code:
Map<String, Player> players = new HashMap<String, Player>();

und einen

Code:
Player theo = new Player("Theo");

Dann sind die wichtigsten Methoden einer Map

Code:
players.put(theo.getName(), theo); // Legt eine Zuordnung des Keys "Theo" auf den Player theo an

und

Code:
Player myRetrievedPlayer = players.get("Theo"); // Zieht einen Player mit dem Key "Theo" aus der Map oder null, falls es keinen solchen gibt

Wenn du deine Player irgendwo ausliest, kannst du dir die ganzen Literale da natürlich schenken. Das ist nur zur Demonstration.

API: http://docs.oracle.com/javase/6/docs/api/java/util/Map.html
 
Bringt ihn doch nicht ab von seinem Array.
1. Arrays sind viel besser als ihr Ruf. Z.B. viel effizienter als dynamische Collections.
2. Er will lernen, ist doch super, erstmal mit Array anzufangen.
---
Was mir in der Diskussion bisher gefehlt hat -
keinen einziger Vorschlag war WIRKLICH Objektorientiert, alles hier wurde sehr funktional beschrieben.

Ich versuche jetzt mal ein paar abstrakte Ideen zu bringen, ohne jetzt eine fertige Lösung zu präsentieren.
1) Beschäftige dich mit den Methoden
equals und hashCode beide(!) braucht deine Klasse Spieler für deinen "Vergleich"
(Frag Google)
2) Besser wäre, du fängst mit einem Test an, das hilft dir, Objektorientiert / als Nutzer deiner Klassen und weniger
in Funktionen zu denken
3. NIEMALS direkt auf Attribute zu greifen (EVIL) Warum frag Google :)
4. Bevor du hier ans Coden gehst, denk dir erstmal eine LOGIK aus, was willst du genau erreichen,
da ich das nicht alles weiß, phantasiere ich mal kurz:

Du willst vermutlich ein kleines Spiel programmieren.
Dein Spiel hat vermutlich eine Spielewelt oder Spiefeld (und eigentlich solltest du alles auf Englisch schreiben, aber egal mal jetzt...)

Spiel
- Spielfeld
- Spieler[]
- SpielRegeln[]
- Punktestand

Und (zumindest in meiner Version, ob das wirklich besser ist, müßte man sich genauer überlegen, aufmalen, usw..)
die Punkte findest du in Punktestand
Vermutlich geben die Spielregeln vor, das der, der zuerst eine bestimmte Punktzahl hat,
gewonnen hat (also er ist dann der Gewinner)

Punktestand
public addSpielPunkte(String spielerName, int punktZahl) {
punktZahl(spielerName).add(punktZahl); //oder halt + punktZahl wenn kein Objekt, aber meist besser Objekt...
}

public boolean existsWinner(){


for(Punktzahl punktZahl: punktzahlen){
if(punktZahl.greaterOrEqual(spielRegeln.punktZahlTtoWin()){
return true;
}
}
}

public Spieler winner(){
for(Punktzahl punktZahl: punktzahlen){
if(punktZahl.greaterOrEqual(spielRegeln.punktZahlTtoWin()){
return punktZahl.spieler();
}
}
}
}

--------

Also ich hab Feierabend und hab das mal eben hin gerotzt,
und "greaterOrEqual" ist vielleicht schon overdesign -
ich hab nur mal versucht eine "Objektorientierte Denke" hier bisserl mehr
reinzu kriegen.
Und denk an Equal und HashCode.

DIE brauchst du, damit du weißt, ob der Spieler, den du suchst, der ist, den du suchst..

dann sagst du nämlich:
Player gesuchterPlayer = new Player("HANS");
Player[] players;
for(Player player: players){
if "HANS".equals(player){
return true;
}
---
Wichtig bei dem Equals Vergleich Konstante vorne - sonst kriegst du u.U. eine NullPointerException,
was du vermutlich vermeiden möchtest.........
Hoffe das hilft was, sorry für Chaos...

Marcus
 
Und was soll daran schlecht sein?
Eigentlich meinte ich eher prozedural als funktional.
Aber auch funktional - hat seine Vorteile - siehe Java 8 - aber auch seine Nachteile.
Wie auch immer, funktional Programmierung mit Java würde ich jetzt mal als Step 2 bezeichnen -
erstmal sollte er anfangen, richtig objektorientiert zu denken und zu programmieren - das können - LEIDER
die wenigsten.

Inwiefern? Ich sehe nur Nachteile.
Arrays sind effizienter als Collections, es gibt sie in (fast?) jeder Programmiersprache, damit sollten / werden sie auch von jedem
verstanden, und jeder Anfänger fängt nun mal mit einem Array an.
Und last but not least - wenn ich keine dynamische Collection brauche - warum sollte ich dann eine nutzen?
ArrayList z.B. basiert ja selbst wieder auf Arrays. Und wenn ich ein statisches Array fester Größe habe, sorgt dass auch dafür,
dass sich die Größe des Arrays (ohne "manuellen Eingriff") nicht ändert.

Und überhaupt. (Das wichtigste Argument! ;-)
 
Kann die Vorschläge nicht nachvollziehen. Für solche längeren Abgleiche macht man switch case und fertig, die ursprüngliche Idee im ersten Posting kann auch beibehalten werden.

Wobei ich das eigentliche Problem, das gelöst werden soll, nicht ganz verstehe.

Es könnte der Fall auftreten dass ich 100 Objekte von der Klasse Spieler hätte, dann müsste ich 100 vergleiche aufschreiben.
Tja, dann ist es halt so.

Wenn du allerdings so viele Objekte in deinem "Programm" brauchst, dann brauchst du ja wohl offensichtlich auch eine Datenbank. Und da muss es dann eine definierte Funktion geben um Objekte reinzuschreiben und auszulesen. Ist ja ein Standardproblem.
 
Prinzipiell richtig - für einen easy case würde ich AUCH ein switch machen.
Aber das ist ja (denke ich) nur ein Lernbeispiel -
und da wollte ich ihn "auf die richtige Seite der Macht ziehen"! ;-)

Wenn man anfängt zu lernen und dann sieht "huuiii ein switch, das ist ja einfach"..
Dann kommt da schnell so ein Spaghetti-Coder raus, von der Sorte, vor der ich mich fürchte...
;-)
Ergänzung ()

Weiter denke ich, die Frage zu "...dann müßte ich 100 Vergleiche aufschreiben"
heißt: Was vermeidet eine (for/foreach/while)-Schleife?!

;-)
 
Dooing schrieb:
1. Arrays sind viel besser als ihr Ruf. Z.B. viel effizienter als dynamische Collections.
So pauschal ist das einfach falsch. Das kommt auf den Anwendungsfall drauf an.
Eine ArrayList die mit der richtigen Anzahl der Elemente initialisiert wurde, ist genauso effizient wie ein entsprechendes Array (weil es ein eben solches verwendet). Und wer hauptsächlich anhand eines Schlüssels zugreift, ist mit einer Hash-Table meist besser (im Worst Case zumindest nicht schlechter) bedient.
Arrays haben in der Praxis (zumindest für mich) nur begrenzten Nutzten, weil bei den Anwendungen die Zahl der Elemente nicht im Vorhinein bekannt ist. Sie haben wie alles ihren Platz, aber man sollte sich das Leben auch nicht unnötig schwer machen.

Dooing schrieb:
Was mir in der Diskussion bisher gefehlt hat -
keinen einziger Vorschlag war WIRKLICH Objektorientiert, alles hier wurde sehr funktional beschrieben.
Dafür haben wir hier wie ich finde zu wenige Informationen über das Problem. Natürlich kann man wie du etwas annehmen (was auch OK ist), aber das gegebene Problem lässt sich nun mal mit ein Hash-Table ideal lösen.
Btw: Du meinst prozedual. Funktionale Programmierung ist was anders. ;)

Dooing schrieb:
Also ich hab Feierabend und hab das mal eben hin gerotzt,
und "greaterOrEqual" ist vielleicht schon overdesign -
ich hab nur mal versucht eine "Objektorientierte Denke" hier bisserl mehr
reinzu kriegen.
Die Klasse "Punktestand" ist meiner Meinung nach nicht nötig. Der Punktestand ist für mich kein Objekt sondern ein Attribut eines Spielers. Mir fällt kein Verhalten eines Punktestands ein, dass über das einer Ganzzahl hinausgeht und sinnvoll zu modellieren wäre. Man kann es schon machen, aber hier halte ich es für unnötig.

Dooing schrieb:
Code:
Player gesuchterPlayer = new Player("HANS");
Player[] players;
for(Player player: players){
    if "HANS".equals(player){
        return true;
    }
}
Nein, so sollte man "equals" nicht einsetzen.
"equals" sagt dir (wie der Name schon sagt) ob zwei Objekte als gleich angesehen werden. Der String "HANS" ist für mich nie gleich einem Spieler. "HANS" ist nur der Name des Spielers aber eben nicht gleichbedeutend mit ihm. Und ja, in der Realität sagt man natürlich "Das ist Hans!" und nicht "Das ist der Spieler mit dem Namen Hans!", aber das ist eben nur eine sprachliche Ungenauigkeit und nicht die Realität.
Außerdem: Was machst du wenn du den Spieler mit einer bestimmten Punktzahl suchst? player.equals(42)? Ich hoffe nicht.
 
Hui. Endlich mal einer hier der Programmieren kann! ;-)
Ja, das mit dem equals ist mir auch schon aufgefallen - aber ich sagte ja "Feierabend" ;-)
Aber da hast du auch eine Halbwarheit gesagt -
richtig player.equals(otherPlayer) ist besser, wenn möglich - aber kommt eben auch auf den Anwendungfall an -
eventuell hat man an der Stelle keinen Player, und "NAME".equals(player.name()) geht dann ja auch.

Bezüglich prozedural / funktional - lies mal alle meine Threads - ja, ist mir auch schon aufgefallen.
Man sollte nach Feierabend nix mehr schreiben! ;-)
Aber wo ist eigentlich der Threadstarter? Scheint seine Hausaufgabe ist schon erledigt...
 
Zurück
Oben