Compare array of objects to array of ids - javascript

Using jQuery, I would like to use an array of ids to find the objects inside the allObjects array that have the matching Id value.
var arrayOfIds = [1, 4, 5];
var allObjects = [{"Id":"1", "name":"aa"},{"Id":"2", "name":"bb"} ,{"Id":"3", "name":"cc"} ,{"Id":"4", "name":"dd"}, {"Id":"5", "name":"ee"}, {"Id":"6", "name":"ff"}, {"Id":"7", "name":"gg"}, {"Id":"8", "name":"hh"}, {"Id":"9", "name":"ii"}];
The result would equal:
[{"Id":"1", "name":"aa"}, {"Id":"4", "name":"dd"}, {"Id":"5", "name":"ee"}]
So far, I can only use the following to extract an individual object:
var result = $.grep(arrayOfIds, function(e) { return e.Id == 3; });
I feel as though the answer might be achieved by amending the above $.grep query somehow but can't figure it out.

You don't need jQuery for this. You can use Array.prototype.filter() to filter allObjects and Array.prototype.includes() to check if the objects Id property is in arrayOfIds:
allObjects.filter(x=> arrayOfIds.includes(Number(x.Id)))
See demo on JS Bin.

Best is you transform the array to an object itself:
function atoo(a)
{
var i, obj;
obj = {};
for (i = 0; i < a.length; i++)
{
obj[a[i].Id] = a[i];
}
return obj;
}
You can now access all items in the array through the object by simply addressing them as an index:
obj["4"]
returns the correct object that is also stored in the array under a[3].
There is no jQuery involved which should be considered a feature because it is a general solution to all kinds of these problems.
Using a filter (as in Array.prototype.filter()) is easier to write but also incurs in performance problems when you access the items very often or the array is very large. The above solution relies on the internal implementation of the object referencing which is as fast as you can wish for.

You can use filter() method like following.
var arrayOfIds = [1, 4, 5];
var allObjects = [{ "Id": "1", "name": "aa" }, { "Id": "2", "name": "bb" }, { "Id": "3", "name": "cc" }, { "Id": "4", "name": "dd" }, { "Id": "5", "name": "ee" }, { "Id": "6", "name": "ff" }, { "Id": "7", "name": "gg" }, { "Id": "8", "name": "hh" }, { "Id": "9", "name": "ii" }];
var result = $(allObjects).filter(function() { return arrayOfIds.indexOf(+this.Id) > -1 }).get();

Related

Array element comparison with Json response in Javascript

I have a Json response which looks like this.
[
{
"name": "name1",
"id": "1"
},
{
"name": "name2",
"id": "2"
},
{
"name": "name4",
"id": "4"
},
{
"name": "name5",
"id": "5"
}
]
I have another array called "a" which has only id [1,2,3,4,5]. Now i have to compare every element in the array with json response object id. For example, the first element of array "a" exists in json response object , then its respective name should be retrieved and stored in another new array called "b" -> [name1]. The second element of array "a" exists in json response object , then its respective name should be retrieved and appended in "b" array -> [name1,name2]. The third element of array "a" does not exists in json response object , hence no name. In this case, Instead of name, "0" should be appedned in b array for that id -> [name1,name2,0]. The fourth element of array "a" exists in json response object , then its respective name should be retrieved and appended in b array -> [name1,name2,0,name4]. The fifth element of array "a" exists in json response object , then its respective name should be retrieved and appended in b array -> [name1,name2,0,name4,name5].
I tried to implement this by the following code. But instead of [name1,name2,0,name4,name5] , I am getting [name1,name2,name4,name5,0]
for (var i = 0; i < a.length; i++) {
if (a.includes(jsonResponse[i].id)) {
b.push(jsonResponse[i].name);
}
else{
b.push("0");
}
}
You need to search for each element of b in the entire jsonResponse array, not just test the current index of jsonResponse.
Use .find() to find the element with the ID you're looking for.
let jsonResponse = [{
"name": "name1",
"id": "1"
},
{
"name": "name2",
"id": "2"
},
{
"name": "name4",
"id": "4"
},
{
"name": "name5",
"id": "5"
}
];
let a = [1, 2, 3, 4, 5];
let b = a.map(id => {
let found = jsonResponse.find(u => u.id == id);
return found ? found.name : "0";
});
console.log(b);
You can use Map collection to have O(1) while accessing to the desired element when you map your elements:
let mapResponse = new Map(jsonResponse.map(s=> [+s.id, s.name]));
const result = a.map(id => mapResponse.get(id) || '0')
An example:
let jsonResponse = [
{
"name": "name1",
"id": "1"
},
{
"name": "name2",
"id": "2"
},
{
"name": "name4",
"id": "4"
},
{
"name": "name5",
"id": "5"
}
];
let a = [1, 2, 3, 4, 5];
let mapResponse = new Map(jsonResponse.map(s=> [+s.id, s.name]));
const result = a.map(id => mapResponse.get(id) || '0')
console.log(result);

How to delete object from an array of objects having relations with each arrays?

This Object have relationship as: childOne > childTwo > childThree > childFour > childFive > childSix.
{
"parentObj": {
"childOne": [
{
"name": "A",
"id": "1"
},
{
"name": "B",
"id": "2"
}
],
"childTwo": [
{
"name": "AB",
"parent_id": "1",
"id": "11"
},
{
"name": "DE",
"parent_id": "2",
"id": "22"
}
],
"childThree": [
{
"name": "ABC",
"parent_id": "22",
"id": "111"
},
{
"name": "DEF",
"parent_id": "11",
"id": "222"
}
],
"childFour": [
{
"name": "ABCD",
"parent_id": "111",
"id": "1111"
},
{
"name": "PQRS",
"parent_id": "111",
"id": "2222"
}
],
"childFive": [
{
"name": "FGRGF",
"parent_id": "1111",
"id": "11111"
},
{
"name": "ASLNJ",
"parent_id": "1111",
"id": "22222"
},
{
"name": "ASKJA",
"parent_id": "1111",
"id": "33333"
}
],
"childSix": [
{
"name": "SDKJBS",
"parent_id": "11111",
"id": "111111"
},
{
"name": "ASKLJB",
"parent_id": "11111",
"id": "222222"
}
]
}
}
Is there any way to delete an item by ID and the objects which are associated with that particular ID should get deleted(i.e., If I do delete parentObj.childTwo[1], then all the related object beneath it should also gets deleted).
Looping manually is too bad code, and generate bugs. There must be better ways of dealing with this kind of problems like recursion, or other.
The data structure does not allow for efficient manipulation:
By nature objects have an non-ordered set of properties, so there is no guarantee that iterating the properties of parentObj will give you the order childOne, childTwo, childThree, ... In practice this order is determined by the order in which these properties were created, but there is no documented guarantee for that. So one might find children before parents and vice versa.
Although the id values within one such child array are supposed to be unique, this object structure does not guarantee that. Moreover, given a certain id value, it is not possible to find the corresponding object in constant time.
Given this structure, it seems best to first add a hash to solve the above mentioned disadvantages. An object for knowing a node's group (by id) and an object to know which is the next level's group name, can help out for that.
The above two tasks can be executed in O(n) time, where n is the number of nodes.
Here is the ES5-compatible code (since you mentioned in comments not to have ES6 support). It provides one example call where node with id "1111" is removed from your example data, and prints the resulting object.
function removeSubTree(data, id) {
var groupOf = {}, groupAfter = {}, group, parents, keep = { false: [], true: [] };
// Provide link to group per node ID
for (group in data) {
data[group].forEach(function (node) {
groupOf[node.id] = group;
});
}
// Create ordered sequence of groups, since object properties are not ordered
for (group in data) {
if (!data[group].length || !data[group][0].parent_id) continue;
groupAfter[groupOf[data[group][0].parent_id]] = group;
}
// Check if given id exists:
group = groupOf[id];
if (!group) return; // Nothing to do
// Maintain list of nodes to keep and not to keep within the group
data[group].forEach(function (node) {
keep[node.id !== id].push(node);
});
while (keep.false.length) { // While there is something to delete
data[group] = keep.true; // Delete the nodes from the group
if (!keep.true.length) delete data[group]; // Delete the group if empty
// Collect the ids of the removed nodes
parents = {};
keep.false.forEach(function (node) {
parents[node.id] = true;
});
group = groupAfter[group]; // Go to next group
if (!group) break; // No more groups
// Determine what to keep/remove in that group
keep = { false: [], true: [] };
data[group].forEach(function (node) {
keep[!parents[node.parent_id]].push(node);
});
}
}
var tree = {"parentObj": {"childOne": [{"name": "A","id": "1"},{"name": "B","id": "2"}],"childTwo": [{"name": "AB","parent_id": "1","id": "11"},{"name": "DE","parent_id": "2","id": "22"}],"childThree": [{"name": "ABC","parent_id": "22","id": "111"},{"name": "DEF","parent_id": "11","id": "222"}],"childFour": [{"name": "ABCD","parent_id": "111","id": "1111"},{"name": "PQRS","parent_id": "111","id": "2222"}],"childFive": [{"name": "FGRGF","parent_id": "1111","id": "11111"},{"name": "ASLNJ","parent_id": "1111","id": "22222"},{"name": "ASKJA","parent_id": "1111","id": "33333"}],"childSix": [{"name": "SDKJBS","parent_id": "11111","id": "111111"},{"name": "ASKLJB","parent_id": "11111","id": "222222"}]}}
removeSubTree(tree.parentObj, "1111");
console.log(tree.parentObj);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Sure, the function you use to delete an entry should FIRST recurse, which means run itself on the linked entry, unless there is none. So, in psuedocode
function del(name, index)
{
if parent[name][index] has reference
Then del(reference name, reference ID)
Now del parent[name][index]
}
No loop needed.
And since we stop if there is no reference, we do not recurse forever.
Not sure what it is you want but maybe this will work:
const someObject = {
"parentObj": {
"childOne": [
{
"name": "A",
"id": "1"
},
{
"name": "B",
"id": "2"
}
],
"childTwo": [
{
"name": "AB",
"childOne": "1",
"id": "11"
},
{
"name": "DE",
"childOne": "2",
"id": "22"
}
]
}
};
const removeByID = (key,id,parent) =>
Object.keys(parent).reduce(
(o,k)=>{
o[k]=parent[k].filter(
item=>
!(Object.keys(item).includes(key)&&item[key]===id)
);
return o;
},
{}
);
const withoutID = Object.assign(
{},
someObject,
{ parentObj : removeByID("childOne","1",someObject.parentObj) }
);
console.log(`notice that childTwo item with childOne:"1" is gone`);
console.log("without key:",JSON.stringify(withoutID,undefined,2));
const otherExample = Object.assign(
{},
someObject,
{ parentObj : removeByID("childOne","2",someObject.parentObj) }
);
console.log(`notice that childTwo item with childOne:"2" is gone`);
console.log("without key:",JSON.stringify(otherExample,undefined,2));
const both = Object.assign(
{},
someObject,
{ parentObj : removeByID("childOne","1",otherExample.parentObj) }
);
console.log(`notice that childTwo items with childOne are both gone`);
console.log("without key:",JSON.stringify(both,undefined,2));

convert integer to array of object.

var items = [
{ "id": 1, "label": "Item1" },
{ "id": 2, "label": "Item2" },
{ "id": 3, "label": "Item3" }
];
I have this array of objects named 'items'. I get itemselected = 3 from the database.
I need to convert this 3 into the following form.
0:Object
id:3
label:"Item3"
Similarly, if i have a value 2 coming from the database, i should convert it to
0:Object
id:2
label:"Item2"
Can anyone please let me hint of how to get it solved. i am not here to get the answer. These questions are quite tricky for me and i always fail to get the logic right. Any advice on how to master this conversions will be of great help. thanks.
Since you tagged underscore.js, this should be very easy:
var selectedObject = _.findWhere(items, {id: itemselected});
Using ECMA6, you can achieve the same using .find method on arrays:
let selectedObject = items.find(el => el.id === itemselected);
With ECMA5, you can use filter method of arrays. Be careful that filter returns undefined if no element has been found:
var selectedObject = items.filter(function(el) { return el.id === itemselected});
Use jquery $.map function as below
$.map(item, function( n, i ) { if(n["id"] == 3) return ( n );});
Based on the title of your question: «convert integer to array of object». You can use JavaScript Array#filter.
The filter() method creates a new array with all elements that
pass the test implemented by the provided function.
Something like this:
var items = [{
"id": 1,
"label": "Item1"
},
{
"id": 2,
"label": "Item2"
},
{
"id": 3,
"label": "Item3"
}
];
var value = 2;
var result = items.filter(function(x) {
return x.id === value;
});
console.log(result); // Prints an Array of object.
Try this
var obj = {} ;
items = [
{ "id": 1, "label": "Item1" },
{ "id": 2, "label": "Item2" },
{ "id": 3, "label": "Item3" }
];
items.map(function(n) { obj[n.id] = n });

AngularJS search filter in array into object

I look ID in an array of objects JSON.
Example JSON:
{
"Przydzial": [{
"M": "Cos",
"Przydzialt": [{
"Name": "",
"Przydz": "tach_1",
"Cos": "Pod",
"Ha": "20",
"ID": "94"
}, {
"Name": "B_K",
"Przydz": "lea",
"Cos": "Chea",
"HA": "8",
"ID": "78"
}
}]
}]
}
Use in controller
var foo = { //my json };
var nowy = $filter('filter')(foo.Przydzialt, { ID:78});
result:
console.log(nowy); // undefined
json is correct - validated in JSLint.
As "$foo.Przydzial" is an array of objects, where every object has its "Przydzialt" attribute, you should execute $filter in a loop:
var newArray;
angular.forEach($foo.Przydzial, function (el) {
newArray = $filter('filter')(el.Przydzialt, {ID: 78});
console.log(newArray);
});

JQuery $.extend doesn't work like I would expect: How to code this correctly?

Here is the JQuery extend page.
What I would expect this to do is take two arrays, join them together and create uniform properties for each resulting array element. How do I get this to work as expected?
var a = [];
a.push({ "id": 1, "text": "one" });
a.push({ "id": 2, "text": "two" });
a.push({ "id": 3, "text": "three" });
var b = [];
b.push({"id":3 , "selected":true});
var c = [];
$.extend(c,a,b);
What I would expect is that the resulting array would include:
{ "id": 1, "text": "one", "selected": false }
{ "id": 2, "text": "two", "selected": false }
{ "id": 3, "text": "three", "selected": true }
but instead it seems to just copy the first array over top of the second:
{ "id": 3, "text": null, "selected": true }
{ "id": 2, "text": "two" }
{ "id": 3, "text": "three" }
The documentation includes:
When we supply two or more objects to $.extend(), properties from all of the objects are added to the target object.
What am I doing wrong, or how would I accomplish this otherwise?
EDIT: Jball's suggestion implemented:
var a = [];
a.push({ "id": 1, "text": "one" });
a.push({ "id": 2, "text": "two" });
a.push({ "id": 3, "text": "three" });
var b = [];
b.push({ "id": 3, "selected": true });
var c = [];
for (var index = 0; index < a.length; index++) {
var tempresult = {};
var tempb = b.filter(
function (ele, idx, collection) {
return (collection[idx].id == index + 1);
});
if (tempb.length == 0)
tempb = [{ "id": index + 1, "selected": false }];
$.extend(tempresult, a[index], tempb[0]);
c.push(tempresult);
}
produces:
[{"id":1, "selected":false, "text": "one"},
{"id":2, "selected":false, "text": "two"},
{"id":3, "selected":true, "text": "three"}]
That's the answer. Now I wonder if it can be cleaned up a bit.
I'm not sure if you noticed it, but the $.extend() function is intended for properties of objects, not elements of an array.
It seems like you need to create a function to loop through the arrays, and call $.extend() on matching elements to get your desired result. You would have to decide whether you want to add or ignore non-matching elements from the second array.
The problem is that jQuery has no idea what elements in your array are matching, and so matches them by index, though I'm not sure why the result for the first item has "text": "three" instead of "text": "one", unless it is attempting to match by the individual items properties after it does an $.extend() based on index.

Categories

Resources