i created multiple conditions by using map, but i think there are other methods to optimize this code:
if (content.risks) {
content.risks.map((risk) => {
if (risk.coverageCode === "PUB" || risk.coverageCode === "SPPI" || risk.coverageCode === "PROD" || risk.coverageCode === "PR" || risk.coverageCode === "DO") {
risk._class = "com.generali.gip.local.hk.domain.RiskPublicLiability";
}
if (risk.coverageCode === "PD") {
risk._class = "com.generali.gip.local.hk.domain.RiskMaterialDamage";
}
if (risk.coverageCode === "BI") {
risk._class = "com.generali.gip.local.hk.domain.RiskBusinessInterruption";
}
});
}
How i can to rewrite this code by using find or indexof?
My objective in software development is to express my intents in a way that is clear and unambiguous.
For this kind of "problems", I will always reach out for the humble map. There's no extra ceremonies (i.e. if/else, switch/case, etc.). It just says "if you give me an X, I'll give you a Y".
const risk_map =
{ PUB: "com.generali.gip.local.hk.domain.RiskPublicLiability"
, SPPI: "com.generali.gip.local.hk.domain.RiskPublicLiability"
, PROD: "com.generali.gip.local.hk.domain.RiskPublicLiability"
, PR: "com.generali.gip.local.hk.domain.RiskPublicLiability"
, DO: "com.generali.gip.local.hk.domain.RiskPublicLiability"
, PD: "com.generali.gip.local.hk.domain.RiskMaterialDamage";
, BI: "com.generali.gip.local.hk.domain.RiskBusinessInterruption"
};
Regardless of your programming background, the "time to get it" is low.
It can indeed lead to duplication but I don't think it comes at the expense of readability or maintenance. (How hard would it be to replace these duplicated strings with a constant for example?)
Now how can we "query" this map? Let's build a high-order function for that:
We say "Give me a map, then give me a key, I'll get you a value":
const get_value = map => key => map[key];
get_value(risk_map)("PUB");
//=> "com.generali.gip.local.hk.domain.RiskPublicLiability"
The get_value is a high-order function. We're meant to build specialised functions out of it. Let's just do that:
const get_risk = get_value(risk_map);
get_risk("PUB");
//=> "com.generali.gip.local.hk.domain.RiskPublicLiability"
With this we can solve your "problem" quite simply:
const content_risks =
content.risks
? content.risks.map(risk => get_risk(risk.coverageCode))
: null;
I'll leave it as an exercise to combine and adapt this to fit your exact needs.
Hope this helps though.
Related
I am working with a child component where an array item is passed as prop. However, that item also contains another array where there should be null and undefined check before rendering. Adding || [] to each filed didn't seem the best way. Is there a better way that I am missing?
const ChildComponent= ({ newsItem, textColor, newsItemHeadingColor }) => {
const imageFormats = newsItem?.itemImage?.formats;
const imageSrc = useProgressiveImage({ formats: imageFormats });
const history = useHistory();
const { state } = useContextState();
const { schemeMode, colorSchemes } = state;
const { itemTagColor, itemTagTextColor } = getThemeColors({
schemeMode,
colorSchemes,
colors: {
itemTagColor: newsItem?.itemTagColor?.name,
itemTagTextColor: newsItem?.itemTagTextColor?.name,
},
});
return (
<NewsItem
onClick={() => {
const url =
newsItem?.itemTag === 'Lab'
? getPageLink({
page: newsItem?.itemLink || [], <<<<<< this check
})
: newsItem?.itemLink || []; <<<<<< this check
url && history.push(url);
}}
>
<ImageContainer>
<Image src={imageSrc} alt={`${newsItem?.itemImage || []}`} /> <<<<<< this check
</ImageContainer>
<NewsItemTag color={itemTagColor} itemTagTextColor={itemTagTextColor}>
<Body4>{`${newsItem?.itemTag || []}`}</Body4> <<<<<< this check
</NewsItemTag>
<NewsItemName newsItemHeadingColor={newsItemHeadingColor}>{`${
newsItem?.itemTitle || [] <<<<<< this check
}`}</NewsItemName>
<Description textColor={textColor}>{`${
(newsItem.description &&
newsItem?.itemDescription) || [] <<<<<< this check
}`}</Description>
</NewsItem>
);
};
In fact yes, you have many many ways for improving your code and the readabilty of it.
In your <NewItem /> onClick function:
I have nothing to say for the first one, it seems correct since you want the item link or an empty array
For the second one, your are already using the optional chaining operator, the "?". This operator check if there is a value, if not, it returns null. That means that should be enough, since you check after your url variable is defined or not. So simply write that : : newsItem?.itemLink
For the third one, the one on your <Image /> component, First there is no need at all to put everything in backquote. Simply alt={newsItem?.itemImage || []} should work fine. Then, alt attribute is taking a string, so maybe change it with alt={newsItem?.itemImage || ""}
For the three last one, they are basically the same, you have content to display and you want to display nothing if there are empty. The fact here is that your are rendering some elements even if there is no content and this is not an optimized way. The cleanest way in my opinion in order to make your template more readable will be to define variable before your return function and based on this variable, you will display the appropriate section :
Before your return function:
const hasTag = !!newsItem?.itemTag;
const hasTitle = !!newsItem?.itemTitle;
const hasDescription = !!newsItem.description && !!newsItem?.itemDescription;
In your template:
{hasTag && <NewsItemTag color={itemTagColor} itemTagTextColor={itemTagTextColor}>
<Body4>{newsItem.itemTag}</Body4>
</NewsItemTag>}
{hasTitle && <NewsItemName newsItemHeadingColor={newsItemHeadingColor}>
{newsItem.itemTitle}
</NewsItemName>
{hasDescription && <Description textColor={textColor}>
{newsItem.itemDescription}
</Description>
I hope this was clear, hit me up if this wasn't.
Happy coding :)
There are multiple ways that you could handle this in javascript, assume that we have a component that receives a prop called newsItem which is an object
You could do that in the following ways
Using the logical operator or (es6)
const itemLinks = newsItem.links || []
you dont need the optional chaining operator (?.) here if you know that newsItem is an object and not undefined.
This is the shortest syntax, and it works fine as long as links is either undefined or an array
however it becomes problematic if later links become a boolean variable, which will yield incorrect results
This method is not safe, and it becomes cumbersome to handle as properties become nested deeply
Using lodash get method or some other library or a custom solution (es6)
because in es6 the only practical way was to either the logical operator and this was a common problem, custom solutions were brought it, basically any solution should have two advantages over the logical or operator
They should work fine with boolean values
They should be easier to work with deeply nested values
custom someDeepleyNested = get(newsItem, 'property1.property2.property3', 'defaultValue')
// there is no need for property1, property2, property3 to exist at all
Optional chaining operator and Nullish coalescing Operator (stage 4 finished proposals)
Because this was a common problem for all javascript developers,the language had to bring a native solution
const someNestedProperty = newsItem?.property1?.property2?.property3 ?? 'someDefaultValue'
// notice that both the Optional chaining operator and Nullish coalescing Operator, work with both undefined and null
Specific to react: use default props
const Component = ({newsLink}) => {}
Component.defaultProps = {
newsItem: {
itemLinks: []
}
}
I already searched for similar issues but I didn't find anything that could help me yet.
I'm trying to reach a picture path (using JSON format) depending on the material type of the picked element. Actually, my code is built like this:
if (globalData.Material.Mat_type == "OSCILLOSCOPE") {
var picture = (globalData.Material.Oscilloscope.picture);
}
if (globalData.Material.Mat_type == "ALIMENTATION") {
var picture = (globalData.Material.Alim.picture);
}
But not optimized at all, so Im trying to make it this way :
var mat_type = (globalData.Material.Mat_type);
var picture = (globalData.Material[mat_type].picture);
But it doesn't work... Got some exception:
TypeError : globalData.Material[mat_type] is undefined.
I already tried a lot of things, have you got any idea? Thanks!
I outlined the issue with character case in the comment under the question, so presumably adjusting value of globalData.Material.Mat_type could do the trick:
var mat_type =
globalData.Material.Mat_type.charAt(0).toUpperCase() +
globalData.Material.Mat_type.substr(1).toLowerCase();
I can also see that this general rule may not be applicable in all cases. If it's not a typo, it won't work for the second case where Mat_type == "ALIMENTATION", because then you try to access Alim property of Material instead of Alimentation. In this case you could access property by prefix:
function pictureOf(material) {
if (!material || !String(material.Mat_type)) {
return null;
}
let mat_type = String(material.Mat_type).toUpperCase();
for (var propertyName in material) {
if (mat_type.startsWith(propertyName.toUpperCase())) {
return material[propertyName].picture || null;
}
}
return null;
}
console.log(pictureOf({
Mat_type: "OSCILLOSCOPE",
Oscilloscope: {
picture: "picture of oscilloscope"
}
}));
console.log(pictureOf({
Mat_type: "ALIMENTATION",
Alim: {
picture: "picture of alimentation"
}
}));
But this kind of approach can be error prone, if multiple properties share the same prefix. There's also a hidden issue with case-insensitive prefix matching in case you use some special unicode characters in property names. Lastly this method is not efficient, because it has to iterate over all properties of the object (worst case scenario). It can be replaced with much safer property mapping:
const matTypeMapping = {
"ALIMENTATION": "Alim"
};
function pictureOf(material) {
if (!material || !String(material.Mat_type)) {
return null;
}
let matType = String(material.Mat_type);
// find property mapping or apply general rule, if mapping not defined
let propertyName = matTypeMapping[matType] ||
matType.charAt(0).toUpperCase() + matType.substr(1).toLowerCase();
return material[propertyName].picture || null;
}
console.log(pictureOf({
Mat_type: "OSCILLOSCOPE",
Oscilloscope: {
picture: "picture of oscilloscope"
}
}));
console.log(pictureOf({
Mat_type: "ALIMENTATION",
Alim: {
picture: "picture of alimentation"
}
}));
NB: To avoid headaches, maybe you should prefer strict equality operator over loose equality operator.
Problem Solved
Peter Wolf was right ! It was a case-sensitive issue
I actually don't know how to promote his comment, sorry for this..
Anyway, thank you guys !
var mat_type = (globalData.Material.Mat_type);
if(mat_type!==undefined)
var picture = (globalData.Material[mat_type].picture)
Just do an existential check before accessing the value, for keys that may not be present.
PS: I have already searched the forums and have seen the relevant posts for this wherein the same post exists but I am not able to resolve my issue with those solutions.
I have 2 json objects
var json1 = [{uid:"111", addrs:"abc", tab:"tab1"},{uid:"222", addrs:"def", tab:"tab2"}];
var json2 = [{id:"tab1"},{id:"new"}];
I want to compare both these and check if the id element in json2 is present in json1 by comparing to its tab key. If not then set some boolean to false. ie by comparing id:"tab1" in json2 to tab:"tab1 in json1 .
I tried using below solutions as suggested by various posts:
var o1 = json1;
var o2 = json2;
var set= false;
for (var p in o1) {
if (o1.hasOwnProperty(p)) {
if (o1[p].tab!== o2[p].id) {
set= true;
}
}
}
for (var p in o2) {
if (o2.hasOwnProperty(p)) {
if (o1[p].tab!== o2[p].id) {
set= true;
}
}
}
Also tried with underscore as:
_.each(json1, function(one) {
_.each(json2, function(two) {
if (one.tab!== two.id) {
set= true;
}
});
});
Both of them fail for some test case or other.
Can anyone tell any other better method or outline the issues above.
Don't call them JSON because they are JavaScript arrays. Read What is JSON.
To solve the problem, you may loop over second array and then in the iteration check if none of the objects in the first array matched the criteria. If so, set the result to true.
const obj1 = [{uid:"111", addrs:"abc", tab:"tab1"},{uid:"222",addrs:"def", tab:"tab2"}];
const obj2 = [{id:"tab1"},{id:"new"}];
let result = false;
for (let {id} of obj2) {
if (!obj1.some(i => i.tab === id)) {
result = true;
break;
}
}
console.log(result);
Unfortunately, searching the forums and reading the relevant posts is not going to replace THINKING. Step away from your computer, and write down, on a piece of paper, exactly what the problem is and how you plan to solve it. For example:
Calculate for each object in an array whether some object in another array has a tab property whose value is the same as the first object's id property.
There are many ways to do this. The first way involves using array functions like map (corresponding to the "calculate for each" in the question, and some (corresponding to the "some" in the question). To make it easier, and try to avoid confusing ourselves, we'll do it step by step.
function calculateMatch(obj2) {
return obj2.map(doesSomeElementInObj1Match);
}
That's it. Your program is finished. You don't even need to test it, because it's obviously right.
But wait. How are you supposed to know about these array functions like map and some? By reading the documentation. No one help you with that. You have to do it yourself. You have to do it in advance as part of your learning process. You can't do it at the moment you need it, because you won't know what you don't know!
If it's easier for you to understand, and you're just getting started with functions, you may want to write this as
obj2.map(obj1Element => doesSomeElementInObj1Match(obj1Element))
or, if you're still not up to speed on arrow functions, then
obj2.map(function(obj1Element) { return doesSomeElementInObj1Match(obj1Element); })
The only thing left to do is to write doesSomeElementInObj2Match. For testing purposes, we can make one that always returns true:
function doesSomeElementInObj2Match() { return true; }
But eventually we will have to write it. Remember the part of our English description of the problem that's relevant here:
some object in another array has a tab property whose value is the same as the first object's id property.
When working with JS arrays, for "some" we have the some function. So, following the same top-down approach, we are going to write (assuming we know what the ID is):
In the same way as above, we can write this as
function doesSomeElementInObj2Match(id) {
obj2.some(obj2Element => tabFieldMatches(obj2Element, id))
}
or
obj2.some(function(obj2Element) { return tabFieldMatches(obj2Element, id); })
Here, tabFieldMatches is nothing more than checking to make sure obj2Element.tab and id are identical.
We're almost done! but we still have to write hasMatchingTabField. That's quite easy, it turns out:
function hasMatchingTabField(e2, id) { return e2.tab === id; }
In the following, to save space, we will write e1 for obj1Element and e2 for obj2Element, and stick with the arrow functions. This completes our first solution. We have
const tabFieldMatches = (tab, id) { return tab === id; }
const hasMatchingTabField = (obj, id) => obj.some(e => tabFieldMatches(e.tab, id);
const findMatches = obj => obj.some(e => hasMatchingTabField(e1, obj.id));
And we call this using findMatches(obj1).
Old-fashioned array
But perhaps all these maps and somes are a little too much for you at this point. What ever happened to good old-fashioned for-loops? Yes, we can write things this way, and some people might prefer that alternative.
top: for (e1 of obj1) {
for (e2 of (obj2) {
if (e1.id === e2.tab) {
console.log("found match");
break top;
}
}
console.log("didn't find match);
}
But some people are sure to complain about the non-standard use of break here. Or, we might want to end up with an array of boolean parallel to the input array. In that case, we have to be careful about remembering what matched, at what level.
const matched = [];
for (e1 of obj1) {
let match = false;
for (e2 of obj2) {
if (e1.id === e2.tab) match = true;
}
matched.push(match);
}
We can clean this up and optimize it bit, but that's the basic idea. Notice that we have to reset match each time through the loop over the first object.
I am writing some code that needs to loop through an array of objects continuously. There are several types of blocks, such as bricks, metal or sand, and I update their position and whether or not a player is touching them in one foreach loop.
The sand needs to have a method by which it falls down when the player is standing on it. What is the best way in javascript to run a method specific to the sand object from within the foreach loop?
I would just use an if statement within the forEach. For example:
const playerPosition = ...
const arrayOfBlocks = [ ... ]
arrayOfBlocks.forEach(block => {
if (block.type === 'sand' && playerPosition === block.position) {
block.fall()
}
})
A different approach would be to just filter both the type and position. For example:
const playerPosition = ...
const arrayOfBlocks = [ ... ]
arrayOfBlocks
.filter(block => block.type === 'sand')
.filter(block => block.position === player.position)
.forEach(block => black.fall())
I have been experimenting with RxJS for two weeks now, and although I love it in principle I just cannot seem to find and implement the correct pattern for managing state. All articles and questions appear to agree:
Subject should be avoided where possible in favor of just pushing state through via transformations;
.getValue() should be deprecated entirely; and
.do should perhaps be avoided except for DOM manipulation?
The problem with all such suggestions is that none of the literature appears to directly say what you should be using instead, besides "you'll learn the Rx way and stop using Subject".
But I cannot find a direct example anywhere that specifically indicates the correct way to perform both additions and removals to a single stream/object, as the consequence of multiple other stream inputs, in a stateless and functional manner.
Before I get pointed in the same directions again, problems with uncovered literature are:
The Introduction to Reactive Programming You've been missing: great starting text, but does not specifically address these questions.
The TODO example for RxJS comes with React and involves explicit manipulation of Subjects as proxies for React Stores.
http://blog.edanschwartz.com/2015/09/18/dead-simple-rxjs-todo-list/ : explicitly uses a state object for addition and removal of items.
My perhaps 10th rewrite of the standard TODO follows - My prior iterations covered include:
starting with a mutable 'items' array - bad as state is explicit and imperatively managed
using scan to concatenate new items to an addedItems$ stream, then branching another stream where the removed items were deleted - bad as the addedItems$ stream would grow indefinitely.
discovering BehaviorSubjectand using that - seemed bad since for each new updatedList$.next() emission, it requires the previous value to iterate, meaning that Subject.getValue() is essential.
trying to stream the result of the inputEnter$ addition events into filtered removal events - but then every new stream creates a new list, and then feeding that into the toggleItem$ and toggleAll$ streams means that each new stream is dependent on the previous, and so causing one of the 4 actions (add, remove, toggle item or toggle all) requires the whole chain to be unnecessarily run through again.
Now I have come full circle, where I am back to using both Subject (and just how is it supposed to be successively iterated upon in any way without using getValue()?) and do, as show below. Myself and my colleague agree this is the clearest way, yet it of course seems the least reactive and most imperative. Any clear suggestions on the correct way for this would be much appreciated!
import Rx from 'rxjs/Rx';
import h from 'virtual-dom/h';
import diff from 'virtual-dom/diff';
import patch from 'virtual-dom/patch';
const todoListContainer = document.querySelector('#todo-items-container');
const newTodoInput = document.querySelector('#new-todo');
const todoMain = document.querySelector('#main');
const todoFooter = document.querySelector('#footer');
const inputToggleAll = document.querySelector('#toggle-all');
const ENTER_KEY = 13;
// INTENTS
const inputEnter$ = Rx.Observable.fromEvent(newTodoInput, 'keyup')
.filter(event => event.keyCode === ENTER_KEY)
.map(event => event.target.value)
.filter(value => value.trim().length)
.map(value => {
return { label: value, completed: false };
});
const inputItemClick$ = Rx.Observable.fromEvent(todoListContainer, 'click');
const inputToggleAll$ = Rx.Observable.fromEvent(inputToggleAll, 'click')
.map(event => event.target.checked);
const inputToggleItem$ = inputItemClick$
.filter(event => event.target.classList.contains('toggle'))
.map((event) => {
return {
label: event.target.nextElementSibling.innerText.trim(),
completed: event.target.checked,
};
})
const inputDoubleClick$ = Rx.Observable.fromEvent(todoListContainer, 'dblclick')
.filter(event => event.target.tagName === 'LABEL')
.do((event) => {
event.target.parentElement.classList.toggle('editing');
})
.map(event => event.target.innerText.trim());
const inputClickDelete$ = inputItemClick$
.filter(event => event.target.classList.contains('destroy'))
.map((event) => {
return { label: event.target.previousElementSibling.innerText.trim(), completed: false };
});
const list$ = new Rx.BehaviorSubject([]);
// MODEL / OPERATIONS
const addItem$ = inputEnter$
.do((item) => {
inputToggleAll.checked = false;
list$.next(list$.getValue().concat(item));
});
const removeItem$ = inputClickDelete$
.do((removeItem) => {
list$.next(list$.getValue().filter(item => item.label !== removeItem.label));
});
const toggleAll$ = inputToggleAll$
.do((allComplete) => {
list$.next(toggleAllComplete(list$.getValue(), allComplete));
});
function toggleAllComplete(arr, allComplete) {
inputToggleAll.checked = allComplete;
return arr.map((item) =>
({ label: item.label, completed: allComplete }));
}
const toggleItem$ = inputToggleItem$
.do((toggleItem) => {
let allComplete = toggleItem.completed;
let noneComplete = !toggleItem.completed;
const list = list$.getValue().map(item => {
if (item.label === toggleItem.label) {
item.completed = toggleItem.completed;
}
if (allComplete && !item.completed) {
allComplete = false;
}
if (noneComplete && item.completed) {
noneComplete = false;
}
return item;
});
if (allComplete) {
list$.next(toggleAllComplete(list, true));
return;
}
if (noneComplete) {
list$.next(toggleAllComplete(list, false));
return;
}
list$.next(list);
});
// subscribe to all the events that cause the proxy list$ subject array to be updated
Rx.Observable.merge(addItem$, removeItem$, toggleAll$, toggleItem$).subscribe();
list$.subscribe((list) => {
// DOM side-effects based on list size
todoFooter.style.visibility = todoMain.style.visibility =
(list.length) ? 'visible' : 'hidden';
newTodoInput.value = '';
});
// RENDERING
const tree$ = list$
.map(newList => renderList(newList));
const patches$ = tree$
.bufferCount(2, 1)
.map(([oldTree, newTree]) => diff(oldTree, newTree));
const todoList$ = patches$.startWith(document.querySelector('#todo-list'))
.scan((rootNode, patches) => patch(rootNode, patches));
todoList$.subscribe();
function renderList(arr, allComplete) {
return h('ul#todo-list', arr.map(val =>
h('li', {
className: (val.completed) ? 'completed' : null,
}, [h('input', {
className: 'toggle',
type: 'checkbox',
checked: val.completed,
}), h('label', val.label),
h('button', { className: 'destroy' }),
])));
}
Edit
In relation to #user3743222 very helpful answer, I can see how representing state as an additional input can make a function pure and thus scan is the best way to represent a collection evolving over time, with a snapshot of its previous state up to that point as an additional function parameter.
However, this was already how I approached my second attempt, with addedItems$ being a scanned stream of inputs:
// this list will now grow infinitely, because nothing is ever removed from it at the same time as concatenation?
const listWithItemsAdded$ = inputEnter$
.startWith([])
.scan((list, addItem) => list.concat(addItem));
const listWithItemsAddedAndRemoved$ = inputClickDelete$.withLatestFrom(listWithItemsAdded$)
.scan((list, removeItem) => list.filter(item => item !== removeItem));
// Now I have to always work from the previous list, to get the incorporated amendments...
const listWithItemsAddedAndRemovedAndToggled$ = inputToggleItem$.withLatestFrom(listWithItemsAddedAndRemoved$)
.map((item, list) => {
if (item.checked === true) {
//etc
}
})
// ... and have the event triggering a bunch of previous inputs it may have nothing to do with.
// and so if I have 400 inputs it appears at this stage to still run all the previous functions every time -any- input
// changes, even if I just want to change one small part of state
const n$ = nminus1$.scan...
The obvious solution would be to just have items = [], and manipulate it directly, or const items = new BehaviorSubject([]) - but then the only way to iterate on it appears to be using getValue to expose the previous state, which Andre Stalz (CycleJS) has commented on in the RxJS issues as something that shouldn't really be exposed (but again, if not, then how is it usable?).
I guess I just had an idea that with streams, you weren't supposed to use Subjects or represent anything via a state 'meatball', and in the first answer I'm not sure how this doesn't introduce mass chained streams which are orphaned/grow infinitely/have to build on each other in exact sequence.
I think you already found a good example with : http://jsbin.com/redeko/edit?js,output.
You take issue with the fact that this implementation
explicitly uses a state object for addition and removal of items.
However, thas is exactly the good practice you are looking for. If you rename that state object viewModel for example, it might be more apparent to you.
So what is state?
There will be other definitions but I like to think of state as follows:
given f an impure function, i.e. output = f(input), such that you can have different outputs for the same input, the state associated to that function (when it exists) is the extra variable such that f(input) = output = g(input, state) holds and g is a pure function.
So if the function here is to match an object representing a user input, to an array of todo, and if I click add on a todo list with already have 2 todos, the output will be 3 todos. If I do the same (same input) on a todo list with only one todo, the output will be 2 todos. So same input, different outputs.
The state here that allows to transform that function into a pure function is the current value of the todo array. So my input becomes an add click, AND the current todo array, passed through a function g which give a new todo array with a new todo list. That function g is pure. So f is implemented in a stateless way by making its previously hidden state explicit in g.
And that fits well with functional programming which revolves around composing pure functions.
Rxjs operators
scan
So when it comes to state management, with RxJS or else, a good practice is to make state explicit to manipulate it.
If you turn the output = g(input, state) into a stream, you get On+1 = g(In+1, Sn) and that's exactly what the scan operator does.
expand
Another operator which generalizes scan is expand, but so far I had very little use of that operator. scan generally does the trick.
Sorry for the long and mathy answer. It took me a while to get around those concepts and that's the way I made them understandable for me. Hopefully it works for you too.