Is it possible to get a list of unique values of a single field?

281 views
Skip to first unread message

Alan Finger

unread,
Jan 23, 2015, 10:28:59 PM1/23/15
to tiddl...@googlegroups.com
Hi All,

I'd like to get a list of unique values of a field in a group of tiddlers so I can build a group of radio buttons to select one. Is there a way to do that?

Thanks,
Alan

RichShumaker

unread,
Jan 23, 2015, 10:58:37 PM1/23/15
to tiddl...@googlegroups.com
First let me say this is what I am working on so others will need to help out.
I don't know completely how to do it but I can give you some ideas.

There are two parts from what I can tell,
1. Filters to get you what you want, I have been using the Advanced Search to make sure my filter works right.
2. List with that filter inside

Here is Tobias's Page that helped me earlier today on Filters.
From there I wrapped it in {{{ Triple Brackets }}}

So this will give you a list of Tags
{{{ [tag[List]] }}}
you can also add a sort to that
{{{ [tag[hangouts]!sort[title]] }}} - Reverse Order Title Sort
{{{ [tag[hangouts]sort[title]] }}} - No ! means Normal Order

Here is where I get stuck as I am not sure how to list all the items in a specific field across all the Tiddlers.
I apologize if you knew all this already and I hope it helps at least a little.
I have a feeling that there is another better way to do this so I look forward to what others let you know as it will help me.

Rich Shumaker

Astrid Elocson

unread,
Jan 24, 2015, 4:02:05 AM1/24/15
to tiddl...@googlegroups.com
Hi Alan,

It's interesting you mention this, because I was on the verge of posting something to the Dev group about this yesterday.

The get operator will output a list of the values in a specified field in its input tiddlers: [tag[Example]get[my-field]]. But the output can contain duplicates.

This is odd, because every other filter operator takes care to avoid outputting duplicates. I wonder if get is intended to be different. Or is this an oversight that ought to be fixed?

– æ

Danielo Rodríguez

unread,
Jan 24, 2015, 6:10:20 AM1/24/15
to tiddl...@googlegroups.com
Hello,

I have this exact setup for a dropdown of categories for my bookmarks.
It is fairly simple with the use of the each operand:

<$list filter="[tag[bookmark]each[topic]]">

Regards.

Tobias Beer

unread,
Jan 24, 2015, 6:12:06 AM1/24/15
to tiddl...@googlegroups.com
Use the each filter...

<$list filter="[each[type]get[type]]" variable="type">
<$radio field="type" value=<
<type>>><<type>></$radio><br>
</$list>

Best wishes, Tobias.

Tobias Beer

unread,
Jan 24, 2015, 6:18:05 AM1/24/15
to tiddl...@googlegroups.com
Example...


Best wishes, Tobias.

Astrid Elocson

unread,
Jan 24, 2015, 7:14:15 AM1/24/15
to tiddl...@googlegroups.com
Interesting.

Why is get special, such that [get[type]] doesn't mean [each[type]get[type]?

– æ

Jed Carty

unread,
Jan 24, 2015, 7:33:30 AM1/24/15
to tiddl...@googlegroups.com
Astrid,

I don't think that the get operator the same as the normal filtering operators because it operates on each tiddler in the returned list instead of the list itself. So it lists all the tiddlers that match the filter without the get operator, and then outputs the value of the  field for each tiddler, so the get operator would be shorthand for

<$list filter='[tag[someTag]]'>
<$transclude tiddler=<<currentTiddler>> field=someField/>
</$list>

which, when using the get operator, could be written as

<$list filter='[tag[someTag]get[someField]]'>

</$list>

I am not  sure if that is actually how the code works, but that is consistent with the output I have gotten when testing filters. The default filter if you just use < $list/> appears to be [!is[system]] so [get[fieldName]] is consistent with this behavior. I don't know if there are any other operators that work similarly.
I don't know if there is any time when this behavior would be useful, maybe listing given names of people where not everyone has a unique given name?

Tobias Beer

unread,
Jan 24, 2015, 10:41:37 AM1/24/15
to tiddl...@googlegroups.com
Why is get special, such that [get[type]] doesn't mean [each[type]get[type]?

I think it boils down to a matter of implementation. Possibly get came after each and was designed for the purpose of fetching a single tiddler's field, e.g. to set a variable. I guess it was not intended to operate on a list of tiddlers. But the behaviour you sugest sounds like a meaningful expectation because those duplicates really are undesired. Otherwise, we'd need another unique filter operand to get rid of the duplicates.

So, theoretically, I think it could operate like each, but then I think it should rather be [has[type]each[type]get[type]... not returning blanks. But perhaps there is a case where you do want specifically declared blanks, rather than undefined.

I was about to extend each, so it does handle list fields, e.g. [each:list[]] or [each:list[my-list-field]. But now I am thinking that this isn't consistent with the way each actually works right now.

Perhaps it should rather be: [tag[foo]get:list[]] or [tag[foo]get:list[my-list-field]] with the behaviour you describe, thus returning individual tiddler references of list fields, not those distinct combinations or values thereof that would be returned now.

Best wishes, Tobias.

cmari

unread,
Jan 24, 2015, 11:39:02 AM1/24/15
to tiddl...@googlegroups.com
One pedantic footnote about the "each" approach, from experience: obviously if only one tiddler in your file contains a particular field value, e.g., [myfieldname[fieldvalue1]], if you use your radio button to change that tiddler's field value to [myfieldname[fieldvalue2]], then fieldvalue1 will no longer appear as an option in the radio button list.  For my use case, I found I still needed to create "placeholder" tiddlers containing the fieldvalues that I wanted to be always available for selection.
cmari

Astrid Elocson

unread,
Jan 24, 2015, 11:47:59 AM1/24/15
to tiddl...@googlegroups.com
> I guess it was not intended to operate on a list of tiddlers.

It's implemented like any other filter operator, taking an input list and producing an output list.

> I think it should rather be [has[type]each[type]get[type]... not returning blanks.

But get never returns blanks, although each does return tiddlers in which the field in question is blank. So on tiddlywiki.com at present, [each[color]] returns six titles, whereas [get[color]] and [each[get[color]] return five.

>
But perhaps there is a case where you do want specifically declared blanks, rather than undefined.

In exploring the title operator today, I've discovered that it supports negation (previously undocumented). title[x] is absolute, ignoring its input. But !title[x] is relative, and serves to filter out x from the input. Oddly, though, it doesn't filter out x if x doesn't exist as a tiddler. So we can't use !title[] to filter out blanks from other lists.

>
I was about to extend each, so it does handle list fields

So that, given one tiddler with list A B C and another with list A C E G, it would return A B C E G? That sounds like a relative form of the list operator: [tag[foo]list:relative[]]. Or an absolute form of it that somehow took a list of text references as its parameter.

>
Perhaps it should rather be: [tag[foo]get:list[]] or [tag[foo]get:list[my-list-field]] with the behaviour you describe

That would also be logical. In fact, the concept of unpacking a list into an array is so useful that
maybe it deserves its own unsuffixed operator.

– æ

Astrid Elocson

unread,
Jan 24, 2015, 11:56:53 AM1/24/15
to tiddl...@googlegroups.com
> In fact, the concept of unpacking a list into an array is so useful that maybe it deserves its own unsuffixed operator.

And come to think of it, that operator already exists: it's list[tiddler!!field]. What's needed is the reverse of that, so that the parameter (tiddler!!field) can be specified as the input instead.

– æ

Tobias Beer

unread,
Jan 24, 2015, 11:57:41 AM1/24/15
to tiddl...@googlegroups.com
obviously if only one tiddler in your file contains a particular field value, e.g., [myfieldname[fieldvalue1]], if you use your radio button to change that tiddler's field value to [myfieldname[fieldvalue2]], then fieldvalue1 will no longer appear as an option in the radio button list.

Yes, that is true... at which point your ui should also provide a way to add a yet undefined new "type".
 
For my use case, I found I still needed to create "placeholder" tiddlers containing the fieldvalues that I wanted to be always available for selection.

I would think for most usecases it is the best approach to define the options in a precise spot, rather than take them from existing values. However, selecting anything via radio-buttons does not necessarily mean to change any of the tiddlers from which the options were constructed.

It only means to make a selection, perhaps for some dependent ui that generates desired output. So, the radio button would actually set some state or temporary tiddler.

Best wishes, Tobias.

Astrid Elocson

unread,
Jan 24, 2015, 12:02:25 PM1/24/15
to tiddl...@googlegroups.com
One othe related oddity of the list operator is that it behaves very differently when negated:

* [list[t!!f]] is absolute, and outputs the titles listed in field f of tiddler t
* [tag[foo]!list[t!!f]] is relative, and outputs any foo-tagged titles that are not listed in field f of tiddler t

– æ

Tobias Beer

unread,
Jan 25, 2015, 9:36:20 AM1/25/15
to tiddl...@googlegroups.com
* [tag[foo]!list[t!!f]] is relative, and outputs any foo-tagged titles that are not listed in field f of tiddler t

Are you sure about that? I think there is quite a difference between list and listed.

Best wishes, Tobias.

Astrid Elocson

unread,
Jan 25, 2015, 11:16:20 AM1/25/15
to tiddl...@googlegroups.com
> Are you sure about that?

Positive. If you don't believe me, look at the code in filters/list.js.

It starts by retrieving an array of titles from the list field. list without an exclamation mark simply returns that array. But negated list iterates over its input titles, i.e. tag[foo] in my example, and it outputs only those input titles that are not in the array.

– æ

Tobias Beer

unread,
Jan 25, 2015, 12:59:01 PM1/25/15
to tiddl...@googlegroups.com
[list[t!!f]] is absolute, and outputs the titles listed in field f of tiddler t

[tag[foo]!list[t!!f]] is relative, and outputs any foo-tagged titles that are not listed in field f of tiddler t

Ok, I get it now.
The confusion seems to be from comparing apples and pears.
If you do want to compare something, you have to compare:
 
[tag[foo][list[t!!f]] is relative, and outputs any foo-tagged titles that are listed in field f of tiddler t
[tag[foo]!list[t!!f]] is relative, and outputs any foo-tagged titles that are not listed in field f of tiddler t

Best wishes, Tobias.

Tobias Beer

unread,
Jan 25, 2015, 2:30:18 PM1/25/15
to tiddl...@googlegroups.com
 [tag[foo][list[t!!f]] is relative, and outputs any foo-tagged titles that are listed in field f of tiddler t

Ok, I get it now. This is not happening, although it probably should, otherwise you cannot talk of negation.

Made a pull request...


@Astrid / @Jeremy, this is probably the #1 reason why there should never two source function iterators in a filter, one for positive and one for negation!

Best wishes, Tobias.

Tobias Beer

unread,
Jan 25, 2015, 2:42:41 PM1/25/15
to tiddl...@googlegroups.com
In fact, I just opened another issue to handle this consistently throughout all filters...

handle filter negation via filters.js

No filters should implement their own negation handlers. Instead, a helper function in$:/core/modules/filters.js should evaluate a boolean expression and depending on the negation prefix !add to the result-set or not. Every filter should thus be automatically negation-enabled.
 
Best wishes, Tobias.

c pa

unread,
Oct 5, 2015, 7:56:01 PM10/5/15
to tiddl...@googlegroups.com
Is there a way to return a list of the unique values in a list field?

You can paste this post into a tiddler on tiddlywiki.com to see what I mean.

''[[get Operator (Examples)]] demonstrates that `[each[tags]get[tags]]` will list the value in every tiddler's tags field ''<br/>

''If I make a slight change, `[get[tags]each[tags]]`, I get a unique listing of all the tags in a TiddlyWiki:''

<$list filter="[get[tags]each[tags]]" variable="type">

     <$radio field="type" value=<<type>>><<type>></$radio><br>
</$list>

''Neither `[each[list]get[list]]` nor `[get[list]each[list]]` returns a unique listing of all the list entries in a TiddlyWiki:''

`[each[list]get[list]]`

<$list filter="[each[list]get[list]]" variable="type">

     <$radio field="type" value=<<type>>><<type>></$radio><br>
</$list>

`[get[list]each[list]]`

<$list filter="[each[list]get[list]]" variable="type">

c pa

unread,
Oct 5, 2015, 8:44:54 PM10/5/15
to TiddlyWiki
OK (trying to answer my own question) this should work but for some reason it displays the contents of the macro instead of executing the macro. Could someone help me with my syntax?

Copy the below into a tiddler to see what I mean

\define returnList(tiddlerName, fieldName)<$list filter="[list[$tiddlerName$!!$fieldName$]]">&#91;&#91;<$view field="title"/>&#93;&#93; </$list>

\define returnAllLists(fieldName)<$list filter="[has[$fieldName$]]"><$macrocall $name="returnList" tiddlerName=<<currentTiddler>> fieldName="$fieldName$" /></$list>

\define listAllFieldItems(fieldName, itemsList)
    <ul>
    <$list filter="$itemsList$">
        <li>
            <<currentTiddler>>
        </li>
    </$list>
    </ul>
\end

<$macrocall $name="listAllFieldItems"
        fieldName="list"
        itemsList=<<returnAllLists "list">>
/>

Reply all
Reply to author
Forward
0 new messages