I would like to use Underscore.js to determine if an instance of an object is present in an array.
An example usage would be:
var enrollments = [
{ userid: 123, courseid: 456, enrollmentid: 1 },
{ userid: 123, courseid: 456, enrollmentid: 2 },
{ userid: 921, courseid: 621, enrollmentid: 3 }
]
I want to be able to identify unique an enrollment where the userid and courseid are the same.
So basically, given a list of enrollments I can remove duplicates based on matches to the userid and courseid, but not the enrollment id.
You can use the filter method from Underscore:
function contains(arr, userid, courseid){
var matches = _.filter(arr, function(value){
if (value.userid == userid && value.courseid == courseid){
return value;
}
});
return matches;
}
contains(enrollments, 123, 456);
Related
Im new in react js and I get a problem with my array... I want to return a value of my array that have contain name and adress .and all value are string thi is my data that I need
name :123,
adress:12569
const array = [
0: [ 'name','123' ],
1: [ 'adress','12569'],
2: ['family','4'],
];
You can run loop on the array and assign key-value for each of the array items.
const array = [
['name', '123'],
['adress', '12569'],
['family', '4'],
];
const res = {};
array.forEach((item) => {
res[item[0]] = item[1];
})
console.log(res);
In this case, you should use an Object.
const foo = {
name: '123',
adress: 'bar',
family: '4',
}
So, to access the propertys:
console.log(foo.name); // 123
console.log(foo.adress); // bar
console.log(foo.family); // 4
But if you are getting this information as an array, you can always transform it into an object.
It would make more sense for that data to be combined into a single object rather than a series of nested arrays, and then use find to locate the object that matches the query.
const data = [
{ name: 'Bob', address: '999 Letsbe Avenue', family: 4 },
{ name: 'Sally', address: '8 Treehouse Lane', family: 0 },
{ name: 'Joan', address: '85 Long Terrace', family: 6 }
];
// Accepts the data array, and a query object
function findFamily(data, query) {
// Iterate through the data array to `find`
return data.find(obj => {
// Split the query into key/value pairs
const queryEntries = Object.entries(query);
// And return only those objects where the
// object key/value matches the query key/value
return queryEntries.every(([ key, value ]) => {
return obj[key] === value;
});
// And if there are no matches return 'No match'
}) || 'No match';
}
console.log(findFamily(data, {
name: 'Bob',
address: '999 Letsbe Avenue',
family: 0
}));
console.log(findFamily(data, {
address: '999 Letsbe Avenue',
family: 4
}));
console.log(findFamily(data, {
name: 'Sally'
}));
Additional documentation
every
Destructuring assignment
Object.entries
customerProducts: [
{
name: "foo",
id: 123
},
{
name: "test",
id: 44
}
]
otherProducts: [
{
name: "other",
id: 44
},
{
name: "test",
id: 21
}
]
I want to iterate through customerProducts, which is an array of objects. I want to filter the customerProducts that have an ID that another array of objects, otherProducts, has. So for examople, I'd want the returned result in this case to be:
{
name: "test",
id: 44
}
since otherProducts has an id of 44.
I was thinking of mapping through otherProducts and just returning an array of IDs, then running a forEach on that but that seems like a long way of doing it.
Create an indexed Set of the values to filter by (id from otherProducts) then filter customerProducts by that Set
const customerProducts = [{name: "foo",id: 123},{name: "test",id: 44}]
const otherProducts = [{name: "other",id: 44},{name: "test",id: 21}]
const otherProductIds = new Set(otherProducts.map(({ id }) => id))
const filteredCustomerProducts = customerProducts.filter(({ id }) =>
otherProductIds.has(id))
console.info(filteredCustomerProducts)
This can be done by using array methods filter and some.
customerProducts.filter((x)=> otherProducts.some(y=> y.id === x.id));
Explanation:
filter method will call each and every element in the otherProducts array and check if the id of customerProduct is present in otherProducts for at least one element.
declare customerProducts , otherProducts as JS array variable and use JS Array filter find functions
let customerProducts = [
{
name: "foo",
id: 123
},
{
name: "test",
id: 44
}
]
let otherProducts = [
{
name: "other",
id: 44
},
{
name: "test",
id: 21
}
];
let filtered = customerProducts.filter( el => otherProducts.find( e => e.id == el.id) )
console.log(filtered);
I want to add a new property (contactDetails.countryName) and assign a value to a nested object stored in an array called users using the function map().
I've recently learned that I should use the spread operator (...) and then create / assign the new property in order to avoid mutating my original array of objects so I've developed 2 different implementations for this but I'm not really confident I'm following the best practices to accomplish I want to regarding the semantic and performance.
What would be the best approach to accomplish what I want to do in your opinion?
const countries = [
{ id: 3, countryName : "UK" },
{ id: 4, countryName : "Spain" },
{ id: 6, countryName : "Germany"}
];
const users = [
{ id : 1,
name: "Douglas Camp",
dateOfBirth: "23-06-1984",
contactDetails:
{
country: 3,
phone: "7373724997"
}
},
{
id : 2,
name: "Martin Stein",
dateOfBirth: "19-08-1992",
contactDetails:
{
country: 6,
phone: "3334343434"
}
},
];
const usersData = users.map(user=> {
// Version 1 : using spreading operator twice
const newUser = {
...user,
contactDetails: {
...user.contactDetails,
countryName: countries.find(c=> c.id == user.contactDetails.country).countryName
}
};
return newUser;
});
// Version 2: copying the original object property and using spread operator only for cloning the nested object properties
const newUser = {
id: user.id,
name: user.name,
dateOfBirth: user.dateOfBirth,
contactDetails: {
...user.contactDetails,
countryName: countries.find(c=> c.id == user.contactDetails.country).countryName
}
};
console.log(users);
console.log(usersData);
Here is an approach you can consider:
First of all I would Array.reduce the countries to a Map so you can get them via key/value or in this case by countries.get(key) and avoid filtering that array every time.
You can map through the users and for each one create a new object. In this case I call them accounts.
You can also consider using Object.assign
Note that both ... operator and Object.assign are shallow clone approaches. They do not recursively clone the nested objects/children. For that you can use JSON.stringify and JSON.parse etc.
let countries = [
{ id: 3, countryName : "UK" },
{ id: 4, countryName : "Spain" },
{ id: 6, countryName : "Germany"}
].reduce((r,{id, countryName}) => (r.set(id, countryName), r), new Map()) // reduce with Map
let users = [ { id : 1, name: "Douglas Camp", dateOfBirth: "23-06-1984", contactDetails: { country: 3, phone: "7373724997" } }, { id : 2, name: "Martin Stein", dateOfBirth: "19-08-1992", contactDetails: { country: 6, phone: "3334343434" } }, ];
let accounts = users.map(user => Object.assign({}, user, { // <-- map through
contactDetails: {
...user.contactDetails,
countryName: countries.get(user.contactDetails.country) // <-- get by key
}
}))
users[0].id = 2 // <-- modify users
users[0].contactDetails.phone = "00000"
console.log(users, accounts) // <-- no changes to accounts
Notice when we update the users[0].id and users[0].contactDetails.phone the accounts values did not update.
I normally use version 1, the spread operator twice. I also would consider checking out immer which allows you to do mutable updates on a cloned draft and handles merging it back for you.
const newUser = immer(user, draft => {
draft.contactDetails.countryName = countries.find(
c => c.id == user.contactDetails.country).countryName
)
})
Just edit the specific property you want and immer handles copying the rest of it.
Cloning and merging MapsSection
Just like Arrays, Maps can be cloned:
var original = new Map([
[1, 'one']
]);
var clone = new Map(original);
console.log(clone.get(1)); // one
console.log(original === clone); // false. Useful for shallow comparison
I personally like to use Version 1, as it makes your code much less redundant and easier to read. It also passes all the properties of 'user' down to newUser.
I'm using EXTJS framework for my code.
below is my array structure:
data = [{
id: 22,
rows: [{
id: "673627",
name: "ABS",
address: "536street"
}, {
id: "333",
name: "TEST$$",
address: "536street"
}, {
id: "999",
name: "TEST$$",
address: "536street"
}]
}, {
id: 33,
rows: [{
id: "899",
name: "TES",
address: "536street"
}, {
id: "333",
name: "TEST$$",
address: "536street"
}, {
id: "999",
name: "TES673",
address: "536street"
}]
}]
Now I want to filter the name from this array, whose value I'm comparing with say "TEST$$".
I'm doing this;
Ext.each(data, function(item) {
filter = item.rows.filter(function(name) {
return name.name === "TEST$$";
}, this);
}, this);
console.log(filter);
In this case, it returns only 1 match, where as I have 3 matches for this particular value. It returns the match from the last item in the data array and hence I dont get all the matching values, any idea how this can be looped to get all values matching?
thx!
You're reassigning the filter variable on every iteration over the data array:
filter = item.rows.filter(function(name) {
return name.name === "TEST$$";
}, this);
On the last iteration, there is only one match, the one with id of 333, so that's the only one that you see after running the Ext.each. Try pushing to an external array that doesn't get overwritten instead:
const testItems = [];
Ext.each(data, function(item) {
const filtered = item.rows.filter(row => row.name === "TEST$$")
testItems.push(...filtered);
});
console.log(testItems);
Note that there's no need to pass along the this context.
Another option is to flatMap to extract all rows to a single array first:
const output = data
.flatMap(({ rows }) => rows)
.filter(({ name }) => name === 'TEST$$');
I'm using angular 2 at the moment.
And I have array of some data
data: MyModel[] = [
{
id: 1,
name: 'Name',
secondName: 'SecondName'
}
Also MyModel is interface:
interface MyModel {
id: number,
name: string,
secondName: string
Let's imagine, that I received data from Back-End(object json):
{
id: 2,
FIRSTname: 'FName',
secondName: 'SecondName'
}
How can I validate, that keys in object are equals to my interface?
For example field "FIRSTname" is incorrect, then I should throw exception or something else.
Maybe there is a better way in typescript, in es6 you can do:
const data = [
{
id: 2,
name: 'FName',
secondName: 'SecondName'
},
{
name: 'foo',
secondName: 'bar'
},
];
const validate = ({id, name, secondName}) => id && name && secondName
const validData = data.filter(validate)
console.log(validData);
Be a ware that if one of the values: id, name, secondName, is null validate will return false.
What if I say that you can define a variable obj implementing the model interface and initialise all its property and then compare the keys of obj with the backend data lets name it respDataObj
Array.prototype.compare = function(testArr) {
if (this.length != testArr.length) return false;
for (var i = 0; i < testArr.length; i++) {
if (this[i].compare) { //To test values in nested arrays
if (!this[i].compare(testArr[i])) return false;
}
else if (this[i] !== testArr[i]) return false;
}
return true;
}
Object.keys(respDataObj).compare(Object.keys(obj))
Compare function courtesy: https://stackoverflow.com/a/6229258/2791802