如何遍历对象列表并分配子项?

时间:2015-04-02 00:34:15

标签: java object graph-algorithm pojo java-5

我有一个Location POJO,用于存储从JSON文件解析的Location对象,我想将其映射到图形。图中每个节点的位置对应于它的id字段,其中id =“1”是起始节点,id =“10”是目标节点。

为了解决这个问题,我调整了一个Node类,以包含setWeight()addChildLocation()等方法,但我不确定如何从我的位置列表中创建图形。我知道如何通过硬编码位置和调用addChildren来创建图形,通过执行以下操作,但不知道如何从已有的Location对象列表创建它:

    Node LocationOne= new Node("LocationOne", 170);
    LocationOne.addChildNode(LocationTwo, 105);

我对这个问题的看法是,应该使用for..each循环遍历列表中的位置,并将每个位置添加为前一个位置的子项。

基本上,我想知道如何迭代Location对象列表,并在每个连续位置调用addChild?

下面是我用来将位置映射到对象表示的Location类:

public class Location {

    private Location[] location;

    private int id;

    private String description;

    private String weight;

    private String name;

    private Exit[] exit;

    private boolean visited = false;
    private boolean goalLocation;
    private int approximateDistanceFromGoal = 0;
    private Location parent;

    private Map<Location, Integer> children = new HashMap<Location, Integer>();




    public Location() {
        super();
    }

    public Location(String name){
        this.name = name;
    }

    public Location(String name, int goalDistance){
        this.name = name;
        this.approximateDistanceFromGoal = goalDistance;
    }

    public Location[] children(){
        return (Location[]) children.keySet().toArray(new Location[children.size()]);
    }

    public int getDistance(Location loc){
        if(children.get(loc) == null) System.out.println(this.name + ": " + loc.getName());
        return children.get(loc);
    }


    public int getChildLocationCount(){
        return children.size();
    }

    public void addChildLocation(Location child, int distance){
        children.put(child, distance);
    }

    public boolean isLeaf(){
        if (children.size() > 0){
            return false;
        }else{
            return true;
        }
    }


    public void removeChild(Location child){
        children.remove(child);
    }


    public Location[] getLocation() {
        return location;
    }

    public void setLocation(Location[] location) {
        this.location = location;
    }


    public int getId() {
        return id;
    }

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

    public String getDescription ()
    {
        return description;
    }

    public void setDescription (String description)
    {
        this.description = description;
    }


    public String getWeight() {
        return weight;
    }

    public void setWeight(String weight) {
        this.weight = weight;
    }

    public String getName ()
    {
        return name;
    }

    public void setName (String name)
    {
        this.name = name;
    }

    public Exit[] getExit() {
        return exit;
    }

    public void setExit(Exit[] exit) {
        this.exit = exit;
    }


    public boolean isVisited() {
        return visited;
    }

    public void setVisited(boolean visited) {
        this.visited = visited;
    }

    public boolean isGoalLocation() {
        return goalLocation;
    }

    public void setGoalLocation(boolean goalLocation) {
        this.goalLocation = goalLocation;
    }

    public int getApproximateDistanceFromGoal() {
        return approximateDistanceFromGoal;
    }

    public void setApproximateDistanceFromGoal(int approximateDistanceFromGoal) {
        this.approximateDistanceFromGoal = approximateDistanceFromGoal;
    }

    public Location getParent() {
        return parent;
    }

    public void setParent(Location parent) {
        this.parent = parent;
    }

    @Override
    public String toString() {
        return "Location [location=" + Arrays.toString(location) + ", id=" + id
                + ", description=" + description + ", weight=" + weight
                + ", name=" + name + ", exit=" + Arrays.toString(exit)
                +"]";
    }


}

2 个答案:

答案 0 :(得分:3)

如果你想构建任何类型的图形,那么要认识到图形由2个基本元素组成:

  1. E - &gt;边缘
  2. V - &gt;顶点(A.K.A节点)
  3. 关键属性:

    • 顶点可以包含任意数量的边。
    • 边缘只在单身之间 节点(在我的实现中,我为了记账而修改了它)。

    实际上,您如何访问这些将取决于功能和性能之间的权衡。此外,如果图形节点不包含您的某些信息,则它们毫无价值。所以,我们添加

    Map<String,Object> properties
    

    因此我们可以存储一些数据:

    new Vertext().set("age",10);
    

    我们还使用命名边缘,因此您可以执行以下操作:

    Graph g = new Graph();
    g.addVertex("Doctor",new DrVertex("Dr. Smith"));
    g.addVertex("Doctor",new DrVertex("Dr. Cooper"));
    List<Vertex> doctors = g.get("Doctor");
    assertTrue("Dr. Smith",doctors.get(0));
    assertTrue("Dr. Cooper",doctors.get(1));
    

    我已经将我如何实现通用图的基本结构放在一起。但有些人指出,像Neo这样的图形数据库非常复杂。

    以下是代码。如果您想为您的位置建模,请使用它。

    /**
     * @author Christian Bongiorno
     */
    public class Graph {
    
        private class Vertex {
            Map<String,Object> properties;
            private Map<String,Edge> edges;
    
            public Graph addVertex(String edgeName, Vertex v) {
                Edge e = edges.get(edgeName);
                if(e == null) {
                    e = new Edge(this);
                    edges.put(edgeName,e);
                }
    
                e.addVertex(v);
                return Graph.this;
            }
    
            public Graph addVertex(Vertex v) {
                return addVertex("anonymous",v);
            }
    
        }
    
        private static class Edge {
            Map<String,Object> properties;
            Vertex in;
            Collection<Vertex> out;
    
            private Edge(Vertex in) {
                this.in = in;
            }
    
    
            private void addVertex(Vertex v) {
                out.add(v);
            }
        }
    
    }
    

    您可以考虑将此问题移至codereview.stackexchange.com

      

    被修改

    想象一下你的代码是这样的:

    • 位置 - &gt;顶点
    • 位置[] - &gt;所有连接的位置(顶点),其中位置[i]中的i是边

    您的代码很难处理,因为您没有声明边缘。边缘的一个特性是'#34; weight&#34;但在这里你把它作为地点的财产。

    至于实施&#34;访问&#34; - 这是一个呼叫状态,而不是图宽状态。但是,通过使其成为位置的一部分,您现在遇到了州管理问题;想象一下,试图找到&#34;再一次?你必须重置“访问过的”#39;每个节点上的属性或丢弃并再次创建整个图形。非常低效且容易出错。

    如果你实现DFS,这很容易递归,甚至是尾循环,你可以通过&#34;访问过的&#34;状态以及dfs方法调用。例如:

    public Location find(Integer locationId) {
       Location result = null;
       for(Location l : locations) {
          // this hashset represents the visited state which only matters for this method call
          result = dfs(new HashSet(),l,locationId); 
          if(result != null)
              break;
       }
       return result;
    }
    

    请注意,下一个方法是私有

    private Location dfs(Set<Location> visitedAlready,Location current, Integer id){
       if(current.id == id)
          return current;
       visitedAlready.add(current); // instead of your boolean
       Location result = null;
       for(Location l : current.locations) {
          result = dfs(visitedAlready,l,id);
          if(result != null)
            break;
       }
       return result;
    }
    

    这是一个粗略的轮廓。如果你在Java chat与我联系,我会给予更多的投入,最终会有更多的光滑和可重复使用的东西。我没有声称上述DFS有效。但它很接近

答案 1 :(得分:1)

我不确定我是否完全理解,但在“退出”中做出了名字。数组成为子节点?不确定Exit对象上有哪些方法,或者这甚至是远程最有效的解决方案,而且不幸的是我现在无法检查语法。

这个想法是该方法接受一个节点,找到子节点,然后有效地递归地调用该节点上的方法“步行&#39;在层次结构中。

ArrarList<Location> allNodes

// Create children for the specified node
public void createChildNodes(node n){
    // Fetch all available exits
    for(Exit e : n.getExit()){
        // Iterate through all possible nodes
        for(tempNode : allNodes) {
            // Check if the 'exit' node matches one of the available nodes
            if(tempNode.getName().equals(e.getName()){
                // Match found, add it
                n.addChildNode(tempNode, tempNode.getDistance));

                // Check for children nodes of the temp node
                createChildNodes(tempNode);
            }
        }
    }
}