Merge 2 array of objects only if key matches - arrays

I have 2 array of objects which I want to merge their properties together ONLY IF user from both array matches.
Example Arrays
arr1 = [{ bank: 1, user: 'fred', depositAmount: 100, withdrawalAmount: 0 }];
arr2 = [{ user: 'fred', gender: 'male', age: 27, state: "arizona" }, { user: 'john',gender: 'male', age: 28, state: "texas" }];
Expected Output
arr1 = [{ bank: 1, user: 'fred', depositAmount: 100, withdrawalAmount: 0, gender: 'male', age: 27, state: "arizona" }];
Here's what I tried so far, but it is returning an empty array
var result = [];
arr1.concat(arr2)
.forEach(item =>
result[item.user] =
Object.assign({}, result[item.user], item)
);
result = result.filter(r => r);
console.log(result)

You can achieve taht by using map, filter Array functionalities and spread operator (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_syntax):
const arr1 = [{ bank: 1, user: 'fred', depositAmount: 100, withdrawalAmount: 0 }, { user: 'john2',gender: 'male', age: 28, state: "texas" }];
const arr2 = [{ user: 'fred', gender: 'male', age: 27, state: "arizona" }, { user: 'john',gender: 'male', age: 28, state: "texas" }];
const newArray = arr1.map((obj) => {
const secondArrayObj = arr2.find((obj2) => obj2.user === obj.user);
if (secondArrayObj) {
return {...secondArrayObj, ...obj}
}
return null;
}).filter((obj) => obj != null);
console.log(newArray);
//[{
// "user": "fred",
// "gender": "male",
// "age": 27,
// "state": "arizona",
// "bank": 1,
// "depositAmount": 100,
// "withdrawalAmount": 0
//}]
Notice that if you have same field in both objects, field from arr2 object will be overridden by field from arr1 object

Related

How to Iterate dictionary in React Typescript

I am learning react with typescript. I have one dictionary of the department in which employees data of department is stored in the form of an array.
type Department = {
Emp_Id: number,
Name: string,
Age: number
}
let dict: {[DepartmentNo: number]: Department[] } = {};
dict[0] = [ {Emp_Id: 1, Name:"Test", Age: 23},
{Emp_Id: 2, Name:"Test", Age: 23},
{Emp_Id: 3, Name:"Test", Age: 23}
];
dict[1] = [ {Emp_Id: 1, Name:"Test 2", Age: 23},
{Emp_Id: 2, Name:"Test 3", Age: 23},
{Emp_Id: 3, Name:"Test 4", Age: 23}
];
dict[2] = [ {Emp_Id: 1, Name:"Test 2", Age: 23},
{Emp_Id: 2, Name:"Test 3", Age: 23}
];
I created a function that will return me an unordered list.
const printDepartment = () => {
// getting error in map argument: department
Object.entries(dict).map((department: Department) => {
let count = 0;
// here also saying condition will always return true
if(dict[count] != 2){
return (<ul>
<li>{department.Emp_Id}</li>
<li>{department.Name}</li>
</ul>)
}
})
}
in my return I am simply calling this function:
<div>
{
printDepartment()
}
</div>
The type of keys on your dict will always be string. If you change that, the types in the Array.map element will be correctly inferred as [string, Department[]].
type Department = {
Emp_Id: number;
Name: string;
Age: number;
};
let dict: { [DepartmentNo: string]: Department[] } = {};
dict[0] = [
{ Emp_Id: 1, Name: "Test", Age: 23 },
{ Emp_Id: 2, Name: "Test", Age: 23 },
{ Emp_Id: 3, Name: "Test", Age: 23 },
];
dict[1] = [
{ Emp_Id: 1, Name: "Test 2", Age: 23 },
{ Emp_Id: 2, Name: "Test 3", Age: 23 },
{ Emp_Id: 3, Name: "Test 4", Age: 23 },
];
dict[2] = [
{ Emp_Id: 1, Name: "Test 2", Age: 23 },
{ Emp_Id: 2, Name: "Test 3", Age: 23 },
];
const printDepartment = () => {
Object.entries(dict).map((entry) => { // [string, Department[]]
console.log({ key: entry[0], value: entry[1] });
});
};
printDepartment();
demo

Merge two arrays avoiding O(n^2) complexity

Given two arrays, farmers and collections, I want to be able to merge the farmer information to each collection when farmer_id in the collection is equal to id in farmers. if there is no id of the farmer that matches farmer_id in the collection then that collection should have a an empty farmer object
const farmers = [{
id: 10,
name: 'John Doe',
email: 'jdoe#gmail.com'
},
{
id: 11,
name: 'James Bond',
email: 'james#gmail.com'
}
]
const collections = [{
id: 9,
name: 'Book',
farmer_id: 10,
date: 'June'
},
{
id: 10,
name: 'Game',
farmer_id: 11,
date: 'July'
},
{
id: 13,
name: 'Car',
farmer_id: 10,
date: 'August'
},
{
id: 11,
name: 'Wristwatches',
farmer_id: 20,
date: 'August'
}
]
The result should be in this format below
const result = [{
id: 9,
name: 'Book',
farmer_id: 10,
date: 'June',
farmer: {
id: 10,
name: 'John Doe',
email: 'jdoe#gmail.com'
}
},
{
id: 10,
name: 'Game',
farmer_id: 11,
date: 'July',
farmer: {
id: 11,
name: 'James Bond',
email: 'james#gmail.com'
}
},
{
id: 13,
name: 'Car',
farmer_id: 10,
date: 'August',
farmer: {
id: 10,
name: 'John Doe',
email: 'jdoe#gmail.com'
}
},
{
id: 11,
name: 'Wristwatches',
farmer_id: 20,
date: 'August',
farmer: {}
}
]
This is what i have been able to come up with but am stuck right now
function mapper(farmers, collectors) {
for (let k = 0; k < farmers.length; k++) {
const idToFarmerInfo = {};
idToFarmerInfo[farmers[k].id] = farmers[k];
for (let j = 0; j < collectors.length; j++) {
let mapper = idToFarmerInfo[collectors[j].farmer_id];
farmers[mapper] = collectors[j]
}
}
return farmers
}
i followed this link as am trying to avoid O of N squared but O of N complexity
For a better performance you could create a hash of farmers where the complexity is O(N) because we're iterating the farmers list only once.
const farmers = [{ id: 10, name: 'John Doe', email: 'jdoe#gmail.com' }, { id: 11, name: 'James Bond', email: 'james#gmail.com' } ]; const collections = [{ id: 9, name: 'Book', farmer_id: 10, date: 'June' }, { id: 10, name: 'Game', farmer_id: 11, date: 'July' }, { id: 13, name: 'Car', farmer_id: 10, date: 'August' }, { id: 11, name: 'Wristwatches', farmer_id: 20, date: 'August' } ]
var farmers_hash = farmers.reduce((hash, item) => {
hash[item.id] = item;
return hash;
}, {});
console.log(farmers_hash);
The following step is to build the desired output by assigning one farmer using hash keys.
This can be achieved using map method in combination with Object.assign.
const farmers = [{ id: 10, name: 'John Doe', email: 'jdoe#gmail.com' }, { id: 11, name: 'James Bond', email: 'james#gmail.com' } ]; const collections = [{ id: 9, name: 'Book', farmer_id: 10, date: 'June' }, { id: 10, name: 'Game', farmer_id: 11, date: 'July' }, { id: 13, name: 'Car', farmer_id: 10, date: 'August' }, { id: 11, name: 'Wristwatches', farmer_id: 20, date: 'August' } ]
var farmers_hash = farmers.reduce((hash, item) => {
hash[item.id] = item;
return hash;
}, {});
var result = collections.map((item) => {
item.farmer = Object.assign({}, farmers_hash[item.farmer_id])
return item;
});
console.log(result);
As you can see the final complexity is O(N) + O(M) where N is the length of farmers array and M is the length of collections array.
Demo on stackblitz
You can use a more declarative approach and use Array.map and Array.find
const result = collections.map(collection => {
return {
...collection,
farmer: farmers.find(farmer => collection.farmer_id == farmer.id) || {}
};
});
console.log(result);
You can create a Map collection to have O(N) of access to desired farmer by id. Then mapping becomes faster in terms of performance:
const unique = new Map(farmers.map(f=> [f.id, f]));
const result = collections.map(s => ({
...s, farmer_id: unique.get(s.farmer_id) || s.farmer_id
}))
Now mapping of collections has complexity O(N). However, do not forget to sum complexity of making unique farmers. The overall complexity is O(N) + O(M).
An example:
const farmers = [{
id: 10,
name: 'John Doe',
email: 'jdoe#gmail.com'
},
{
id: 11,
name: 'James Bond',
email: 'james#gmail.com'
}
];
const collections = [{
id: 9,
name: 'Book',
farmer_id: 10,
date: 'June'
},
{
id: 10,
name: 'Game',
farmer_id: 11,
date: 'July'
},
{
id: 13,
name: 'Car',
farmer_id: 10,
date: 'August'
},
{
id: 11,
name: 'Wristwatches',
farmer_id: 20,
date: 'August'
}
];
const unique = new Map(farmers.map(f=> [f.id, f]));
const result = collections.map(s => ({
...s, farmer_id: unique.get(s.farmer_id) || s.farmer_id
}))
console.log(result);

Angular UI grid :Show only selected objects

I have a code snippet
$scope.users = [
{ name: "abc", age: 10, location: 'Nagpur' },
{ name: "bcd", age: 30, location: 'Chennai' },
{ name: "efr", age: 29, location: 'Chennai' },
{ name: "abc", age: 25, location: 'Bangalore' },
{ name: "abc", age: 27, location: 'Vizag' }
];
$scope.gridOptions.data = $scope.users;
In grid how to show only users which have name = "abc"?
You just have to filter out all values from your array whose name is "abc"
angular.forEach($scope.users,function(val){
if(val.name=='abc')
$scope.abcUsers.push(val);
});
$scope.gridOptions.data = $scope.abcUsers;

Get diff between two arrays of objects with ES6 or TypeScript

I have the following arrays:
arr1 = [{
id: 1,
name: 'Diego',
age: 23
}, {
id: 2,
name: 'Brian',
age: 18
}]
arr2 = [{
id: 1,
name: 'Diego',
age: 23
}, {
id: 2,
name: 'Brian',
age: 18
}, {
id: 3,
name: 'Pikachu',
age: 88
}]
I need get difference between this two arrays, the espected result is:
arr3 [{id:3, name: 'Pikachu', age: 88}]
How do i solve this problem using ES6 or TypeScript?
I tried using SET, but doesn't worked.
Something like this maybe:
let ids1 = arr1.map(item => item.id);
let ids2 = arr2.map(item => item.id);
let diff = ids1.map((id, index) => {
if (ids2.indexOf(id) < 0) {
return arr1[index];
}
}).concat(ids2.map((id, index) => {
if (ids1.indexOf(id) < 0) {
return arr2[index];
}
})).filter(item => item != undefined);
(code in playground)

How to edit cells with backgrid

I am trying an example with backgrid paging. I have to edit a cell content on click of edit button then save the updated cell content to the server. Here iam rendering the buttons using backgrid cell extention but not able to figure it out how to enable a cell for editing on click of the button.
Here is the sample am trying.. In EditCell i have a method editRow in which i have to perform the updation.
Thanks
(function(){
//Namespacing the views collections and models
window.App = {
Models: {},
Views: {},
Collections: {},
Helpers: {}
},
//Template helper to load the template of any id
App.Helpers.template = function(id){
return _.template($('#' + id).html());
}
//Person Model
App.Models.Person = Backbone.Model.extend({});
//Person collection - People
App.Collections.People = Backbone.PageableCollection.extend({
model: App.Models.Person,
state: {
pageSize: 10
},
mode: "client"
});
var personCollection = new App.Collections.People([
{
id: 1,
name: 'Trim',
age: 33,
occupation: 'Dotnet Programmer'
},
{
id: 2,
name: 'Crum',
age: 25,
occupation: 'Developer'
},
{
id: 3,
name: 'Drum',
age: 46,
occupation: 'Designer'
},
{
id: 4,
name: 'Srum',
age: 27,
occupation: 'Java Programmer'
},
{
id: 5,
name: 'Vrum',
age: 24,
occupation: 'Developer'
},
{
id: 6,
name: 'Brum',
age: 29,
occupation: 'Designer'
},
{
id: 7,
name: 'Frum',
age: 33,
occupation: 'Dotnet Programmer'
},
{
id: 8,
name: 'Jrum',
age: 25,
occupation: 'Developer'
},
{
id: 9,
name: 'Lrum',
age: 46,
occupation: 'Designer'
},
{
id: 10,
name: 'Hrum',
age: 27,
occupation: 'Java Programmer'
},
{
id: 11,
name: 'Prum',
age: 24,
occupation: 'Developer'
},
{
id: 12,
name: 'Zrum',
age: 29,
occupation: 'Designer'
}
]
);
var EditCell = Backgrid.Cell.extend({
template: _.template('<button>Edit</button>'),
events: {
"click": "editRow"
},
editRow: function (e) {
e.preventDefault();
//Enable the occupation cell for editing
//Save the changes
//Render the changes.
},
render: function () {
this.$el.html(this.template(this.model.toJSON()));
this.delegateEvents();
return this;
}
});
var columns = [{
name: "id",
label: "ID",
editable: false,
cell: Backgrid.IntegerCell.extend({
orderSeparator: ''
})
}, {
name: "name",
label: "Name",
cell: "string"
}, {
name: "age",
label: "Age",
cell: "integer"
}, {
name: "occupation",
label: "Occupation",
cell: "string"
}, {
name: "actions",
label: "Actions",
cell: EditCell
}];
// Initialize a new Grid instance
var grid = new Backgrid.Grid({
columns: columns,
collection: personCollection
});
var paginator = new Backgrid.Extension.Paginator({
collection: personCollection
});
// Render the grid and attach the root to your HTML document
$("#grid").append(grid.render().el);
$("#paginator").append(paginator.render().$el);
})();
the following code solved my problem.. With the below code we can make each cell editable/noneditable depending upon a condition. Still looking for a better approach to Enable editing on edit button click.
(function(){
//Person Model
var Person = Backbone.Model.extend({
});
//Person collection - People
var People = Backbone.Collection.extend({
model: Person
});
var personCollection = new People([
{
id: 1,
name: 'Trim',
age: 33,
occupation: 'Dotnet Programmer'
},
{
id: 2,
name: 'Crum',
age: 25,
occupation: 'Developer'
},
{
id: 3,
name: 'Drum',
age: 46,
occupation: 'Designer'
},
{
id: 4,
name: 'Srum',
age: 27,
occupation: 'Java Programmer'
},
{
id: 5,
name: 'Vrum',
age: 24,
occupation: 'Developer'
},
{
id: 6,
name: 'Brum',
age: 29,
occupation: 'Designer'
},
{
id: 7,
name: 'Frum',
age: 33,
occupation: 'Dotnet Programmer'
},
{
id: 8,
name: 'Jrum',
age: 25,
occupation: ''
},
{
id: 9,
name: 'Lrum',
age: 46,
occupation: ''
},
{
id: 10,
name: 'Hrum',
age: 27,
occupation: 'Java Programmer'
},
{
id: 11,
name: 'Prum',
age: 24,
occupation: 'Developer'
},
{
id: 12,
name: 'Zrum',
age: 29,
occupation: 'Designer'
}
]
);
var MyCell = Backgrid.Cell.extend({
initialize: function (options) {
MyCell.__super__.initialize.apply(this, arguments);
this.listenTo(this.model, "backgrid:edited", this.doSomething);
},
doSomething: function () {
console.log('something');
},
enterEditMode: function () {
this.$el.width((this.$el.outerWidth() - 10) + 'px');
Backgrid.Cell.prototype.enterEditMode.apply(this, arguments);
},
exitEditMode: function () {
this.$el.width(false);
Backgrid.Cell.prototype.exitEditMode.apply(this, arguments);
}
});
var columns = [{
name: "id", // The key of the model attribute
label: "ID", // The name to display in the header
editable: false, // By default every cell in a column is editable, but *ID* shouldn't be
// Defines a cell type, and ID is displayed as an integer without the ',' separating 1000s.
cell: "string", //Backgrid.IntegerCell.extend({ tagName: "td style='text-align:left'" })
editable:false,
isEnabled: false
}, {
name: "name",
label: "Name",
// The cell type can be a reference of a Backgrid.Cell subclass, any Backgrid.Cell subclass instances like *id* above, or a string
cell: "string", // This is converted to "StringCell" and a corresponding class in the Backgrid package namespace is looked up
editable:false
}, {
name: "age",
label: "Age",
cell: "string", // An integer cell is a number cell that displays humanized integers
editable: false
}, {
name: "occupation",
label: "Occupation",
cell: MyCell, // A cell type for floating point value, defaults to have a precision 2 decimal numbers
editable: function (c, m) {
if (typeof(c.collection) === 'undefined')
return false;
else
return (c.attributes.age <= 30) ? true : false;
}
}];
// Initialize a new Grid instance
var grid = new Backgrid.Grid({
columns: columns,
collection: personCollection
});
// Initialize a client-side filter to filter on the client
// mode pageable collection's cache.
var filter = new Backgrid.Extension.ClientSideFilter({
collection: personCollection,
fields: ['name']
});
// Render the grid and attach the root to your HTML document
$("#grid").append(grid.render().el);
$("#grid").before(filter.render().el);
})();

Resources