0

I am using a kind of dict in javascript and want to add an element to a list which is part of a kind of dictionary.

Here is the code snippet:

lines = [
    [1,2],
    [2,4],
    [2,3],
    [3,5]
];

nodes = [1,2,3,5,4];

function get_adjdict(nodes, lines) {
    // create an empty something
    adjacent = [];
    // loop over all elements on the array 'nodes'. The variable 'node' is supposed to take the various values of the elements in 'nodes'. So in this example this will be the values 1,2,3,5,4.
    for (var node in nodes) {
        // Add a key-value pair to the object/array/whatever named 'adjacent'. key is the value of 'node, the value is an empty array.
        adjacent.push({node:[]});
        // loop over all elements on the array 'lines'. The variable 'line' is supposed to take the various values of the elements in 'lines'. So in this example this will be the values [1,2], then [2,4] and so on
        for (var line in lines) {
            // checks if the value of 'node' is present in the array 'line'
            if (line.includes(node))  {
                // If the first element of the array 'line' has the same value as 'node'...
                if (line[0] == node) {
                    // ... add the second element of 'line' to 'adjacent[node]'
                    adjacent[node].push(line[1]) //ERROR
                } else {
                     // ... add the first element of 'line' to 'adjacent[node]'
                    adjacent[node].push(line[0])
                }

            }
        }
    }       
    return adjacent
}

The error is "TypeError: adjacent[node].push is not a function". How to do it then?

Expected data-structure:

adjdict = {
   1: [2],
   2: [1,4,3],
   3: [2,5],
   4: [2],
   5: [3]
}
14
  • not sure why you are using push and you should be pushing into the array.... you do not have .node Commented Jul 20, 2017 at 14:20
  • found that in various other SO answers. What else can I use? Commented Jul 20, 2017 at 14:20
  • Well it should be adjacent[node].node.push, but I htink that is also wrong since indexes start at zero. Commented Jul 20, 2017 at 14:20
  • @epascarello: Not sure this is correct. Why would I need two 'nodes' there? Commented Jul 20, 2017 at 14:22
  • Can explain what this algorithm intends to do? What is a kind of dict? Commented Jul 20, 2017 at 14:23

4 Answers 4

1

This what you are looking for:

var lines = [
    [1,2],
    [2,4],
    [2,3],
    [3,5]
];

var nodes = [1,2,3,4,5];

function get_adjdict (nodes, lines) {
    var adjacent = {};
    var node, line;

    for (var node_idx in nodes) {
        node = nodes[node_idx];
        adjacent[node] = [];

        for (var line_idx in lines) {
            line = lines[line_idx];

            if (line.includes(node))  {
                if (line[0] == node) {
                    adjacent[node].push(line[1]);
                } else {
                    adjacent[node].push(line[0]);
                }

            }
        }
    }       
    return adjacent;
}

get_adjdict(nodes, lines);

Bear in mind that, when using the construction for (var idx in arr) {} in JavaScript, idx is the key in the iteration, not the value.

for (var node in nodes) {

In the above code, node takes values 0 to 4. nodes[node] would take values 1 to 5 as I think you are expecting.

I always use the suffix _idx for this kind of variables. In this case, rename node to node_idx or node_index and you will see how everything falls into place.

Sign up to request clarification or add additional context in comments.

2 Comments

Hm yes, now it makes more sense, I am not very experienced in javascript! Thanks for the help, now I have to fugure out how to console-log these arrays (to check if the correct things are being done)...
for/in should not be used on arrays as it can iterate over inherited properties in some cases. Instead use .forEach().
0

You could just iterate the lines and create the object.

function add(o, k, v) {
    if (!o[k]) {
        o[k] = [];
    }
    if (o[k].indexOf(v) === -1) {
        o[k].push(v);
    }
}

var lines = [[1, 2], [2, 4], [2, 3], [3, 5]],
    result = {};

lines.forEach(function (l) {
    add(result, l[0], l[1]);
    add(result, l[1], l[0]);
});

console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }

Comments

0

You can simplify it with first mapping all of the indexes first and than use a simple reduce to build the object.

const lines = [
    [1,2],
    [2,4],
    [2,3],
    [3,5]
];

const nodes = [1,2,3,4,5];

// Make a lookup table where all the numbers appear
var lookup = lines.slice(0).reduce( (o, node, i) => {        
    o[node[0]] = o[node[0]] || []; // if we have not found it, set an array
    o[node[0]].push(node[1]); // add index value to the array
    o[node[1]] = o[node[1]] || []; // if we have not found it, set an array
    o[node[1]].push(node[0]); // add index value to the array
  return o  //return object for reduce
}, {})

var result = nodes.reduce( (o, n) => { //now loop over the nodes and make the `hash` table
  o[n] = lookup[n] || []
  return o
}, {})

console.log(result)

Comments

0

Don't use for/in loops on arrays. They can wind up iterating inherited properties as well as array items. for/in is for object iteration. Use .forEach() instead which will make working with the enumerated items much simpler (no indexes to manage).

Next, you are indicating that you want an object outputted, but you are creating adjacent as an array. Arrays inherit from objects, but they store their data differently.

Also, remember to formally declare your variables, otherwise they become global.

Lastly, don't rely on automatic semi-colon insertion. That can lead to bugs in certain edge cases.

If you follow good coding best practices, a lot of these kinds of issues just go away.

// Don't forget to use "var" to declare your variables otherwise
// they will become global.
var nodes = [1,2,3,4,5];

var lines = [
    [1,2],
    [2,4],
    [2,3],
    [3,5]
];

function get_adjdict(nodes, lines) {
  var adjacent = {};  // <-- You are asking for an object, not an array
    
  // Loop through the nodes array (use .forEach() to loop arrays)
  nodes.forEach(function(node){
    
    // Array to store results in
    var results = [];
    
    // Loop through the lines
    lines.forEach(function(line) {
      if (line.includes(node))  {
          if (line[0] === node) {
            results.push(line[1]);
          } else {
            results.push(line[0]);
          }
          // Set array as new property value
          adjacent[node] = results;
      }
     });      
  });
  // This needs to be outside of all loops, just before function terminates
  return adjacent; 
}

console.log(get_adjdict(nodes, lines));

7 Comments

Not quite the output I expect
@Alex You'll have to explain how you get to the result you are showing. Your algorithm is not clear. You show that you want an object returned, but your code creates an array.
Your algorithm is not clear. You show that you want an object returned, but your code creates an array.
An array is no object? In any case, if the code returns an object or an array is irrelevant. I just want to the function to work (just don't return anything...)
@Alex An array inherits from an object, but has a different data structure.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.