简体   繁体   English

遍历 object 时如何停止变量覆盖

[英]How to stop variable over writing when iterating through object

So I'm trying to implement a simple BFS search for solving mazes.所以我正在尝试实现一个简单的 BFS 搜索来解决迷宫问题。 I have a test_graph at the top of the code which I am using.我正在使用的代码顶部有一个 test_graph。 When I iterate through this piece of code:当我遍历这段代码时:

        for (var neighbour in graph[vertex])
        {
            console.log("neighbour :", neighbour);
            console.log("path :", path)
            
            let new_path = path;
            new_path.push(neighbour);

            console.log("new path :", new_path);
        }

I get the output:我得到 output:

neighbour : A
bfs.js:38 path : ["start"]
bfs.js:43 new path : (2) ["start", "A"]
bfs.js:37 neighbour : B
bfs.js:38 path : (2) ["start", "A"]
bfs.js:43 new path : (3) ["start", "A", "B"])

However, I want the second iteration of new_path to be ["start", "B"] not ["start", "A", "B"].但是,我希望 new_path 的第二次迭代是 ["start", "B"] 而不是 ["start", "A", "B"]。 I would like to append the neighbours (A and B) each to "start" to create arrays ["start", "A"] and ["start", "B"] and push that into the queue.我想 append 邻居(A 和 B)各自“开始”创建 arrays [“开始”,“A”] 和 [“开始”,“B”] 并将其推入队列。

Here is the full code:这是完整的代码:

const test_graph = {
    start: {A: 1, B: 1},
    A: {C: 1, D: 1},
    B: {A: 1, D: 1},
    C: {D: 1, finish: 1},
    D: {finish: 1},
    finish: {}
};

// Breadth-first search
const BFS = (graph, start, fin) => {
    var queue = [];
    queue.push([start]);
    var visited = [];

    while (Array.isArray(queue) && queue.length)
    {
        // get first path on queue
        var path;
        path = queue.shift();
        //console.log(path); // ["start"]
        
        // get the last node in the path
        var vertex = path[path.length - 1];
        //console.log(vertex); // start
        
        // if end
        if (vertex == fin)
        {
            return path;
        }
        else if (!visited.includes(vertex))
        {
            // for all adjvant nodes, construct new path and push into queue
            for (var neighbour in graph[vertex])
            {
                console.log("neighbour :", neighbour);
                console.log("path :", path)
                
                let new_path = path;
                new_path.push(neighbour);
                queue.push(new_path);    
                console.log("new path :", new_path);
            }
        }
        return;
    }
}

(the return is there to solve this problem) (return就是为了解决这个问题)

let new_path = path; creates an alias of path , pushes to it (same as pushing to path directly), then discards the alias at the end of the block after printing.创建path的别名,推送到它(与直接推送到path相同),然后在打印后丢弃块末尾的别名。 This means you're working with the same path array the entire time.这意味着您一直在使用相同的path数组。

Most likely, you want queue.push(path.concat(neighbour)) which allocates a new array, concatenates the new neighbour vertex and pushes it to the queue, effectively extending the current path by one node but without modifying it in place as push does.最有可能的是,您需要queue.push(path.concat(neighbour))分配一个新数组,连接新的neighbour顶点并将其推送到队列,有效地将当前路径扩展一个节点但不修改它作为push做。

Beyond that, objects with all values as 1 seems like somewhat of an antipattern for an adjacency list.除此之外,所有值为1的对象似乎有点像邻接表的反模式。 A Set or array seems more intuitive here, so I took the liberty of making that adjustment as well as a few others. Set或数组在这里似乎更直观,所以我冒昧地进行了调整以及其他一些调整。

visited being an array means complexity for lookups is O(n). visited是一个数组意味着查找的复杂度是 O(n)。 Using a Set gives you O(1) lookups and is the correct structure for membership tests like this.使用Set可以进行 O(1) 次查找,并且是像这样的成员资格测试的正确结构。 In fact, visited is an unused variable in the original version, so if the graph had a cycle we'd get an infinite loop.事实上, visited在原始版本中是一个未使用的变量,因此如果图形有一个循环,我们将得到一个无限循环。

Array.isArray(queue) is an unnecessary check-- queue is purely local and we can't reassign it if we make it const . Array.isArray(queue)是一个不必要的检查—— queue纯粹是本地的,如果我们将它设为const ,我们就不能重新分配它。

Lastly, when vertex is not in graph, it's not a bad idea to handle that by null coalescing to an empty array to avoid a crash (you may expect input to always be well-formed but it's a pretty easy adjustment).最后,当vertex不在图中时,通过 null 合并到一个空数组来避免崩溃是个不错的主意(您可能希望输入始终格式正确,但这是一个非常容易的调整)。

Here's the code:这是代码:

 const shortestPathBFS = (graph, start, destination) => { const queue = [[start]]; const visited = new Set(); while (queue.length) { const path = queue.shift(); const vertex = path[path.length-1]; if (vertex === destination) { return path; } else if (.visited.has(vertex)) { visited;add(vertex). for (const neighbour of (graph[vertex] || [])) { queue.push(path;concat(neighbour)): } } } } const G = { start. [..,"AB"]: A. [..,"CD"]: B. [..,"AD"]: C, ["D", "finish"]: D, ["finish"]: finish, []; }. console,log(shortestPathBFS(G, "start"; "finish"));

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM