Need to filter one array based on another array. Is there a util function in knock out ? else i need to go with javascript
First :
var obj1 = [{
"visible": "true",
"id": 1
}, {
"visible": "true",
"id": 2
}, {
"visible": "true",
"id": 3
}, {
"Name": "Test3",
"id": 4
}];
Second :
var obj2 = [ 2,3]
Now i need to filter obj1 based on obj2 and return items from obj1 that are not in obj2 omittng 2,3 in the above data (Comparison on object 1 Id)
output:
[{
"visible": "true",
"id": 1
}, {
"Name": "Test3",
"id": 4
}];
You can simply run through obj1 using filter and use indexOf on obj2 to see if it exists. indexOf returns -1 if the value isn't in the array, and filter includes the item when the callback returns true.
var arr = obj1.filter(function(item){
return obj2.indexOf(item.id) === -1;
});
With newer ES syntax and APIs, it becomes simpler:
const arr = obj1.filter(i => !obj2.includes(i.id))
Even if the answer provided by #Joseph are good, it can lead to performance issues if you have a very large array. The complexity is O(n^2), but it can be improved to O(n). Below I put the code I'd use to perform this task:
//create a map for storing object id
const map = new Map();
//add existing id from the array to the map
for (item of obj2) {
map.set(item.id, true);
}
//create a new array that contains all items that aren't included in the //map
//the map lookUp is O(1) complexity
const arr = obj1.filter(item => !map[item.id]);
In this way we avoid nested iteration and have O(n) complexity
To create your output array, create a function that will iterate through obj1 and populate a new array based on whether the id of every obj in the iteration exists in obj2.
var obj1 = [{
"visible": "true",
"id": 1
}, {
"visible": "true",
"id": 2
}, {
"visible": "true",
"id": 3
}, {
"Name": "Test3",
"id": 4
}];
var obj2 = [2,3]
var select = function(arr) {
var newArr = [];
obj1.forEach(function(obj) {
if obj2.indexOf(obj.id) !== -1 {
newArr.push(obj)
};
};
return newArr;
};
Related
I am having an object of the following kind:
var sourceObj = {
"feature1": [
{"id":"1","name":"abc","enabled":false,"type":"type1"},
{"id":"2","name":"xyz","enabled":false,"type":"type1"}
]
,
"feature2": [
{"id":"3","name":"lmn","enabled":true,"type":"type2"},
{"id":"4","name":"pqr","enabled":false,"type":"type2"}
]
}
Need to get converted to an array of objects of the following type:
var destArr = [
{ "feature_name":"feature1",
"feature_details":[
{"id":"1","name":"abc","enabled":false,"type":"type1"},
{"id":"2","name":"xyz","enabled":true,"type":"type1"}
]
},
{ "feature_name":"feature2",
"feature_details":[
{"id":"3","name":"lmn","enabled":true,"type":"type2"}
{"id":"4","name":"pqr","enabled":false,"type":"type2"}
]
}
]
I have tried the following approaches for conversion of source object to resultant array of objects and resultant array of objects back to the source object
//Converting source object to array of objects
let arr = Object.keys(sourceObj).map(key => {
return sourceObj[key];
})
converting array of objects back to source objetc
let obj = Object.assign({}, ...destArr.map(item => ({ [item.name]: item.value })));
You could use Object.entries to map everything in a single shot.
To go back to the original structure, you could use reduce against the generated array (see backToOriginalArray below)
var sourceObj = {
"feature1": [{
"id": "1",
"name": "abc",
"enabled": false,
"type": "type1"
},
{
"id": "2",
"name": "xyz",
"enabled": false,
"type": "type1"
}
],
"feature2": [{
"id": "3",
"name": "lmn",
"enabled": true,
"type": "type2"
},
{
"id": "4",
"name": "pqr",
"enabled": false,
"type": "type2"
}
]
};
// Step 1: use object.entries against the original object to build an array of objects.
var destArray = Object.entries(sourceObj).map(([key, value]) => ({
"feature_name": key,
"feature_details": value
}));
console.log(destArray);
// Step 2: use reduce against the generated array to get an object with the same structure of the original one.
var backToOriginalArray = destArray.reduce((acc, {feature_name, feature_details}) => (acc[feature_name] = feature_details, acc), {});
console.log(backToOriginalArray);
Map the Object.entries of your initial object:
var sourceObj = {
"feature1": [
{"id":"1","name":"abc","enabled":false,"type":"type1"},
{"id":"2","name":"xyz","enabled":false,"type":"type1"}
],
"feature2": [
{"id":"3","name":"lmn","enabled":true,"type":"type2"},
{"id":"4","name":"pqr","enabled":false,"type":"type2"}
]
};
const destArr = Object.entries(sourceObj).map(
([feature_name, feature_details]) => ({ feature_name, feature_details })
);
console.log(destArr);
To go the other way around, use Object.fromEntries:
const arr=[{feature_name:"feature1",feature_details:[{id:"1",name:"abc",enabled:!1,type:"type1"},{id:"2",name:"xyz",enabled:!1,type:"type1"}]},{feature_name:"feature2",feature_details:[{id:"3",name:"lmn",enabled:!0,type:"type2"},{id:"4",name:"pqr",enabled:!1,type:"type2"}]}];
const obj = Object.fromEntries(arr.map(
({ feature_name, feature_details }) => [feature_name, feature_details]
));
console.log(obj);
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 });
Suppose I have 2 json objects and I want to see whether there is a match/intersection based on the ids . These are the 2 objects:
obj= {
"container_copy": {
"card1": {
"id": "300",
"copy": "hello"
},
"card2": {
"id": "1000",
"type": "card"
},
"text": "bla"
}
}
and
items= [{id:"103",text:'hello'}, {id:"11",text:'yo'}]
I tried this:
let o1 = _.keyBy(_.values(obj), 'id');
let o2 = _.keyBy(items, 'id');
let inter = _.intersection(_.keys(o1), _.keys(o2));
let result = _.chain(o1)
.pick(inter)
.merge(_.pick(o2, inter))
.value();
What am I doing wrong?
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();
I am receiving real-time responses from the back-end that contains the following JSON (almost every second):
One Array:
{
"newUpdate": [
{
"id": "TP",
"val" : 3
},
{
"id": "TPE20",
"val" : 3
}]
}
Another array (after one second or less)
{
"newUpdate": [
{
"id": "CRK",
"val" : 24
},
{
"id": "TPE20",
"val" : 44
}]
}
I am getting the above JSON almost every second knowing that each time it comes with different values and id's, and the array itself does not have a specific size.
Well, what I want to do is to get the average of the values having the same key 'id'.
For example, for the above array, the average will be for TPE20 :
(3+44)/2 =23.2 (as it computes the average for the id : TPE20)
Then it should show it here (using JQuery for example) [Think of the real-time average value like in the stock market]
<div id="TPE20"></div>
Currently, using the below for loop, I print the JSON listed above:
for(var i in load.updates){
var id = load.newUpdate[i].id;
updatesMap[id] = load.newUpdate[i].value;
var valueOfID = newUpdate[id];
}
The challenge is that I am receiving a lot of arrays at once (1/sec), each array contains different "id" and "val", I really don't know how I can compute the average using the way I described above!
Just use an object with keys representing the ids of the array objects and the values as objects containing the count, total, and average of those ids.
When you receive a new array simply update the object:
function updateObj(arr) {
arr.forEach(function(el) {
var key = el.id;
obj[key] = obj[key] || { count: 0, total: 0, avg: 0 };
obj[key].count++;
obj[key].total += el.val;
obj[key].avg = obj[key].total / obj[key].count;
});
}
Here's a simulation with setInterval sending one array to the function each second, and then displaying the completed object in the console.
Does this help? It get the Average of the search term like you asked. It uses jquery $.each to iterate through the array
var newdata = [
{
"newUpdate": [
{
"id": "TP",
"val" : 3
},
{
"id": "TPE20",
"val" : 3
}]
},
{
"newUpdate": [
{
"id": "CRK",
"val" : 24
},
{
"id": "TPE20",
"val" : 44
}]
}
]
function getAverage(array, term){
var sum = 0, n = 0;
$.each(array, function(i, item){
n++
var arrs = item.newUpdate
$.each(arrs, function(d, place){
// console.log(d)
if (place.id == term){
sum +=place.val
}
})
})
return sum / n
}
document.write(getAverage(newdata, "TPE20"))
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.0/jquery.min.js"></script>
You can use Array.prototype.forEach() , create a private property at an object to store number of occasions unique property occurs within callback; pass each object individually to function in succession to maintain averages of properties at single object
var a = {
"newUpdate": [{
"id": "TP",
"val": 3
}, {
"id": "TPE20",
"val": 3
}]
};
var b = {
"newUpdate": [{
"id": "CRK",
"val": 24
}, {
"id": "TPE20",
"val": 44
}]
}
var avg = {};
function update(update) {
update.newUpdate.forEach(function(value, index) {
if (!avg[value.id] || !avg.hasOwnProperty(value.id)) {
avg["_" + value.id] = 1;
avg[value.id] = value.val / avg["_" + value.id];
} else {
++avg["_" + value.id];
avg[value.id] += value.val;
avg[value.id] = avg[value.id] / avg["_" + value.id];
}
});
return avg
}
console.log(update(a), update(b), avg)