Add "reduce" and "filter" operators

optimising-macrocalls
jeremy@jermolene.com 2020-10-06 19:20:03 +01:00
rodzic 0027b990e4
commit 14a28b7779
11 zmienionych plików z 228 dodań i 4 usunięć

Wyświetl plik

@ -0,0 +1,31 @@
/*\
title: $:/core/modules/filters/filter.js
type: application/javascript
module-type: filteroperator
Filter operator returning those input titles that pass a subfilter
\*/
(function(){
/*jslint node: true, browser: true */
/*global $tw: false */
"use strict";
/*
Export our filter function
*/
exports.filter = function(source,operator,options) {
var filterFn = options.wiki.compileFilter(operator.operand),
results = [],
target = operator.prefix !== "!";
source(function(tiddler,title) {
var list = filterFn.call(options.wiki,options.wiki.makeTiddlerIterator([title]));
if((list.length > 0) === target) {
results.push(title);
}
});
return results;
};
})();

Wyświetl plik

@ -0,0 +1,54 @@
/*\
title: $:/core/modules/filters/reduce.js
type: application/javascript
module-type: filteroperator
Filter operator evaluats a subfilter for each item, making the running total available in the variable `accumulator`, and the current index available in the variable `index`
\*/
(function(){
/*jslint node: true, browser: true */
/*global $tw: false */
"use strict";
/*
Export our filter function
*/
exports.reduce = function(source,operator,options) {
// Accumulate the list
var results = [];
source(function(tiddler,title) {
results.push(title);
});
// Run the filter over each item
var filterFn = options.wiki.compileFilter(operator.operand),
accumulator = operator.suffix || "";
for(var index=0; index<results.length; index++) {
var title = results[index],
list = filterFn.call(options.wiki,options.wiki.makeTiddlerIterator([title]),{
getVariable: function(name) {
switch(name) {
case "currentTiddler":
return "" + title;
case "accumulator":
return "" + accumulator;
case "index":
return "" + index;
case "revIndex":
return "" + (results.length - 1 - index);
case "length":
return "" + results.length;
default:
return options.widget.getVariable(name);
}
}
});
if(list.length > 0) {
accumulator = "" + list[0];
}
}
return [accumulator];
};
})();

Wyświetl plik

@ -0,0 +1,9 @@
created: 20201004145650743
modified: 20201006181234412
price: 4.99
quantity: 1
tags: shopping
title: Brownies
type: text/vnd.tiddlywiki
//This is a sample shopping list item for the [[Shopping List Example]]//

Wyświetl plik

@ -0,0 +1,9 @@
created: 20201004145612358
modified: 20201006181232439
price: 1.32
quantity: 5
tags: shopping
title: Chick Peas
type: text/vnd.tiddlywiki
//This is a sample shopping list item for the [[Shopping List Example]]//

Wyświetl plik

@ -0,0 +1,9 @@
created: 20201004145636906
modified: 20201006181233518
price: 0.46
quantity: 12
tags: shopping
title: Milk
type: text/vnd.tiddlywiki
//This is a sample shopping list item for the [[Shopping List Example]]//

Wyświetl plik

@ -0,0 +1,9 @@
created: 20201004145502135
modified: 20201006181230956
price: 2.66
quantity: 4
tags: shopping
title: Rice Pudding
type: text/vnd.tiddlywiki
//This is a sample shopping list item for the [[Shopping List Example]]//

Wyświetl plik

@ -0,0 +1,23 @@
created: 20201004141030951
modified: 20201004143326056
tags: [[Operator Examples]] [[filter Operator]]
title: filter Operator (Examples)
type: text/vnd.tiddlywiki
\define larger-than-1k() [get[text]length[]compare:integer:gteq[1000]]
\define smaller-than-2k() [get[text]length[]compare:integer:lteq[2000]]
\define contains-missing-links() [links[]!is[shadow]is[missing]]
\define display-variable(name)
''<$text text=<<__name__>>/>'': <code><$text text={{{ [<__name__>getvariable[]] }}}/></code>
\end
These examples use the following predefined variables:
* <<display-variable larger-than-1k>>
* <<display-variable smaller-than-2k>>
* <<display-variable contains-missing-links>>
<<.operator-example 1 "[tag[HelloThere]filter<larger-than-1k>]">>
<<.operator-example 2 "[tag[HelloThere]filter<smaller-than-2k>]">>
<<.operator-example 3 "[tag[HelloThere]filter<larger-than-1k>filter<smaller-than-2k>]">>
<<.operator-example 4 "[tag[Features]filter<contains-missing-links>]">>

Wyświetl plik

@ -1,16 +1,34 @@
created: 20201004154413968
modified: 20201004154413968
modified: 20201006181831622
tags: [[Operator Examples]] [[reduce Operator]]
title: reduce Operator (Examples)
type: text/vnd.tiddlywiki
\define add-numbers() [get[text]length[]compare:integer:gteq[1000]]
\define add-price() [get[price]multiply{!!quantity}add<accumulator>]
\define num-items() [get[quantity]add<accumulator>]
\define display-variable(name)
''<$text text=<<__name__>>/>'': <code><$text text={{{ [<__name__>getvariable[]] }}}/></code>
\end
These examples use the following predefined variables:
* <<display-variable add-numbers>>
* <<display-variable add-price>>
* <<display-variable num-items>>
<<.operator-example 1 "[tag[HelloThere]filter<larger-than-1k>]">>
They also use the following data tiddlers:
<ul>
<$list filter="[tag[shopping]!has[draft.of]]">
<li>
''<$link><$text text=<<currentTiddler>>/></$link>'' quantity: <$text text={{!!quantity}}/>, price: <$text text={{!!price}}/>
</li>
</$list>
</ul>
Number of items:
<<.operator-example 1 "[tag[shopping]reduce<num-items>]">>
Total price:
<<.operator-example 2 "[tag[shopping]reduce<add-price>]">>

Wyświetl plik

@ -0,0 +1,33 @@
caption: filter
created: 20200929174420821
modified: 20201006173606828
op-input: a [[selection of titles|Title Selection]] passed as input to the filter
op-neg-input: a [[selection of titles|Title Selection]] passed as input to the filter
op-neg-output: those input titles that <<.em "do not">> pass the filter <<.place S>>
op-output: the [[selection of titles|Title Selection]] that pass the filter <<.place S>>
op-parameter: a [[filter expression|Filter Expression]]
op-parameter-name: S
op-purpose: apply a subfilter to each input title and return the titles that return a non-empty result from the subfilter
tags: [[Filter Operators]] [[Negatable Operators]]
title: filter Operator
type: text/vnd.tiddlywiki
<<.from-version "5.1.23">> The <<.op filter>> operator runs a subfilter for each input title, and returns those input titles for which the subfilter returns a non-empty result (in other words the result is not an empty list). The results of the subfilter are thrown away.
Simple filter operations can be concatenated together directly (eg `[tag[HelloThere]search[po]]`) but this doesn't work when the filtering operations require intermediate results to be computed. The <<.op filter>> operator can be used to filter on an intermediate result which is discarded. To take the same example but to also filter by those tiddlers whose text field is longer than 1000 characters:
```
<$vars myfilter="[get[text]length[]compare:integer:gteq[1000]]">
<$list filter="[tag[HelloThere]search[po]filter<myfilter>]">
<div>
<$link>
<$text text=<<currentTiddler>>/>
</$link>
</div>
</$list>
</$vars>
```
<<.tip "Compare with the similar [[subfilter|subfilter Operator]] operator which runs a subfilter and directly returns the results">>
<<.operator-examples "filter">>

Wyświetl plik

@ -0,0 +1,27 @@
caption: reduce
created: 20201004154131193
modified: 20201006174749170
op-input: a [[selection of titles|Title Selection]] passed as input to the filter
op-output: the final result of running the subfilter <<.place S>>
op-parameter: a [[filter expression|Filter Expression]]
op-parameter-name: S
op-purpose: apply a subfilter to each input title in turn, accumulating a single value
op-suffix: Initial value for accumulator
op-suffix-name: V
tags: [[Filter Operators]]
title: reduce Operator
type: text/vnd.tiddlywiki
<<.from-version "5.1.23">> The <<.op reduce>> operator runs a subfilter for each input title, passing the result of the previous subfilter run as a variable. The initial value of the accumulator can optionally be specified. It returns the result of the final subfilter run.
The <<.op reduce>> operator is used to flatten a list of items down to a single item by repeatedly applying a formula. A typical use is to add up the values in a given field of a list of tiddlers.
The following variables are available within the subfilter:
* ''accumulator'' - the result of the previous subfilter run
* ''currentTiddler'' - the input title
* ''index'' - the numeric index of the current list item (with zero being the first item in the list)
* ''revIndex'' - the reverse numeric index of the current list item (with zero being the last item in the list)
* ''length'' - the total length of the input list
<<.operator-examples "reduce">>

Wyświetl plik

@ -22,4 +22,6 @@ type: text/vnd.tiddlywiki
...
```
<<.tip "Compare with the similar [[filter|filter Operator]] operator which runs a subfilter against each title, returning those titles that return a non-empty list (and discards the results of the subfilter)">>
<<.operator-examples "subfilter">>