So I was stuck on a bug in my React App (I am new to react and JS in general) where I wanted to filter a list of company names so that they are all unique and dont repeat. So having access to github copilot I turned it on and out came a solution that worked but I have no idea why or what its doing. If anyone could help me?
useEffect(() => {
const companyNames = data.map(app => app.companyName);
const uniqueCompanies = [...new Set(companyNames)];
setCompanies(uniqueCompanies);
},[data]);
I dont understand how [...new Set(companyNames)] filters out the unique names or what is happening. To my understanding you can only use the spread operator on an array that already exists so didn't know where the new was coming from either.
The expression const uniqueCompanies = [...new Set(companyNames)]; contains the following interesting properties:
[] is an array literal
new Set(companyNames) a new JavaScript Set that can contain only unique values by design, providing the filtering "out of the box".
... The array spread operator here will spread the Set to Array, thus effectively converting the Set to Array.
Related
There are many many threads similar to this one, but this problem it has an extra difficulty that I could not find a solution so far
I have an object like this:
I would like to deep copy this object into a new one, but for every element inside 'trainings' array I'd like to NOT copy 'sessions' and 'user' entirely
Few threads mention Lodash method _.omit() but that does not work for nested objects. Another package Deepdash has the _.deepOmit() method but the problem with that is that it does not work for keys that are Arrays.
I also tried the following solution
let filteredData = _.transform(data, function (filteredData, value, key) {
filteredData[key] = _.isArray(value) && `sessions` in value ? _.omit(value, 'sessions') : value;
});
but also unsuccessful
How can I achieve this?
This package provides the exact solution for this problem:
https://github.com/odynvolk/omit-deep-lodash
And this is the usage to achieve the solution to my problem:
let filteredData = omitDeep(data,"sessions", "user")
The following code was used to create an array containing object groups(arrays) by date. I could understand the intention but could not understand the working of the code. This is from a course by "Neil Cummings" and unfortunately I could not find his SO handle to ask him directly. Also I borrowed the course so I couldn't ask him through Q & A either.
So please consider explaining the code to me.
#computed get activitiesByDate() {
return this.groupActivitiesByDate(Array.from(this.activityRegistry.values()));
}
groupActivitiesByDate(activites: IActivity[]){
const sortedActivities = activites.sort(
(a,b) => Date.parse(a.date) - Date.parse(b.date)
)
return Object.entries(sortedActivities.reduce((activities, activity) => {
const date = activity.date.split('T')[0];
activities[date] = activities[date] ? [...activities[date], activity]: [activity];
return activities;
}, {} as {[key: string]: IActivity[]}));
}
In the code above I could understand that a new array i.e. "sortedActivities" is made by sorting the activities array. Then again the reduce function is called on it where part of date from each activity is split to find objects having same date and grouping them - which is where Object.entries comes in. What I couldn't understand how the ordering of "activites" array is affecting "sortedActivities" when actually we are sorting the activities array and also the line when ternary operator is being used. can we compare two arrays directly like that? if so why get each object from the array?. I am totally confused I tried to search some similar code to get a nice and clear explanation but I couldn't find any. Can any body please help me out. I hope I have provided enough information for the question.
Well, let's go line by line:
const sortedActivities = activites.sort(
(a,b) => Date.parse(a.date) - Date.parse(b.date)
)
Here we sort an array of activities by date, pretty simple. By there is also a very rookie mistake here (not quite sure how course author could make it), is that .sort actually mutates original array. So it is quite bad to call it like that, you need to call .slice() first to create new separate copy.
sortedActivities.reduce((activities, activity) => {
const date = activity.date.split('T')[0];
activities[date] = activities[date] ? [...activities[date], activity]: [activity];
return activities;
}, {} as {[key: string]: IActivity[]})
Then we make map of array of activities grouped by same date, so it it will be something like that in the end:
const reduceResult = {
// Might be different format for date, but you see the point
'2020-08-10': [activity, activity],
'2020-09-10': [activity],
'2020-10-10': [],
// ...
}
So this line:
activities[date] = activities[date] ? [...activities[date], activity]: [activity];
just checks if array with date key already exists, if not it creates new array, if it exists then it just merges old array with current activity
Then we return Object.entries
Object.entries(...)
Basically just grabbing all values from our map.
But there is another possible mistake (or bug) here, because author of the code assumes that creating map from sorted array will always be sorted too, but it is not, Object.entries iterates over the properties of an object in an arbitrary order, so you should not depend on that, even if it work for this case right now.
splice() mutates the original array and should be avoided. Instead, one good option is to use filter() which creates a new array so does not mutates the state. But I used to remove items from an array using splice() with spread operator.
removeItem = index => {
const items = [...this.state.items];
items.splice(index, 1);
this.setState({ items });
}
So in this case when I log items changes but this.state.items stays unchanged.
Question is, why does everyone use filter instead of splice with spread? Does it have any cons?
filter() has a more functional approach, which has its benefits. Working with immutable data is much more easier, concurrency and error safe.
But in your example, you are doing something similar by creating the items array. So you are still not mutating any existing arrays.
const items = [...this.state.items];
Creates a copy of this.state.items, thus it will not mutate them once you do a splice().
So considering you approach, it is no different than filter(), so now it just boils down to a matter of taste.
const items = [...this.state.items];
items.splice(index, 1);
VS
this.state.items.filter(i => ...);
Also performance may be taken into consideration. Check this test for example.
const items = [...this.state.items]; // spread
const mutatedItems = this.state.items.filter(() => {}) // filter
they are the same.
although i found spread line is confusing, and less intuitive than filter.
but i prefer destructuring:
const { items } = this.state // destructure
item.splice()
why? because sometimes within a function/method i have other destructuring assignment such
const { modalVisible, user } = this.state
So i think why not destructure item as well there.
For some who writes a lot of codes in multiple codebase, it would help a lot to work on on "how accurate, and fast can this code skimmed?" as i myself dont really remember what i wrote last week.
While using spread would make me write more lines and doesnt help me when re-read it next month.
I am working on Angular 4 application.
I found below code in my application but unable to find exact purpose of below code.
getManagementView(groupField: string) {
this.auditList = [...this.auditList.filter(this.filterByRevisit)];
}
I changed it to below code both are working fine.
getManagementView(groupField: string) {
this.auditList = this.auditList.filter(this.filterByRevisit);
}
Could any one help me to understand what is the difference in above two code blocks.
There is noting different. The spread (...) operator destroys the array and gives back the elements one by one and then in the [] put them into the making again an array. Which is actually extra operation.
So this.auditList.filter(this.filterByRevisit) returns an array,
and this [...this.auditList.filter(this.filterByRevisit)] returns an array which is spread and again makes an array.
I don't think there is a difference between the two. ... would create a new array, filter already did it.
However if I take the title:
this.array = this.array // does nothing, same object
this.array = [...this.array] // creates a new array, though the same content
I'm feeling my way though functional programming with Ramda and I'm struggling on something sounds like it should be easy.
I want all the entries in an array where a property does not equal a value.
For example in pure js
const filtered = source.filter(entry => entry.name !== 'something');
In Ramda there is a propEq so I can easily get all the elements that do match a value such as
const filtered = R.filter(R.propEq('name','something'),source);
But I can't see how to do the inverse of that, to only return values that do not equal a value.
I'm sure this must be very easy but I'm struggling to see a built in function to do it, the closest I can come up with is:
const others = R.filter(rate => rate.name !== name,res.rates);
But I'm sure there must be a better way?
Yes, Ramda has a reverse of filter called reject:
R.reject(R.propEq('name', 'something'))(source)
You can see this on the Ramda REPL