Home > front end >  Data wrangling a numaric 2d array to json-like nested object of true values
Data wrangling a numaric 2d array to json-like nested object of true values

Time:11-22

Relative novice to Javascript here. I am having issue wrapping my head around the order of operations I need.

I am trying to create a json-like parent-child object from a 2d adjacency matrix. For theses data I do not need to implement a recursive solution, as there are only parent-child nodes (no grand-parent nodes). Still, to my eye it has a lot of nesting, thus my confusion.

I have an array of objects that represent forward links of a node-link diagram I just care if the link exists, not the weights, it is of the form:

exampleRawLinks = [
            { n1: nan, n2: 1.2, n3: nan, n4: 1.3],
            { n1: nan, n2: nan, n3: nan, n4: 1.4],
            { n1: nan, n2: 1.5, n3: nan, n4: 1.4],
            { n1: nan, n2: nan, n3: 1.3, n4: nan],
            ]

The column and row indices are symmetric, i.e., (0,0) is the same node, (1,1) is the same node, etc.

Each node belongs to a parent region (numeric) and has a name(string), these data are encoded as columns at the beginning of the adjacency matrix, yielding:

nodeLinks = [
            {region: 1, node: "n1", n1: nan, n2: 1.2, n3: nan, n4: 1.3],
            {region: 1, node: "n2", n1: nan, n2: nan, n3: nan, n4: 1.4],
            {region: 2, node: "n3", n1: nan, n2: 1.5, n3: nan, n4: 1.4],
            {region: 3, node: "n4", n1: nan, n2: nan, n3: 1.3, n4: nan],
            ]

I am trying to achieve the form: (id(numeric) and group(numeric) have identical region information, targets are the true values on each row of adjacency matrix)

dataFinal = 
{children:
 [

  {id: 1, 
   children:
    [
      {
        id:"n1"
        group: 1
        targets:["n2","n4"]
      },
      {
        id:"n2"
        group: 1
        targets:[]
      },
    ]
  },

  {id: 2, 
   children:
    [
      {
        id:"n1"
        group: 2
        targets:["n2"]
      }
    ]
  },

  {id: 3, 
   children:
    [
      {
        id:"n1"
        group: 3
        targets:["n3"]
      }
    ]
  }
 ]
}

I have fiddled around with d3.groups(...) to handle the region grouping, resulting in a nested array. I suspect a solution is a nested .map, I just don't quite know how to approach implementing that. Beyond that there may be a .toNestedJson() method somewhere for adjacency matrices I am just not aware of despite my searching.

Thank you for any and all help.

UPDATE: ok, I am close, just unable to get the targets to map correctly (the below results in an empty array for targets, the slice is acting on too small of an array, so I am missing something):

dataFinal =  Object.entries(nodeLinks)
    .map(d => ({id: d[1].region, children: [({id: d[1].node, group: d[1].region, targets: Object.keys(Array(d[1]).slice(2,-1).map(obj => _.omitBy(obj, _.isNull)))})] })
        );

CodePudding user response:

const nodeLinks = [
  {region: 1, node: "n1", n1: NaN, n2: 1.2, n3: NaN, n4: 1.3},
  {region: 1, node: "n2", n1: NaN, n2: NaN, n3: NaN, n4: 1.4},
  {region: 2, node: "n3", n1: NaN, n2: 1.5, n3: NaN, n4: 1.4},
  {region: 3, node: "n4", n1: NaN, n2: NaN, n3: 1.3, n4: NaN},
];

// reshape `nodeLinks` items and map them to their regions and ids
const regions = {};
const nodes = {};
nodeLinks.forEach(node => {
  if(!(node.region in regions)) regions[node.region] = [];
  const item = {
    id: node.node,
    group: node.region,
    targets: []
  };
  regions[node.region].push(item);
  nodes[node.node] = item;
});

// now we have a complete list of possible target keys so add the targets
const nodeKeys = Object.keys(nodes);
nodeLinks.forEach(node => {
  nodes[node.node].targets = nodeKeys
    .map(key => (key in node && !Number.isNaN(node[key]) ? key : undefined))
    .filter(item => item !== undefined);
});

// build final object
const dataFinal = {
  children: Object.keys(regions).map(key => (
    {
      id: key,
      children: regions[key]
    }
  ))
};

console.log(dataFinal);

  • Related