2015-07-14 18 views
6

Lassen Sie uns eine Klasse in Java betrachtenFinden Sie die Hierarchie

class Entity { 

Integer id; 
Integer parentId; 

public Integer getId() { 
    return id; 
} 

public void setId(Integer id) { 
    this.id = id; 
} 

public Integer getParentId() { 
    return parentId; 
} 

public void setParentId(Integer parentId) { 
    this.parentId = parentId; 
} 


} 
} 

parentId Betrachten wie die Fremdschlüssel (bezieht sich auf ein anderes Objekt-ID).

Jetzt habe ich 6 Objekte erstellt und einige Werte eingegeben.

Entity e1 = new Entity(); 
    e1.setId(400); 

    Entity e2 = new Entity(); 
    e2.setId(300); 
      e2.setParentId(400); 

    Entity e3 = new Entity(); 
    e3.setId(200); 
    e3.setParentId(300); 

    Entity e4 = new Entity(); 
    e4.setId(100); 
      e4.setParentId(200); 

    Entity e5 = new Entity(); 
    e5.setId(50); 
      e5.setParentId(100); 

    Entity e6 = new Entity(); 
    e6.setParentId(50); 

Jetzt möchte ich die Hierarchie der Objekte erhalten. Das heißt, wenn ich ID gebe, sollte ich die komplette Eltern-Hierarchie und Kind-Hierarchie erhalten.

für zB: wenn ich 100 als ID geben (Einheit: e4), soll ich die übergeordnete Hierarchie erhalten: - e4, e3, e2, e1 Child-Hierarchie: - e4, e5, e6

Erläuterung: - Für die übergeordnete Hierarchie: - Wir sollten zuerst das ursprüngliche e4-Objekt hinzufügen. dann werden wir das Objekt finden, dessen iD dasselbe ist wie das von e4 parentId (hier e3), wird der Prozess fortgesetzt, bis die Parent-ID null für die untergeordnete Hierarchie ist: - wir sollten zuerst das ursprüngliche e4-Objekt hinzufügen. dann werden wir das Objekt finden, dessen parentId dasselbe ist wie das der ID von e4. (Hier e5) der Prozess, bis weitergeht, ist die parentid null

Lösung von mir für Hierarchie parent: -

List<Entity> parent = new ArrayList<Entity>(); 

    Entity ent = list.stream().filter(e -> e.getId() == 100).findFirst() 
      .get(); // // 100 input id value 

    parent.add(ent); 

    Integer parentId = ent.getParentId(); 

    while (parentId != null) { 

     int search = parentId; 
     Entity newEntity = list.stream().filter(e -> e.getId() == search) 
       .findFirst().get(); 

     parent.add(newEntity); 
     parentId = newEntity.getParentId(); 
    } 

für Kind-Hierarchie:

Entity entnew = list.stream().filter(e -> e.getId() == 100).findFirst() 
      .get(); // 100 input id value 



    child.add(entnew); 


    Integer idNew = entnew.getId(); 


    while (idNew != null) { 

    int searchNew = idNew; 

    Entity newEnt = list.stream().filter(f -> f.getParentId()!= null && f.getParentId() == searchNew) 
      .findFirst().get(); 

    child.add(newEnt); 
    idNew = newEnt.getId(); 

    } 

ich diese Methode gefunden um das Szenario zu lösen, aber ich möchte eine effizientere Lösung in Java 8 mit seinen Kernkonzepten, um dies zu lösen.

+0

ist es ein Grund, warum Sie "parentId" statt Verweis auf Eltern halten? – user902383

Antwort

1

Ich habe eine Java8-ish-Lösung gefunden, mit einem Geruch von funktionalen Programmierung.

Angesichts Ihrer sechs Personen (bitte beachten Sie, dass ich die Id für e6 eingestellt haben, sonst bekommen wir ein NullPointerException):

Entity e1 = new Entity(); 
e1.setId(400); 

Entity e2 = new Entity(); 
e2.setId(300); 
e2.setParentId(400); 

Entity e3 = new Entity(); 
e3.setId(200); 
e3.setParentId(300); 

Entity e4 = new Entity(); 
e4.setId(100); 
e4.setParentId(200); 

Entity e5 = new Entity(); 
e5.setId(50); 
e5.setParentId(100); 

Entity e6 = new Entity(); 
e6.setId(25); // this Id must be set, or we'll get a NPE 
e6.setParentId(50); 

Und eine Liste mit ihnen:

List<Entity> list = new ArrayList<>(); 
list.add(e1); 
list.add(e2); 
list.add(e3); 
list.add(e4); 
list.add(e5); 
list.add(e6); 

Dann für Eltern Hierarchie:

Function<Integer, Entity> byId = 
    id -> list.stream() 
     .filter(e -> e.getId().equals(id)) 
     .findFirst() 
     .orElse(null); 

Entity parentsSeed = byId.apply(100); // e4 

UnaryOperator<Entity> nextParent = 
    e -> e == null ? e : byId.apply(e.getParentId()); 

List<Entity> parents = 
    Stream.iterate(parentsSeed, nextParent) 
     .limit(list.size()) 
     .filter(Objects::nonNull) 
     .collect(Collectors.toList()); // [e4, e3, e2, e1] 

Und für Kinder Hierarchie:

Entity childrenSeed = byId.apply(100); // e4 

Function<Integer, Entity> byParentId = 
    id -> list.stream() 
     .filter(e -> id.equals(e.getParentId())) 
     .findFirst() 
     .orElse(null); 

UnaryOperator<Entity> nextChild = 
    e -> e == null ? e : byParentId.apply(e.getId()); 

List<Entity> children = 
    Stream.iterate(childrenSeed, nextChild) 
     .limit(list.size()) 
     .filter(Objects::nonNull) 
     .collect(Collectors.toList()); // [e4, e5, e6] 

Die Idee ist, die Stream.iterate() Methode zu verwenden, indem man einen Strom mit Hilfe einer „funktionellen“ Iteration erzeugt wird.

Für die Eltern, habe ich erstellt eine UnaryOperator (eine Funktion), dass bei einem gegebenen Entity, kehrt entweder ihre Mutter Entity oder null; Für Kinder habe ich eine UnaryOperator erstellt, die bei Entity entweder ihr Kind Entity oder null zurückgibt.

diese beiden Suchanfragen ausführen zu können, ich habe eine andere Function verwendet, die einfach die list von id und parentId sucht wurden.

-1

Müssen Sie int IDs zum Verknüpfen mit dem Eltern verwenden? Je nachdem, was Sie versuchen zu erreichen, kann aber nicht einfach verknüpfen wie folgt aus:

class Entity { 
    Integer id; 
    Entity parent; 
} 

Dann müssten Sie nicht Ihre ganze Liste suchen, sobald Sie haben Ihre erste Einheit.

+0

Ich denke, Sie sollten eine Lösung für diese Frage bieten, nicht durch Bearbeiten der Frage –

+0

Die Verwendung der entsprechenden Datenstruktur für ein Problem ist mindestens so wichtig wie der Algorithmus selbst. Wenn Sie eine Datenstruktur verwenden, die für das Problem nicht geeignet ist, kann der Algorithmus langsam und kompliziert werden. Daher habe ich gefragt, ob es einen Grund gibt, warum diese Datenstruktur verwendet werden muss. – user140547

0

Ich würde erstellen Lookup-Tabellen für Objekte, Eltern und Kinder:

List<Integer> ancestors = new ArrayList<>(); 
List<Integer> descendants = new ArrayList<>(); 
Map<Integer, Entity> objectById = list.stream().collect(Collectors.toMap(e ->e.getId(), e->e)); 
Map<Integer, Integer> parentIdByChildId = list.stream().collect(Collectors.toMap(e->e.getId(), e ->e.getParentId()); 
Map<Integer, Integer> childIdByParentId = list.stream().collect(Collectors.toMap(e ->e.getParentId(), e->e.getId()); 
Integer parentId = 10; 
Integer current = parentId; 
while(current!=null) { 
    current = childIdByParentId.get(current); 
    if(current!=null){ 
     descendants.add(objectById.get(current)); 
    } 
} 
current = parentId; 
while(current!=null) { 
    current = parentIdByChildId.get(current); 
    if(current!=null){ 
     ancestors.add(objectById.get(current)); 
    } 
} 

Dies gilt nicht Entities mit mehreren Kindern unterstützen, möchten Sie vielleicht Beispiele prüfen java.util.stream.Collectors.groupBy