I have an object array. I want to get for each element in the array the difference with the others.
For example thi is my object array:
array= [{id:1, name= 'test', isAdmin: true, userMail:'test#test.com', userTel: '+12555555'},
{id:1, name= 'test', isAdmin: false, userMail:'test#test.com', userTel: '+12555555'}, {id:1,
name= 'test', isAdmin: false, userMail:'test#test.com', userTel: '+12555785444'}]
the result is :
result = [isAdmin, userMail, userTel]
I tried this solution but not working :
for (let index = 0; index < this.array.length; index++) {
const e = this.array[index];
let j = index + 1;
let t;
while (index !== j && j <= (this.array.length - 1) && t === undefined) {
t = this.difference(array);
j++;
}
let y;
if (t !== null && t !== undefined) {
Object.keys(t).forEach(key => {
if (key !== 'idTrace') {
y = key;
}
});
}
this.result.push(y);
}
difference(object, base) {
return transform(object, (result, value, key) => {
if (!isEqual(value, base[key])) {
result[key] = isObject(value) && isObject(base[key]) ?
this.difference(value, base[key]) : value;
}
});
}
Any help, thanks in advance.
you can do it like this.
Please note that this is not the most performant solution, but it is understandable (readable) solution on which you can make optimisations as needed.
const objects = [{
"id": 1,
"name": "test",
"isAdmin": true,
"userMail": "test#test.com",
"userTel": "+12555555"
},
{
"id": 1,
"name": "test",
"isAdmin": false,
"userMail": "test#test123.com",
"userTel": "+12555555"
},
{
"id": 1,
"name": "test",
"isAdmin": false,
"userMail": "test#test.com",
"userTel": "+12555785444"
}
];
// Finds all the keys that are different in two objects.
const difference = (obj1, obj2) => {
let foundKeys = [];
Object.keys(obj1).forEach(key => {
if (obj1[key] !== obj2[key]) {
foundKeys.push(key);
}
});
return foundKeys;
};
let differentKeys = [];
// Compares every object with all objects and pushes to one array all differences in keys.
for (let i = 0; i < objects.length; i++) {
for (let j = i + 1; j < objects.length; j++) {
differentKeys = differentKeys.concat(difference(objects[i], objects[j]));
}
}
// Removes duplicates.
differentKeys = differentKeys.filter(function(value, index, differentKeys) {
return differentKeys.indexOf(value) === index;
});
console.log(differentKeys);
Let me know if you have any questions.
Related
function calculateTotal(items) {
let total = 0;
for (let i = 0; i < items.length; i++) {
if (items[i].type === "food") {
total += items[i].price * 1.1;
} else {
total += items[i].price;
}
}
return total;
}
const items = [
{ type: "food", price: 10 },
{ type: "clothing", price: 20 },
{ type: "electronics", price: 30 }
];
console.log(calculateTotal(items));
I need to improve on this code.
I have tried improving the variable description. here is the code again with improved variables
function calculateTotal(items) {
let total = 0;
for (let i = 0; i < items.length; i++) {
const item = items[i];
if (item.type === "food") {
total += item.price * 1.1;
} else {
total += item.price;
}
}
return total;
}
const items = [
{ type: "food", price: 10 },
{ type: "clothing", price: 20 },
{ type: "electronics", price: 30 }
];
console.log(calculateTotal(items));
what else can i try improving on in this code?
You can add a factor const with shorted if syntax for better readability
function calculateTotal(items) {
let total = 0;
for (let i = 0; i < items.length; i++) {
const item = items[i];
const factor = (item.type === "food") ? 1.1 : 1
total += item.price * factor;
}
return total;
}
const items = [
{ type: "food", price: 10 },
{ type: "clothing", price: 20 },
{ type: "electronics", price: 30 }
];
console.log(calculateTotal(items));
Or using forEach JavaScript syntax you can use:
function calculateTotal(items) {
let total = 0;
items.forEach((item) => {
total += ((item.type === "food") ? item.price * 1.1 : item.price)
})
return total;
}
Also, you can add factor property inside the item object itself to 'special' items (with factor != 1) like this:
const items = [
{ type: "food", price: 10, factor: 1.1 },
{ type: "clothing", price: 20 },
{ type: "electronics", price: 30 }
];
Than you can use the reduce method like this:
function calculateTotal(items) {
let total = items.reduce((acc, item) => {
return acc + item.price * (item?.factor || 1)
}, 0)
return total;
}
Or just:
function calculateTotal(items) {
return items.reduce((acc, item) => {
return acc + item.price * (item?.factor || 1)
}, 0)
}
I am using kendo grid to display data, but while sorting(ascending or descending) it's sorting perfectly for string values. But for numeric it's not sorting properly it's taking only first character to do sorting, not taking as string values even it's in numeric. How to solve this issue ?
You can use the gird column sortable.compare property to assign your own compare function.
Then what you are looking for is a Natural sort, like the one described here: http://web.archive.org/web/20130826203933/http://my.opera.com/GreyWyvern/blog/show.dml/1671288 and implemented here: http://www.davekoelle.com/files/alphanum.js
Here is a demo using a case insensitive version of the natural sort:
https://dojo.telerik.com/eReHUReH
function AlphaNumericCaseInsensitive(a, b) {
if (!a || a.length < 1) return -1;
var anum = Number(a);
var bnum = Number(b);
if (!isNaN(anum) && !isNaN(bnum)) {
return anum - bnum;
}
function chunkify(t) {
var tz = new Array();
var x = 0, y = -1, n = 0, i, j;
while (i = (j = t.charAt(x++)).charCodeAt(0)) {
var m = (i == 46 || (i >= 48 && i <= 57));
if (m !== n) {
tz[++y] = "";
n = m;
}
tz[y] += j;
}
return tz;
}
var aa = chunkify(a ? a.toLowerCase() : "");
var bb = chunkify(b ? b.toLowerCase() : "");
for (x = 0; aa[x] && bb[x]; x++) {
if (aa[x] !== bb[x]) {
var c = Number(aa[x]), d = Number(bb[x]);
if (!isNaN(c) && !isNaN(d)) {
return c - d;
} else return (aa[x] > bb[x]) ? 1 : -1;
}
}
return aa.length - bb.length;
}
var dataSource = new kendo.data.DataSource({
data: [
{ id: 1, item: "item101" },
{ id: 2, item: "item2" },
{ id: 3, item: "item11" },
{ id: 4, item: "item1" }
]
});
$("#grid").kendoGrid({
dataSource: dataSource,
sortable: true,
columns: [{
field: "item",
sortable: {
compare: function(a, b) {
return AlphaNumericCaseInsensitive(a.item, b.item);
}
}
}]
});
I wrote JQuery to grab columns' text in the ColumnChooser pop-up dialog, in order to get colModel's Name (or Index) then I learned it doesn't work that way and I have to somehow use colName against colModel instead.
Problem..
colNames: [ 'Id', 'Stock Number', 'VIN', 'Year' ],
colModel: [
{ name: 'Id', index: 'Id' },
{ name: 'StockNumber', index: 'StockNumber' },
{ name: 'VIN', index: 'VIN' },
{ name: 'Year', index: 'Year' }
As you can see my problem is "Stock Number" is not the same as "StockNumber" when using $ColumnChooserSelectedList against the $jqgridColumnModelSetting. Also, I cannot tell if columns are in proper order (between colName & colModel) as I don't know how it works behind the scene.
var $ColumnChooserSelectedList = $("#colchooser_test ul.selected li");
var $ColumnModelSetting = $("#test").jqGrid('getGridParam', 'colModel');
var returnValue = "";
$.each($ColumnChooserSelectedList, function (i,o) {
if (o.title.length > 0) {
if (returnValue.length > 0) { returnValue += "|"; }
returnValue += o.title; //This o.title need to be changed to match colModel's Name (or Index)...
}
});
Thanks...
Updated - Solution found
Came up with this nice solution but I cannot be sure if it works 100% of the time.
var $ColumnChooserSelectedList = $("#colchooser_test ul.selected li");
var $ColumnModelSetting = $("#test").jqGrid('getGridParam', 'colModel');
var $ColumnNameSetting = $("#test").jqGrid('getGridParam', 'colNames');
var returnValue = "";
$.each($ColumnChooserSelectedList, function (i1,o1) {
if (o1.title.length > 0) {
$.each($ColumnNameSetting, function (i2, o2) {
if ($ColumnNameSetting[i2] == o1.title) {
if (returnValue.length > 0) { returnValue += "|"; }
returnValue += $ColumnModelSetting[i2].name;
return false; //This break the foreach loop...
}
});
}
});
Updated - Solution found
Came up with this nice solution but I cannot be sure if it works 100% of the time.
var $ColumnChooserSelectedList = $("#colchooser_test ul.selected li");
var $ColumnModelSetting = $("#test").jqGrid('getGridParam', 'colModel');
var $ColumnNameSetting = $("#test").jqGrid('getGridParam', 'colNames');
var returnValue = "";
$.each($ColumnChooserSelectedList, function (i1,o1) {
if (o1.title.length > 0) {
$.each($ColumnNameSetting, function (i2, o2) {
if ($ColumnNameSetting[i2] == o1.title) {
if (returnValue.length > 0) { returnValue += "|"; }
returnValue += $ColumnModelSetting[i2].name;
return false; //This break the foreach loop...
}
});
}
});
I am having problem in my custom sorting method. I have a json structure wherein integer values are being passed as String. While sorting I need to sort the list based on the integer value, but it is being sorted as String values.
I have created a JsFiddle for the same:
http://jsfiddle.net/ayan_2587/vjF2D/14/
The angular code is as follows:-
var app = angular.module('myModule', []);
app.controller('ContactListCtrl', function ($scope, $timeout, $filter) {
var sortingOrder = 'price';
$scope.sortingOrder = sortingOrder;
$scope.sortorder = '-sort';
$scope.contacts = [{
"name": "Richard",
"surname": "Stallman",
"price": "7200"
}, {
"name": "Donald",
"surname": "Knuth",
"price": "34565"
}, {
"name": "Linus",
"surname": "Torvalds",
"price": "23454"
}];
$scope.setLoading = function (loading) {
$scope.isLoading = loading;
}
$scope.layoutDone = function (value) {
console.log(value);
$scope.setLoading(true);
$timeout(function() {
// take care of the sorting order
if ($scope.sortingOrder !== '') {
if(value == 'sort'){
$scope.contacts = $filter('orderBy')($scope.contacts, $scope.sortingOrder, false);
}
else if(value == '-sort'){
$scope.contacts = $filter('orderBy')($scope.contacts, $scope.sortingOrder, true);
}
}
$scope.setLoading(false);
}, 1000);
}
$scope.loadFeed = function(url) {
$scope.setLoading(true);
}
$scope.loadFeed();
});
app.directive('repeatDone', function() {
return function(scope, element, attrs) {
if (scope.$last) { // all are rendered
scope.$eval(attrs.repeatDone);
}
}
})
Please help me out !!!
SInce you sort in JS, you can allways use Array.sort() - at least on modern browsers-, passing it a sort function like:
function sortAsc(a,b) {
a = parseInt(a.price);
b = parseInt(b.price);
return a > b ? 1 : (a === b ? 0 : -1);
}
And then execute the sorting like:
if(value == 'sort'){
$scope.contacts.sort(sortAsc);
}
See forked fiddle: http://jsfiddle.net/sRruf/ (the initial state is not sorted)
The sort property (here price) can be parameterized with a little extra work.
And here is a version using the orderBy filter and a custom predicate: http://jsfiddle.net/sRruf/1/
I have a grid in ext with some custom columns, and I want to be able to sort this column - I want to sort it by what is displayed inside of it, but really I just cannot figure out how to define a sorter for a column that will not be based on the dataIndex - I tried using a custom model, but I could not get that to work.
{
text: 'Parent',
dataIndex: 'Parent',
renderer: function(value, meta, record) {
var ret = record.raw.Parent;
if (ret) {
return ret.Name;
} else {
meta.tdCls = 'invisible';
return record.data.Name;
}
},
sortable: true
},
You should be able to override the doSort method of the column. Here's the gist of it. I also created a working fiddle (http://jsfiddle.net/cfarmerga/LG5uA/). The fiddle uses the string length of a field as the property to sort on, but of course you could apply your own custom sort logic.
var grid = Ext.create('Ext.grid.Panel',{
//...
columns: [
{ text: 'name', dataIndex: 'name', sortable: true },
{
text: 'Custom',
sortable : true,
dataIndex: 'customsort',
doSort: function(state) {
var ds = this.up('grid').getStore();
var field = this.getSortParam();
ds.sort({
property: field,
direction: state,
sorterFn: function(v1, v2){
v1 = v1.get(field);
v2 = v2.get(field);
return v1.length > v2.length ? 1 : (v1.length < v2.length ? -1 : 0);
}
});
}
}
]
//....
});
For Ext JS version 5, it looks like doSort was taken out, so I couldn't override that. Instead, I went the route of listening to the sortchange event, and from there, I used the Ext.data.Store.setSorters method. The code is a bit custom, and overly complex because of the data that I'm using, so keep that in mind (Fiddle here):
// grid class
initComponent: function() {
...
this.on('sortchange', this.onSortChange, this);
},
onSortChange: function(container, column, direction, eOpts) {
// check for dayColumnIndex
if (column && column.dayColumnIndex !== undefined) {
this.sortColumnByIndex(column.dayColumnIndex, direction);
}
},
sortColumnByIndex: function(columnIndex, direction) {
var store = this.getStore();
if (store) {
var sorterFn = function(rec1, rec2) {
var sortValue = false;
if (rec1 && rec2) {
var day1;
var daysStore1 = rec1.getDaysStore();
if (daysStore1) {
day1 = daysStore1.getAt(columnIndex);
}
var day2;
var daysStore2 = rec2.getDaysStore();
if (daysStore2) {
day2 = daysStore2.getAt(columnIndex);
}
if (day1 && day2) {
var val1 = day1.get('value');
var val2 = day2.get('value');
sortValue = val1 > val2 ? 1 : val1 === val2 ? 0 : -1;
}
}
return sortValue;
};
if (direction !== 'ASC') {
sorterFn = function(rec1, rec2) {
var sortValue = false;
if (rec1 && rec2) {
var day1;
var daysStore1 = rec1.getDaysStore();
if (daysStore1) {
day1 = daysStore1.getAt(columnIndex);
}
var day2;
var daysStore2 = rec2.getDaysStore();
if (daysStore2) {
day2 = daysStore2.getAt(columnIndex);
}
if (day1 && day2) {
var val1 = day1.get('value');
var val2 = day2.get('value');
sortValue = val1 < val2 ? 1 : val1 === val2 ? 0 : -1;
}
}
return sortValue;
};
}
store.setSorters([{
sorterFn: sorterFn
}]);
}
}
There is a convert method on the Ext.data.Model class that allows you to convert the data before it's being used. Then you can just specify this 'dataIndex' in your column and do a normal sort. The column will be sorted by that converted value. Here is the a sample model with just one field (Parent) and with it's corresponding conversion:
Ext.define('MyModel', {
extend: 'Ext.data.Model',
fields: [
{name: 'Parent', type: 'string', convert: sortParent},
// other fields...
],
sortParent: function(value, record) {
var ret = record.raw.Parent;
if (ret) {
return ret.Name;
} else {
meta.tdCls = 'invisible';
return record.data.Name;
}
}
});