I have an array of objects , each object have key and value .I want if object have same keys then their values shoud be comma sepated of all the values of same key.
my html code:
<p ng-repeat="item in allOptions" class="item" id="{{item.id}}">
{{item.id}} <input type="checkbox" ng-change="sync(bool, item)" ng-model="bool" > {{item}} Selected: {{bool}}
</p>
and my controller code is :
$scope.allOptions = [
{
"id": "1",
"data": "one",
},
{
"id": "1",
"data": "two",
},
{
"id": "2",
"data": "three",
},
];
$scope.data = [
];
$scope.sync = function(bool, item){
if(bool){
// add item
$scope.data.push(item);
} else {
// remove item
for(var i=0 ; i < $scope.data.length; i++) {
if($scope.data[i] == item.id){
$scope.data.splice(i,1);
}
}
}
};
In data array i have objects ,if we select same key of objects (same id value )then i want
{
"id": "1",
"data": "one","two",
}
var myData = [{
"id": "1",
"data": "one",
},{
"id": "1",
"data": "two",
},{
"id": "2",
"data": "three",
}];
var output = [];
//Iterating each element of the myData
myData.forEach(o => {
//Checking the duplicate value and updating the data field
let temp = output.find(x => {
if (x && x.id === o.id) {
x.data += ", " + o.data;
return true;
}
});
if(!temp)
output.push(o);
});
console.log(output);
I think, easiest way to make it would be like:
z = [
{
"id": "1",
"data": "one",
},
{
"id": "1",
"data": "two",
},
{
"id": "2",
"data": "three",
},
];
And immediate code:
var result = {};
var groupedO = {};
for(a in z){
var id = z[a].id;
var data = z[a].data;
if(groupedO[id] && groupedO[id].data){
groupedO[id].data = groupedO[id].data + ',' + data;
} else {
groupedO[id] = {data:data};
}
}
for(ind in groupedO) {
var el = groupedO[ind];
if(el.data.split(',').length > 1) { // here we take only last those, where many datas grouped in
result.id = ind;
result.data = el.data;
}
}
After this, result will look like:
{ id: "1", data: "one,two" }
If you use jQuery, then you can use $.extend() function in this code if you don't want to put reference to the object item in array hash. This means that if you change the object item in array hash, then object item in array myData change too. To avoid this, use $.extend() function.
var myData = [
{
"id": "1",
"data": "one",
},
{
"id": "1",
"data": "two",
},
{
"id": "2",
"data": "three",
},
]; // this will be your input data
function filterData(collection) {
var hash = {};
var result = [];
collection.forEach(function (item) {
if (hash[item.id]) {
hash[item.id].data += ', ' + item.data;
}
else {
hash[item.id] = $.extend({}, item);
}
});
for (var i in hash) {
result.push(hash[i]);
}
return result;
}
var filteredData = filterData(myData); //your filtered data
You can do this in following manner:
var myData = [{
"id": "1",
"data": "one",
},
{
"id": "1",
"data": "two",
},
{
"id": "2",
"data": "three",
},
]; // this will be your input data
function filterData(collection) {
var hash = {};
var result = [];
collection.forEach(function(item) {
if (hash[item.id]) {
hash[item.id].data += ', ' + item.data;
} else {
hash[item.id] = item;
}
});
for (var i in hash) {
result.push(hash[i]);
}
return result;
}
console.log(
filterData(myData) //your filtered data
)
Related
I have an array with objects, like the following.
b = {
"issues": [{
"fields": {
"status": {
"id": "200",
"name": "Backlog"
}
}
}, {
"fields": {
"status": {
"id": "202",
"name": "close"
}
}
}, {
"fields": {
"status": {
"id": "201",
"name": "close"
}
}
}]
};
I want to count how many issues have status close, and how many have backlog. I'd like to save the count in a new array as follows.
a = [
{Name: 'Backlog', count: 1},
{Name: 'close', count: 2}
];
I have tried the following.
b.issues.forEach(function(i) {
var statusName = i.fields.status.name;
if (statusName in a.Name) {
a.count = +1;
} else {
a.push({
Name: statusName,
count: 1
});
}
});
That however doesn't seem to be working. How should I implement this?
This is a perfect opportunity to use Array#reduce. That function will take a function that is applied to all elements of the array in order and can be used to accumulate a value. We can use it to accumulate an object with the various counts in it.
To make things easy, we track the counts in an object as simply {name: count, otherName: otherCount}. For every element, we check if we already have an entry for name. If not, create one with count 0. Otherwise, increment the count. After the reduce, we can map the array of keys, stored as keys of the object, to be in the format described in the question. See below.
var b = {
"issues": [{
"fields": {
"status": {
"id": "200",
"name": "Backlog"
}
}
}, {
"fields": {
"status": {
"id": "202",
"name": "close"
}
}
}, {
"fields": {
"status": {
"id": "201",
"name": "close"
}
}
}]
};
var counts = b.issues.reduce((p, c) => {
var name = c.fields.status.name;
if (!p.hasOwnProperty(name)) {
p[name] = 0;
}
p[name]++;
return p;
}, {});
console.log(counts);
var countsExtended = Object.keys(counts).map(k => {
return {name: k, count: counts[k]}; });
console.log(countsExtended);
.as-console-wrapper {
max-height: 100% !important;
}
Notes.
Array#reduce does not modify the original array.
You can easily modify the function passed to reduce to for example not distinguish between Backlog and backlog by changing
var name = c.fields.status.name;
into
var name = c.fields.status.name.toLowerCase();
for example. More advanced functionality can also easily be implemented.
Using ES6 Arrow functions you can do it with minimum syntax
var b = {
"issues": [{
"fields": {
"status": {
"id": "200",
"name": "Backlog"
}
}
}, {
"fields": {
"status": {
"id": "202",
"name": "close"
}
}
}, {
"fields": {
"status": {
"id": "201",
"name": "close"
}
}
}]
};
var countOfBackLog = b.issues.filter(x => {
return x.fields.status.name === "Backlog"
}).length
var countOfClose = b.issues.filter(x => {
return x.fields.status.name === "close"
}).length
a =[{Name: 'Backlog', count : countOfBackLog}, {Name: 'close', count : countOfClose}]
More about arrow functions here
You can write like this. It is dynamic.
var a = {};
for(var key in b["issues"]){
if(!a.hasOwnProperty(b["issues"][key].fields.status.name)){
a[b["issues"][key].fields.status.name] = 1;
}else{
a[b["issues"][key].fields.status.name] = a[b["issues"][key].fields.status.name]+1;
}
}
var c = [];
for(var key1 in a){
c.push({
name : key1,
count : a[key1]
});
}
Something like this should do the trick. Simply iterate over your data, keep 2 counters with the number of each type of issue, and create the data format you want in the end. Try it live on jsfiddle.
var b = {
"issues": [{
"fields": {
"status": {
"id": "200",
"name": "Backlog"
}
}
}, {
"fields": {
"status": {
"id": "202",
"name": "close"
}
}
}, {
"fields": {
"status": {
"id": "201",
"name": "close"
}
}
}]
};
var data = [];
for(var issue of b.issues){
var entryFound = false;
var tempObj = {
name: issue.fields.status.name,
count: 1
};
for(var item of data){
if(item.name === tempObj.name){
item.count++;
entryFound = true;
break;
}
}
if(!entryFound){
data.push(tempObj);
}
}
console.log(data);
I am looking to create hashmap like array which will contain key and value derived from another array which has nested objects.
so i am trying the following code.
var testhash={},data=[
{
"yang_type": "container",
"name": "c1",
"value": "",
"children": [
{
"yang_type": "container",
"name": "c2",
"value": "",
"children": [
{
"yang_type": "list",
"name": "Car",
"value": "",
"children": [
{
"yang_type": "leaf",
"name": "wheels",
"value": "",
"children": [
{
"name": "max-elements",
"value": "4",
"children": [],
"yang_type": ""
}
]
}
]
},
{
"yang_type": "",
"name": "text",
"value": "4",
"children": []
}
]
}
]
}
];
var k='';
function loop1(a, depth) {
var l,s='';
if(depth){s += '/';}
k=k+a.yang_type+a.name+a.value;
v=Array(depth + 1).join(s) + a.yang_type+a.name+a.value;
testhash.push(k:v);
//console.log(l);
//console.log(Array(depth + 1).join("/") + a.yang_type,a.name,a.value);
//hashServiceParams.push(Array(depth + 1).join("/") + a.yang_type,a.name,a.value);
Array.isArray(a.children) && a.children.forEach(function(child) {
loop1(child, depth + 1);
});
}
console.log(testhash);
The output, I am expecting is
{"containerc1":*,"containerc2":"containerc1/containerc2","listcar":"containerc1/containerc2/listcar","leafwheels":"containerc1/containerc2/listcar/leafwheels","max-elements":"containerc1/containerc2/listcar/leafwheels/max-elements","text4":"containerc1/text4"}
The above array will act as an hash map that contains key and value , where value stores the part of that data in the tree structure.
my code just calculates the depth and adds / to each level it moves down but i expect the output to be as shown above. Any recommendation coders ?
The following should do the trick (use either version according to your needs):
ECMAScript 6:
function parseData(data, prefix) {
let result = {};
data.forEach(o => {
const key = `${o.yang_type}${o.name}`;
result[key] = prefix ? `${prefix}/${key}` : '*';
if (o.children) {
const newPrefix = prefix ? `${prefix}/${key}` : key;
result = Object.assign(result, parseData(o.children, newPrefix));
}
});
return result;
}
ECMAScript 5:
function shallowMerge(obj1,obj2){
var obj3 = {};
for (var attrname in obj1) { obj3[attrname] = obj1[attrname]; }
for (var attrname in obj2) { obj3[attrname] = obj2[attrname]; }
return obj3;
}
function parseData(data, prefix) {
var result = {};
data.forEach(function (o) {
var key = '' + o.yang_type + o.name;
result[key] = prefix ? prefix + '/' + key : '*';
if (o.children) {
var newPrefix = prefix ? prefix + '/' + key : key;
result = shallowMerge(result, parseData(o.children, newPrefix));
}
});
return result;
}
In order to use it you simply need to do the following:
let testhash = parseData(data);
This will populate the testHash with the result you need.
I have below json array structure.. How can i get the key and value of each of the records json object?
{
"records": [{
"cfsub_2": "1",
"cf_7": "1/3/2016",
"cf_1": "Clinic San",
"cf_2": "Fever",
"cf_3": "56.60",
"cfe_8": "dsf4334"
}, {
"cfsub_2": "2",
"cf_7": "3/3/2016",
"cf_1": "Clinic Raju",
"cf_2": "braces",
"cf_3": "183.50",
"cfe_8": "fresr4"
}]
}
My expected output is to get the key and value... below as example:
<b>key</b> : cf_1, <b>value</b> : Clinic San
I have tried to loop in the records, but since i don't know the key, so i unable to get the value..
for (var z in records)
{
var value = records[z].cf_1;
alert(value);
}
//i don't know the key here.. i want to get the key and value
The full JSON structure is as below:
{
"forms": [{
"id": 1,
"records": [{
"cfsub_2": "1",
"cf_7": "1/3/2016",
"cf_1": "Clinic San",
"cf_2": "Fever",
"cf_3": "56.60",
"cfe_8": "dsf4334"
}, {
"cfsub_2": "2",
"cf_7": "3/3/2016",
"cf_1": "Clinic Raju",
"cf_2": "braces",
"cf_3": "183.50",
"cfe_8": "fresr4"
}]
}, {
"id": 7,
"records": [{
"cf_31": "27/3/2016",
"cf_32": "Singapore",
"cf_33": "dfd555",
"cfe_34": ""
}]
}, {
"id": 11,
"records": [{
"cfsub_10": "9",
"cf_9": "25/3/2016",
"cf_10": "256.50",
"cfe_11": "dfg44"
}]
}]
}
Hope this one is helpful for you.
$.each(value.forms, function(index,array){
$.each(array.records, function(ind,items){
$.each(items, function(indo,itemso){
alert( "Key -> "+indo + " : values -> " + itemso );
});
});
});
var getKeys = function (arr) {
var key, keys = [];
for (i = 0; i < arr.length; i++) {
for (key in arr[i]) {
if (arr[i].hasOwnProperty(key)) {
keys.push(key);
}
}
}
return keys;
};
Below are my two arrays .I want to compare them and the resultant array should contain the updated values.Id's are common..
The arrays spans to n levels ie., there is no fixed levels..
The first array ie., the array before updation..
var parentArray1=[
{
"id": 1,
"name": "test",
"context": [
{
"id": 1.1,
"name": "test 1.1"
}
]
},
{
"id": 2,
"name": "test"
},
{
"id": 3,
"name": "test",
"context": [
{
"id": 3.1,
"name": "test 3.1"
}
]
},
{
"id": 4,
"name": "test"
}
]
The operations that i performed are
1.Adding a new Item
2.Updating an existing item
As a result of these two operations the changed values I will be getting in a different array..
ie.,
var changedArray=
[
{
"id": 1,
"name": "test1",
"context": [
{
"id": 1.1,
"name": "Changed test 1.1"
}
]
},
{
"id": 5,
"name": "test5"
}
]
Now I have written a generic function that loops through the parentArray1 and using the unique propertiesI need to either add a new item,if the item is there in the changedArray or update an existing item at any level
The resultant array should be ..
[
{
"id": 1,
"name": "test",
"context": [
{
"id": 1.1,
"name": "Changed test 1.1"
}
]
},
{
"id": 2,
"name": "test"
},
{
"id": 3,
"name": "test",
"context": [
{
"id": 3.1,
"name": "test 3.1"
}
]
},
{
"id": 4,
"name": "test"
},
{
"id": 5,
"name": "test5"
}
]
Generic function:
compareArray(parentArray1, changedArray, ["id"]);
function compareArray(array1, array2, propertyArray) {
var newItem = new Array();
array2.map(function(a1Item) {
array1.map(function(a2Item) {
/ If array loop again /
if (a2Item.constructor === Array) {
compareArray(a2Item, a1Item)
} else {
/ loop the property name to validate /
propertyArray.map(function(property) {
if (a2Item[property]) {
if (a2Item[property] === a1Item[property]) {
a2Item = a1Item
} else {
var isAvailable = _.find(newItem, function(item) {
return item[property] === a1Item[property]
})
if (!isAvailable) {
newItem.push(a1Item);
}
}
}
})
}
});
});
/ Insert the new item into the source array /
newItem.map(function(item) {
array1.push(item);
});
console.log("After Compare : " + array1);
}
I suggest to use a temporary object for the reference to the id and update if exist or push if not exist.
var parentArray1 = [{ "id": 1, "name": "test", "context": [{ "id": 1.1, "name": "test 1.1" }] }, { "id": 2, "name": "test" }, { "id": 3, "name": "test", "context": [{ "id": 3.1, "name": "test 3.1" }] }, { "id": 4, "name": "test" }],
changedArray = [{ "id": 1, "name": "test1", "context": [{ "id": 1.1, "name": "Changed test 1.1" }] }, { "id": 5, "name": "test5" }];
function insert(array, data) {
function iter(array) {
array.forEach(function (a) {
if (!('id' in a)) {
return;
}
if (o[a.id] !== a) {
o[a.id] = a;
}
Object.keys(a).forEach(function (k) {
Array.isArray(a[k]) && iter(a[k]);
});
});
}
var o = {};
iter(array);
data.forEach(function (a) {
if (o[a.id]) {
Object.keys(a).forEach(function (k) {
o[a.id][k] = a[k];
});
return;
}
array.push(a);
});
}
insert(parentArray1, changedArray);
document.write('<pre>' + JSON.stringify(parentArray1, 0, 4) + '</pre>');
This is what I came up with:
function sameKeys(o1, o2, keys) {
for (var i = 0; i < keys.length; i++) {
var key = keys[i];
if (!o1.hasOwnProperty(key) || !o2.hasOwnProperty(key))
throw 'compared objects do not have the key ' + key;
if (o1[key] !== o2[key])
return false;
}
return true;
}
function isNothing(o) {
return typeof(o) === 'undefined' || o === null;
}
// this does not work if objects have functions as properties
function clone(o) {
if (isNothing(o))
return o;
return JSON.parse(JSON.stringify(o));
}
function extend(o1, o2, keys) {
if (isNothing(o2))
return;
if (isNothing(o1))
throw ('first parameter cannot be empty');
if (typeof(o1) != 'object' || typeof(o2) != 'object')
throw ('extend only works on objects');
Object.keys(o2).forEach(function (key) {
var newVal = o2[key];
if (o1.hasOwnProperty(key)) {
if (isNothing(newVal)) {
delete o1[key];
} else
if (Array.isArray(newVal)) {
compareArray(o1[key], newVal, keys);
} else {
switch (typeof(newVal)) {
case 'object':
extend(o1[key], newVal, keys);
break;
case 'boolean':
case 'number':
case 'string':
o1[key] = newVal;
break;
default:
throw 'not supported property type: ' + typeof(newVal);
}
}
} else {
o1[key] = clone(newVal);
}
});
}
function removeFromArray(arr, ids, keyArray) {
var indexes = [];
var it1s = arr.forEach(function (it, idx) {
if (sameKeys(ids, it, keyArray)) {
indexes.push(idx);
} else {
Object.keys(it).forEach(function (key) {
var newVal = it[key];
if (Array.isArray(newVal)) {
removeFromArray(it[key], ids, keyArray);
}
});
}
});
if (indexes.length) {
if (indexes.length > 1)
throw 'found multiple possible objects for the same key combination'
arr.splice(indexes[0], 1);
}
}
function compareArray(a1, a2, keyArray) {
a2.forEach(function (it2) {
var it1s = a1.filter(function (it) {
return sameKeys(it2, it, keyArray);
});
var it1;
if (!it1s.length) {
it1 = clone(it2);
a1.push(it1);
} else {
if (it1s.length > 1)
throw 'found multiple possible objects for the same key combination'
it1 = it1s[0];
extend(it1, it2, keyArray);
}
if (it2.removedIds) {
it2.removedIds.forEach(function (ids) {
removeFromArray(a1, ids, keyArray);
});
}
});
}
Use it with compareArray(parentArray1,changedArray,['id']);
Note that it would not work with objects that contain functions. Also, if the arrays would be large, perhaps a better solution is to sort both arrays by key, then always look from the last found object up. That's all I got for now.
Updated it with some concepts from Nina and some clearing of the code.
As I understood it, you only want to add properties. So extend({a: {b: 2}},{a:{c:3}}) will result in {a: {b:2,c:3}}. If this is not what you wanted, let me know.
I also added functionality for removing ids. If any of the objects in the array contains a removedIds array of the form [{id: 4},{id: 5}] then the items with those ids will be removed from the original array.
Slight modification on code, to satisfy your conditions. Try it!
function compareArray(originalArray, destinationArray, propertyArray) {
var newItem = new Array(), processedItem = new Array();
for (var i = 0; i < originalArray.length; i++) {
var sourceElement = originalArray[i];
for (var j = 0; j < destinationArray.length; j++) {
var destinationElement = destinationArray[j];
var isUpdated = false;
if (sourceElement.constructor === Array) {
compareArray(sourceElement, destinationElement, propertyArray);
} else {
/* loop the property name to validate */
propertyArray.map(function(property) {
if (sourceElement[property]) {
if (sourceElement[property] === destinationElement[property]) {
originalArray[i] = _.clone(destinationElement);
isUpdated = true;
return;
} else {
var isAvailable = _.find(newItem, function(item) {
return item[property] === destinationElement[property];
});
if (!isAvailable) {
var isAlreadyProcessed = _.find(processedItem, function(item) {
return item[property] === destinationElement[property];
});
if(!isAlreadyProcessed){
newItem.push(destinationElement);
}
}
}
}
});
}
if (isUpdated === true) {
break;
}
}
processedItem.push(sourceElement);
}
newItem.map(function(item) {
originalArray.push(item);
});
return originalArray;
}
I have this sample JSON object
var sample = [{
"label": "one",
"value": 1
}, {
"label": "two",
"value": 2
}, {
"label": "three",
"value": 3
}, {
"label": "four",
"value": 4
}, {
"label": "five",
"value": 5
}];
I want to change it some thing like this
var sample = [{
"label": "one",
"value": 1,
"newKeyValue": "one|1"
}, {
"label": "two",
"value": 2,
"newKeyValue": "two|2"
}, {
"label": "three",
"value": 3,
"newKeyValue": "three|3"
},
...
];
It should combine both key values and return new key value combining both.
JSON is coming dynamically key label and value are not static it can be anything. For example [{"name":"srinivas","lastname":"pai"}]
You can use map like this :
EDIT
For handling generic keys you can use
Object.keys(d)[0] for first key
Object.keys(d)[1] for second key
var sample = [
{
"label":"one",
"value":1
},
{
"label":"two",
"value":2
},
{
"label":"three",
"value":3
},
{
"label":"four",
"value":4
},
{
"label":"five",
"value":5
}
];
var data = sample.map(function(d){
return {label: Object.keys(d)[0], value: Object.keys(d)[1], newKeyValue: Object.keys(d)[0] +"|" + Object.keys(d)[1]}
})
console.log(data)
Hope this helps!
You can use Array#map(), Object.keys(), and Array#join().
In ES6, you can use Arrow functions.
sample = sample.map(obj => {
var keys = Object.keys(obj);
obj.newKeyValue = keys.map(key => obj[key]).join('|');
return obj;
});
var sample = [{
"label": "one",
"value": 1
}, {
"name": "two",
"age": 2
}, {
"five": "three",
"six": 3
}, {
"company": "four",
"organization": 4
}, {
"label": "five",
"value": 5
}];
sample = sample.map(function (x) {
var keys = Object.keys(x);
x.newKeyValue = keys.map(key => x[key]).join('|');
return x;
});
console.log(sample);
document.body.innerHTML = '<pre>' + JSON.stringify(sample, 0, 4) + '</pre>';
In ES5, you can use the same code with anonymous functions
sample = sample.map(function (obj) {
var keys = Object.keys(obj);
obj.newKeyValue = keys.map(function (key) {
return obj[key]
}).join('|');
return obj;
});
Limitations due to dynamic keys:
The order of the keys in object cannot be maintained
This will join all the available keys in the object (in case if you just want to join fewer)
var sample = [
{
"label":"one",
"value":1
},
{
"label":"two",
"value":2,
"optionalValue":2
},
{
"label":"three",
"value":3,
"remarks":"free text"
},
{
"label":"four",
"value":4
},
{
"label":"five",
"value":5
}
];
for (var key in sample) {
var newValue = [];
for (var piece in sample[key]){
newValue.push(sample[key][piece])
}
sample[key]["newKeyValue"] = newValue.join('|');
}
$('pre').html(JSON.stringify(sample,null,4));
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<pre></pre>
You can use Array.prototype.forEach() for in situ changes.
The forEach() method executes a provided function once per array element.
Edit: with dynamic keys, stored in an array, because of the order.
var sample = [{ "label": "one", "value": 1 }, { "label": "two", "value": 2 }, { "label": "three", "value": 3 }, { "label": "four", "value": 4 }, { "label": "five", "value": 5 }];
sample.forEach(function (a) {
a.newKeyValue = ['label', 'value'].map(function (k) { return a[k]; }).join('|');
});
document.write('<pre>' + JSON.stringify(sample, 0, 4) + '</pre>');
If more element are their then use $.extend
var sample = [
{
"label":"one",
"value":1
},
{
"label":"two",
"value":2
},
{
"label":"three",
"value":3
},
{
"label":"four",
"value":4
},
{
"label":"five",
"value":5
}
];
$(sample).each(function(i,item){
var keyes = Object.keys(item);
sample[i] = $.extend(item,{newKeyValue: item[keyes[0]] +"|" +item[keyes[1]]});
});
console.log(sample)
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
$.extend also helpful when you are having more objects already and you want to merge both
eg.
var base = {
"label":"one",
"value":1
}
and you want to add more objects
var extra = {
"new1":"value1",
"new2":"value2",
"new3":"value3",
"new4":"value4",
}
then it will be done by
$.extend(base,extra);
Output:
{
"label":"one",
"value":1,
"new1":"value1",
"new2":"value2",
"new3":"value3",
"new4":"value4",
}
var sample = [{"name":"srinivas","lastname":"pai"}];
sample.map(function(item) {
item.newKeyValue = Object.getOwnPropertyNames(item).map(function(d) {return item[d];}).join("|");
})
console.log(sample);