2015-07-14 12 views
6

Rozważmy klasę w javaZnajdź hierarchię

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; 
} 


} 
} 

Rozważmy parentId jak klucza obcego (dotyczy id do innego obiektu).

Teraz stworzyłem 6 obiektów i dodałem kilka wartości.

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); 

Teraz chcę uzyskać hierarchię obiektów. Oznacza to, że jeśli podam id, powinienem uzyskać pełną hierarchię nadrzędną i hierarchię potomną.

dla np: jeśli dam 100 jako identyfikator (jednostki: E4), powinienem dostać hierarchii nadrzędny: - E4, E3, E2, E1 hierarchia dziecko: - E4, E5, E6

Objaśnienie: - dla hierarchii nadrzędnej: - najpierw powinniśmy dodać początkowy obiekt e4. wtedy znajdziemy obiekt, którego ID jest takie samo, jak i ID4 rodzicielskiego e4 (tutaj e3) proces trwa do momentu, gdy parentid ma wartość null dla hierarchii potomnej: - najpierw powinniśmy dodać początkowy obiekt e4. wtedy znajdziemy obiekt, którego parentId jest taki sam jak identyfikator e4. (Tutaj E5) proces trwa aż The parentId jest null

Rozwiązanie przeze mnie dla hierarchii dominującej: -

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(); 
    } 

dla hierarchii dzieci:

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(); 

    } 

znalazłem tę metodę aby rozwiązać scenariusz, Ale chcę bardziej wydajne rozwiązanie w java 8, używając jego podstawowych pojęć, aby rozwiązać ten problem.

+0

czy to jest powód, dla którego zamiast "parentId" zamiast odniesienia do rodzica? – user902383

Odpowiedz

1

Znalazłem więcej rozwiązania Java8 z zapachem programowania funkcjonalnego.

Biorąc swoich sześciu jednostek (proszę zwrócić uwagę, że mam ustawić identyfikator dla e6, w przeciwnym razie możemy uzyskać 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); 

oraz wykaz zawierający je:

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

Następnie dla hierarchii rodziców:

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] 

I dla hierarchii dzieci:

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] 

Chodzi o to, aby skorzystać z metody Stream.iterate(), tworząc strumień za pomocą „funkcjonalny” iteracji.

Dla rodziców Utworzyłem UnaryOperator (funkcji), że podawany był Entity powraca albo jego rodzic Entity lub null; dla dzieci, stworzyłem UnaryOperator, który, biorąc pod uwagę Entity, zwraca jego dziecko: Entity lub null.

Aby wykonać te dwa wyszukiwań Użyłem innego Function że po prostu przeszukuje list przez id i parentId, odpowiednio.

-1

Czy do łączenia z rodzicem musisz używać identyfikatorów int? W zależności od tego, co chce osiągnąć, ale nie można po prostu połączyć tak:

class Entity { 
    Integer id; 
    Entity parent; 
} 

Wtedy nie musiałby szukać całą listę skoro masz swój pierwszy podmiot.

+0

Myślę, że powinieneś podać rozwiązanie tego pytania, nie edytując pytania. –

+0

Użycie odpowiedniej struktury danych dla jakiegoś problemu jest co najmniej tak samo ważne jak sam algorytm. Jeśli używasz struktury danych, która nie jest odpowiednia dla problemu, algorytm może być powolny i skomplikowany. Dlatego zapytałem, czy istnieje jakikolwiek powód, dla którego należy użyć tej struktury danych. – user140547

0

chciałbym tworzyć tabele wyszukiwania dla obiektów, rodziców i dzieci:

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)); 
    } 
} 

nie obsługuje podmioty, z wieloma dziećmi, może chcesz sprawdzić przykłady dla java.util.stream.Collectors.groupBy

Powiązane problemy