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.
This is my code in RxJs6:
const observable$ = interval(1000).pipe(
take(2),
map(x => interval(1500).pipe(
map(y => x+':'+y),
take(2),
concatAll()
)),
);
observable$.subscribe(obs => {
obs.subscribe(x => console.log(x));
});
I expect my code show the result like this:
0:0
1:0
0:1
1:1
But it actually shows:
why my code print data only one character every time ? And I think it should work like what i expected above not the actual result. anything wrong i understand about rxjs ?
This is because of concatAll(). It's typically used to flatten nested Observables but it can work with Promises and arrays (array-like objects) as well. Ant this is exactly what you're seeing here.
It thinks you want to flatten an array even when you have a string so it takes each item in the array (character in your case) and reemits it separately.
However, another question is what you wanted to achieve with concatAll.
I want to left join 2 Observables such that I always take the value from ObservableA, unless there is a corresponding value from ObservableB. In which case I want to use the value from ObservableB. The two Observables should join so will be a akin to a SQL left join.
From reading the RxJS Operators tree it does seem to me that Join would be the logical choice. I am unclear on how the join window works and how to ensure either observable could result in a join happening.
Can anyone provide a simple example?
You can do this easily with just merge where you put ObservableB first and then use take(1) to complete immediately. If ObservableB was empty then it'll emit the value from ObservableA.
const a$ = of(1);
const b$ = of('a');
merge(b$, a$)
.pipe(
take(1),
)
.subscribe(console.log);
Live demo: https://stackblitz.com/edit/rxjs6-demo-u5syjx?file=index.ts
There seems to be no out of the box operator for this. But you may want to zip first, then map the results with your custom logic to get what you want:
zip(observableA, observableB).map([a,b] =>{
if(idMatchesWithB) {return b}
else {return a}
}
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
I'm learning lodash. Is it possible to use lodash to find a substring in an array of strings?
var myArray = [
'I like oranges and apples',
'I hate banana and grapes',
'I find mango ok',
'another array item about fruit'
]
is it possible to confirm if the word 'oranges' is in my array?
I've tried _.includes, _.some, _.indexOf but they all failed as they look at the full string, not a substring
You can easily construct an iteratee for some() using lodash's higher-order functions. For example:
_.some(myArray, _.unary(_.partialRight(_.includes, 'orange')));
The unary() function ensures that only one argument is passed to the callback. The partialRight() function is used to apply the 'orange' value as the second argument to includes(). The first argument is supplied with each iteration of some().
However, this approach won't work if case sensitivity matters. For example, 'Orange' will return false. Here's how you can handle case sensitivity:
_.some(myArray, _.method('match', /Orange/i));
The method() function creates a function that will call the given method of the first argument passed to it. Here, we're matching against a case-insensitive regular expression.
Or, if case-sensitivity doesn't matter and you simply prefer the method() approach, this works as well for ES2015:
_.some(myArray, _.method('includes', 'orange'));
Two quick ways to do it - neither uses lodash (sorry)
var found = myArray.filter(function(el){
return el.indexOf('oranges') > -1;
}).length;
if (found) { // oranges was found }
or as I mentioned in the comment:
var found = myArray.join(',').indexOf('oranges') > -1;
if (found) { // oranges was found }
You can do this using lodash, but it's also very doable using native javascript methods:
function stringArrayContains(array, str) {
function contains(el) {
return (el.indexOf(str) !== -1) ? true : false;
}
return array.some(contains);
}
Testing the above function:
var a = ['hello', 'there'];
var b = ['see', 'ya', 'later'];
stringArrayContains(a, 'ell') // true
stringArrayContains(a, 'what') // false
stringArrayContains(b, 'later') // true
stringArrayContains(b, 'hello') // false
Array.prototype.some applies a function you define to every element of an array. This function (named contains in our case) must return true or false. While iterating through the array elements, if any of the elements returns true, the some method returns true.
Personally, I think in general that if you can use native JS methods for simple functions, it's preferable to loading an library just to do the same thing. Lodash absolutely does have performance benefits, but they aren't necessarily realized unless you're processing large amounts of data. Just my two cents.
Cheers!
The best way is to define a function to check the inclusion of a substring.
var contains = _.curry(function (substring, source) {
return source.indexOf(substring) !== -1;
});
I use _.curry here to get a curried function, which can be partially applied then.
_.some(myArray, contains('item'));
You can also find a substring in a joined string.
contains('item', _.join(myArray))
UPD:
I have not noticed that lodash already has a function to find value in a collection.
The function _.includes is quite the same to what I defined above. However, as everything in lodash, it uses the different order for arguments. In my example, I put a source as the latest argument for a curried function which makes my function useful for point-free style programming when lodash waits for the source as a first argument of the same function.
Check the Brian Lonsdorf's talk on this matter https://www.youtube.com/watch?v=m3svKOdZijA
Also take a chance to look into ramda. This library provides a better way for practical functional programming in JavaScript.
I ran into this Question / Answer thread while trying to figure out how to match a substring against each String in an Array and REMOVE any array item that contains that substring.
While the above answers put me on track, and while this doesn't specifically answer the original question, this thread DOES appear first in the google search when you are trying to figure out how to accomplish the above removal of an array item so I figured I would post an answer here.
I ended up finding a way to use Lodash's _.remove function to remove matching array strings as follows:
// The String (SubString) we want to match against array (for dropping purposes)
var searchSubString = "whatever"
// Remove all array items that contain the text "whatever"
_.remove(my_array, function(searchSubString) {
return n.indexOf(searchSubString) !== -1;
});
Basically indexOf is matching against the position of the substring within the string, if the substring is not found it will return -1, when indexOf returns a number other than -1 (the number is the SubString position in number of characters within the Array string).
Lodash removes that Array item via array mutation and the newly modified array can be accessed by the same name.
_.some(myArray, function(str){
return _.includes(str, 'orange')
})
let str1 = 'la rivière et le lapin sont dans le près';
let str2 = 'product of cooking class';
let str3 = 'another sentence to /^[analyse]/i with weird!$" chars#';
_.some(_.map(['rabbit','champs'], w => str1.includes(w)), Boolean), // false
_.some(_.map(['cook'], w => str2.includes(w)), Boolean), // true
_.some(_.map(['analyse'], w => str3.includes(w)), Boolean), // true