MattStudios
MattStudios

Reputation: 43

Filter array by matching multiple values from another array

Objects are added to nodeArray[] once they are selected, some of the nodes are connected together and these links are stored in linkArray[], each object holds the source ID and the target ID of the node connection.

I need to filter linkArray[] so that it only returns objects where both source and target are in nodeArray[].

So far from browsing similar questions i have the following:

var linkArray = [{
  "conID": "100",
  "source": "10",
  "target": "11"
}, {
  "conID": "101",
  "source": "11",
  "target": "12"
}, {
  "conID": "102",
  "source": "12",
  "target": "13"
}, {
  "conID": "103",
  "source": "13",
  "target": "14"
}, {
  "conID": "386",
  "source": "55",
  "target": "32"
}];
var nodeArray = [{"id": "10"}, {"id": "11"}, {"id": "12"}];

function filterArray(array, filter) {
  var myArrayFiltered = [];
  for (var i = 0; i < array.length; i++) {
    for (var j = 0; j < filter.length; j++) {
      if (array[i].source === filter[j].id) {
        myArrayFiltered.push(array[i]);
      }
    }
  }
  return myArrayFiltered;
}

myArrayFiltered = filterArray(linkArray, nodeArray);

document.body.innerHTML = '<pre>'+ JSON.stringify(myArrayFiltered, null, 4) +'</pre>';

I have tried adding to the if statement to include the target ID as well but im not sure i am understanding it correctly.

The result is returning all links with source matching id in nodeArray[].

[
    {
        "conID": "100",
        "source": "10",
        "target": "11"
    },
    {
        "conID": "101",
        "source": "11",
        "target": "12"
    },
    {
        "conID": "102",
        "source": "12",
        "target": "13"
    }
]

What i need help with is filtering the array so that it only returns objects where both source and target ID are in nodeArray[].

The desired result after selecting node 10, 11 and 12 will be just 2 objects because node 13 is not in the selection.

[
    {
        "conID": "100",
        "source": "10",
        "target": "11"
    },
    {
        "conID": "101",
        "source": "11",
        "target": "12"
    }
]

Hopefully that is clear, Thanks!

Upvotes: 1

Views: 2611

Answers (5)

Nina Scholz
Nina Scholz

Reputation: 386654

You could use a hash table ids and test the values against.

var linkArray = [{ conID: "100", source: "10", target: "11" }, { conID: "101", source: "11", target: "12" }, { conID: "102", source: "12", target: "13" }, { conID: "103", source: "13", target: "14" }, { conID: "386", source: "55", target: "32" }],
    nodeArray = [{ id: "10" }, { id: "11" }, { id: "12" }],
    ids = nodeArray.reduce(function (o, a) {
        o[a.id] = true;
        return o;
    }, Object.create(null)),
    result = linkArray.filter(function (a) {
        return ids[a.source] && ids[a.target];
    });

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

ES6 with

  • Set for the wanted id,
  • Array#filter for getting only the items who match,
  • a keys array with the wanted properties for matching ['source', 'target'],
  • Array#every for checking all keys,
  • Set#has, for checking if the needed key is in the set.

var links = [{ conID: "100", source: "10", target: "11" }, { conID: "101", source: "11", target: "12" }, { conID: "102", source: "12", target: "13" }, { conID: "103", source: "13", target: "14" }, { conID: "386", source: "55", target: "32" }],
    nodes = [{ id: "10" }, { id: "11" }, { id: "12" }],
    keys = ['source', 'target'],
    result = links.filter(
        (s => a => keys.every(k => s.has(a[k])))(new Set(nodes.map(n => n.id)))
    );

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

Upvotes: 1

maazadeeb
maazadeeb

Reputation: 6112

You could try this

var linkArray = [{
  "conID": "100",
  "source": "10",
  "target": "11"
}, {
  "conID": "101",
  "source": "11",
  "target": "12"
}, {
  "conID": "102",
  "source": "12",
  "target": "13"
}, {
  "conID": "103",
  "source": "13",
  "target": "14"
}, {
  "conID": "386",
  "source": "55",
  "target": "32"
}];
var nodeArray = [{
  "id": "10"
}, {
  "id": "11"
}, {
  "id": "12"
}];

function filterArray(array, filter) {
  // Get all the required ids
  var ids = filter.map(function(f) {
    return f.id;
  });
  return array.filter(function(a) {
    // Check if both source and target are present in list of ids
    return ids.indexOf(a.source) !== -1 && ids.indexOf(a.target) !== -1;
  });
}

var myArrayFiltered = filterArray(linkArray, nodeArray);
console.log(myArrayFiltered)

UPDATE

Removed forEach + push and used filter.

Upvotes: 4

TedMeftah
TedMeftah

Reputation: 1915

var linkArray = [{
  "conID": "100",
  "source": "10",
  "target": "11"
}, {
  "conID": "101",
  "source": "11",
  "target": "12"
}, {
  "conID": "102",
  "source": "12",
  "target": "13"
}, {
  "conID": "103",
  "source": "13",
  "target": "14"
}, {
  "conID": "386",
  "source": "55",
  "target": "32"
}];
var nodeArray = [{"id": "10"}, {"id": "11"}, {"id": "12"}];

function filterArray(array, filter) {
  // map the nodeArray to an array of ids: ["10", "11", "12"]
  // could be done outside the function if needed
  var ids = nodeArray.map(function(item) {return item.id});

  // filter the array only returning itemes that have 'target' and 'source' in ids
  return array.filter(function(item) {
    return ids.includes(item.target) && ids.includes(item.source)
  })
}

myArrayFiltered = filterArray(linkArray, nodeArray);

document.body.innerHTML = '<pre>' + JSON.stringify(myArrayFiltered, null, 4) + '</pre>';

Upvotes: 0

Gaurav Chaudhary
Gaurav Chaudhary

Reputation: 1501

You can convert your nodeArray to key-value and use that to check both source and target of each object in linkArray

var linkArray = [{"conID": "100","source": "10","target": "11"}, {"conID": "101","source": "11","target": "12"}, {"conID": "102",   "source": "12",   "target": "13"}, {"conID": "103","source": "13","target": "14"}, {"conID": "386","source": "55","target": "32" }];

var nodeArray = [{"id": "10"}, {"id": "11"}, {"id": "12"}];

var nodes ={};
var myArrayFiltered = [];

for(var i =0; i<nodeArray.length;i++){
  nodes[nodeArray[i].id] = true;
}

for(var i =0; i<linkArray.length;i++){
  if(nodes[linkArray[i].source] && nodes[linkArray[i].target])
    myArrayFiltered.push(linkArray[i])
}

console.log(myArrayFiltered)

Upvotes: 0

Weedoze
Weedoze

Reputation: 13943

You can use Array#filter with the following condition condition

nodeArray.find(n=>n.id === e.source ) && nodeArray.find(n=>n.id === e.target)

The condition uses Array#find - It will return undefined if it doesn't find the node with the source or target id

var linkArray = [{"conID": "100","source": "10","target": "11"}, {"conID": "101","source": "11","target": "12"}, {"conID": "102",   "source": "12",   "target": "13"}, {"conID": "103","source": "13","target": "14"}, {"conID": "386","source": "55","target": "32" }]; 
var nodeArray = [{"id": "10"}, {"id": "11"}, {"id": "12"}];

var filteredArray = linkArray.filter(e=> nodeArray.find(n=>n.id === e.source ) && nodeArray.find(n=>n.id === e.target));

console.log(filteredArray);

Upvotes: 0

Related Questions