Erweiterte Datenstrukturen?

flashray

Erfahrenes Mitglied
Hallo,

habe folgende Probleme mit ein Paar Java Collections.

Szenario 1: Es existiert eine Liste von Wertepaaren. Diese habe ich eine HashMap gespeichert. Es gibt eine Methode get() die zu einem Key das Value liefert. Umgekehrt eine Methode die zu einer Value das Key findet gibt es nicht. Dann gibt es auch keine Methoden zum Erfragen der Indizes jeweils für ein bestimmtes Key oder Value.

Szenario 2: Mehrere Objekte der gleichen Klasse welches mehrere Attribute besizt sind in einer LinkedList gespeichert. Jetzt möchte ich in der Liste suchen ob ein Objekt mit einem bestimmten Attributwert existiert. Es gibt zwar die Methode contains(), diese vergleicht aber die Objekte, so dass man nur abfragen kann ob ein bestimmtes Objekt in der Liste enthalten ist. Ebenso das gleiche Problem, wenn man das Indize eines Objektes erfragen möchte, von welchem man nur einen Attributwert kennt.

Existieren andere komfortablere Datenstrukturen die besser geignet für diese Szenarien wären? Wenn nein, ist dann die einfachste Möglichkeit diese Features zu implementieren Utility Klassen zu schreiben die mit Comparable oder Comparator arbeiten.


Vg Erdal
 
Hallo,

für Szenario zwei habe ich folgende Hilfsklasse geschrieben:
Java:
package util;

import java.util.LinkedList;
import java.util.Map;

import datastructure.*;

public class SessionUtility {

	private LinkedList<Session> sessions;

	private LinkedList<String> name_s;

	private LinkedList<Player> director_s;

	private LinkedList<LinkedList<Player>> players_s;

	private LinkedList<SessionState> state_s;

	private LinkedList<Map<Integer, Highscore>> highscores_s;

	public SessionUtility(LinkedList<Session> sessions) {
		super();
		this.sessions = sessions;
		for (int i = 0; i < sessions.size(); i++) {
			name_s.add(sessions.get(i).getName());
			director_s.add(sessions.get(i).getDirector());
			players_s.add(sessions.get(i).getPlayers());
			state_s.add(sessions.get(i).getState());
			highscores_s.add(sessions.get(i).getHighscores());
		}
	}

	public boolean contains(String sessionName) {
		return name_s.contains(sessionName);
	}

	public boolean contains(Player director) {
		return director_s.contains(director);
	}

	public int indexOf(String sessionName) {
		return name_s.indexOf(sessionName);
	}

	public int indexOf(Player director) {
		return director_s.indexOf(director);
	}

	public Session get(String sessionName) {
		return sessions.get(name_s.indexOf(sessionName));
	}

	public Session get(Player director) {
		return sessions.get(director_s.indexOf(director));
	}

	public LinkedList<Session> getSessions() {
		return sessions;
	}

	public void setSessions(LinkedList<Session> sessions) {
		this.sessions = sessions;
	}
}

Java:
package datastructure;



import java.io.Serializable;

import java.util.Collections;

import java.util.HashMap;

import java.util.LinkedList;

import java.util.Map;




public class Session implements Serializable {



    private static final long serialVersionUID = 4572785872966819648L;

    

    /**

     * name identifying a session

     */

    private String name;

    

    /**

     * creator of the session with more capability than the other

     * players in this session

     */

    private Player director;

    

    /**

     * list of players including the director 

     * {@link de.uni_mannheim.informatik.swt.pm07.bomberman.datastructure.Player Player} 

     */

    private LinkedList<Player> players;

    

    /**

     * {@link de.uni_mannheim.informatik.swt.pm07.bomberman.datastructure.SessionState SessionState}

     */

    private SessionState state = SessionState.OPEN;

    

    /**

     * the map consists of the senderId of a player and its highscore

     */

    private Map<Integer, Highscore> highscores = Collections.synchronizedMap(new HashMap<Integer, Highscore>());

    

    

    

    public Session(String name, Player director, LinkedList<Player> players) {

        this.name = name;

        this.director = director;

        this.players = players;

    }



    public String getName() {

        return name;

    }



    public void setName(String name) {

        this.name = name;

    }



    public Player getDirector() {

        return director;

    }



    public void setDirector(Player director) {

        this.director = director;

    }



    public LinkedList<Player> getPlayers() {

        return players;

    }



    public void setPlayers(LinkedList<Player> players) {

        this.players = players;

    }



    public SessionState getState() {

        return state;

    }



    public void setState(SessionState state) {

        this.state = state;

    }



    public Map<Integer, Highscore> getHighscores() {

        return highscores;

    }



    public void setHighscores(Map<Integer, Highscore> highscores) {

        this.highscores = highscores;

    }

    

}

Das ist jetzt keine allgemeingültige Lösung. Eine solche Utility Klasse muss man neu für jede neue LinkedList schreiben. Gibt es vielleicht doch eine schnellere, einfachere Lösung?


Vg Erdal
 
Hallo,

Szenario 1: Es existiert eine Liste von Wertepaaren. Diese habe ich eine HashMap gespeichert. Es gibt eine Methode get() die zu einem Key das Value liefert. Umgekehrt eine Methode die zu einer Value das Key findet gibt es nicht. Dann gibt es auch keine Methoden zum Erfragen der Indizes jeweils für ein bestimmtes Key oder Value.
Welchen Index meinst du denn? Eine HashMap bzw. eine Map ist nun mal prinzipiell so konzipiert das man auf die
einzelnen Einträge über die entsprechenden Keys zugreifen kann. In Hash-Basierten Collections werden die Werte( bzw. die Keys) abhängig von ihrem HashCode
intern in sogenannten Buckets (Körbe) gespeichert. Die Reihenfolge in der die Einträge in den entsprechenden Buckets aufzufinden sind ist
nicht fix. Es kann beispielsweise vorkommen, das es beim neueinfügen eines Wertes zu einer Schlüsselkollision kommt
und deshalb die komplette Map bzw. Teile davon neu gehashed werden müssen. Dabei werden die Einträger u.U. wieder
in andere Buckets kopiert. Dadurch ändert sich natürlich die interne Ordnung... deshalb ist ein
ein Zugriff über einen "internen" Index wäre bei dieser Containerart so gut wie Sinnfrei... IMHO

Umgekehrt eine Methode die zu einer Value das Key findet gibt es nicht
Kein problem -> hier ein Beispiel wie man eine gespiegelte Map aufbauen kann...
http://www.tutorials.de/forum/java/269458-html-entities-zeichen-umwandeln.html

Szenario 2: Mehrere Objekte der gleichen Klasse welches mehrere Attribute besizt sind in einer LinkedList gespeichert. Jetzt möchte ich in der Liste suchen ob ein Objekt mit einem bestimmten Attributwert existiert. Es gibt zwar die Methode contains(), diese vergleicht aber die Objekte, so dass man nur abfragen kann ob ein bestimmtes Objekt in der Liste enthalten ist. Ebenso das gleiche Problem, wenn man das Indize eines Objektes erfragen möchte, von welchem man nur einen Attributwert kennt.
Was du willst ist ne Art Query by Example und eine Filtermöglichkeit auf Collections...
Das kann man sich ziemlich leicht selber bauen.

Schau mal hier:
Java:
/**
 * 
 */
package de.tutorials;

import java.lang.reflect.AccessibleObject;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;

/**
 * @author Tom
 */
public class QueryByExample {

  /**
   * @param args
   */
  public static void main(String[] args) {
    List<Bubu> list = new LinkedList<Bubu>();
    list.add(new Bubu("AAA", 12));
    list.add(new Bubu("BBB", 1));
    list.add(new Bubu("CCC", 33));
    list.add(new Bubu("AAA", 1));
    list.add(new Bubu("DDD", 12));

    System.out.println("BubusWith1: " + queryByExample(list, new Bubu(null, 1)));

    System.out.println("BubusWithAAA: " + queryByExample(list, new Bubu("AAA", null)));

    System.out.println("BubusWithAAAAnd1: " + queryByExample(list, new Bubu("AAA", 1)));

    System.out.println("##################");

    System.out.println("BubusWithDataGreater10: " + filter(list, new IPredicate<Bubu>() {
      public boolean evaluate(Bubu argument) {
        return argument.getData() > 10;
      }
    }));
  }

  private static <TTargetType> List<TTargetType> filter(List<TTargetType> candidates, IPredicate<TTargetType> predicate) {
    List<TTargetType> results = new ArrayList<TTargetType>();
    for(TTargetType candidate : candidates){
      if(predicate.evaluate(candidate)){
        results.add(candidate);
      }
    }
    return results;
  }


  private static <TTargetType> List<TTargetType> queryByExample(List<TTargetType> candidates, TTargetType exmaple) {
    List<TTargetType> results = new ArrayList<TTargetType>();
    for (TTargetType candidate : candidates) {
      if (attributesMatchIgnoringNulls(candidate, exmaple)) {
        results.add(candidate);
      }
    }
    return results;
  }


  private static boolean attributesMatchIgnoringNulls(Object candidate, Object example) {
    Field[] fields = candidate.getClass().getDeclaredFields();
    Field[] exampleFields = example.getClass().getDeclaredFields();

    AccessibleObject.setAccessible(fields, true);
    AccessibleObject.setAccessible(exampleFields, true);

    boolean matches = true;

    for (int i = 0; i < fields.length; i++) {
      Field field = fields[i];
      for (int j = 0; j < exampleFields.length; j++) {
        Field exampleField = exampleFields[j];
        if (field.getName().equals(exampleField.getName())) {
          try {
            Object value = field.get(candidate);
            Object exampleValue = exampleField.get(example);
            if (null == exampleValue || null == value) {
              continue;
            } else {
              matches &= value.equals(exampleValue);
            }
          } catch (Exception e) {
            e.printStackTrace();
          }
        }
      }
    }

    return matches;
  }

  static class Bubu {
    String value;
    Integer data;


    public String getValue() {
      return value;
    }


    public void setValue(String value) {
      this.value = value;
    }


    public Integer getData() {
      return data;
    }


    public void setData(Integer data) {
      this.data = data;
    }


    /**
     * @param value
     * @param data
     */
    public Bubu(String value, Integer data) {
      super();
      this.value = value;
      this.data = data;
    }


    @Override
    public String toString() {
      return this.value + " : " + this.data;
    }
  }

  static interface IPredicate<TTargetType> {
    boolean evaluate(TTargetType argument);
  }

}

Ausgabe:
Code:
BubusWith1: [BBB : 1, AAA : 1]
BubusWithAAA: [AAA : 12, AAA : 1]
BubusWithAAAAnd1: [AAA : 1]
##################
BubusWithDataGreater10: [AAA : 12, CCC : 33, DDD : 12]

Gruß Tom
 
Hallo Tom,

herzlichen Dank! Einfach Top!

Die gespiegelte Map ist eine tolle Idee. Aber das Query By Example ist genau das Zauberfeature das ich brauchte :) .


Vg Erdal
 
Zurück