Referencing this example from Practical Gremlin and this stack overflow post:
Gremlin Post Filter Path
g.withSack(0).V().
has('code','AUS').
repeat(out().simplePath().has('country',within('US','UK')).
choose(has('code','MAN'),sack(sum).by(constant(1)))).
until(has('code','EDI')).
where(sack().is(1)).
path().by('code').
limit(10)
Is it possible to perform a sack sum in such a way as to only sum the first time a property is found. For instance, instead of the 'code' property inside of the choose() which will only sum once per 'code' encountered thanks to the simplePath(), what if there was another property called 'airport_color'. As we perform the traversal, I would only want the sack sum to increment the first time it encountered 'blue' or 'white' as an example, even though multiple airports could have the same color as we go through the traversal. This would help me in the where() clause because, if I had a couple of colors I was interested in looking for as an example (maybe blue and white), I could set the where() clause to be equal to two and know that two wasn't arrived at just because I passed through blue twice but because blue and white was encountred.
I tried using aggregation to make the sack sum increment only on the first encounter but couldn't get it to work, something like this:
g.withSack(0).V().
has('code','AUS').
repeat(out().simplePath().has('country',within('US','UK')).
choose(has('airport_color','blue').has('airport_color', without('airport_color_agg')),sack(sum).by(constant(1))).
aggregate('airport_color_agg').by('airport_color')).
until(has('code','EDI')).
where(sack().is(1)).
path().by('code').
limit(10)
There could be multiple colors in the choose() via or() but I limited it to just one to keep the example more straightforward.
Thanks for your help!
Using the sample graph below:
g.addV('A').property(id,'a1').property('color','red').as('a1').
addV('A').property(id,'a2').property('color','blue').as('a2').
addV('A').property(id,'a3').property('color','red').as('a3').
addV('A').property(id,'a4').property('color','yellow').as('a4').
addV('A').property(id,'a5').property('color','green').as('a5').
addV('A').property(id,'a6').property('color','blue').as('a6').
addE('R').from('a1').to('a2').
addE('R').from('a2').to('a3').
addE('R').from('a3').to('a4').
addE('R').from('a4').to('a5').
addE('R').from('a5').to('a6')
we can inspect the path through the graph as follows:
g.V('a1').
repeat(out()).
until(not(out())).
path().
by('color')
which shows us the colors found
path[red, blue, red, yellow, green, blue]
the next thing we need to do is to remove the duplicates and filter out the colors not in our want list.
g.withSideEffect('want',['red','green']).
V('a1').
repeat(out()).
until(not(out())).
path().
by('color').
dedup(local).
unfold().
where(within('want'))
which gives us:
red
green
finally, we just need to count them:
g.withSideEffect('want',['red','green']).
V('a1').
repeat(out()).
until(not(out())).
path().
by('color').
dedup(local).
unfold().
where(within('want')).
count()
Which, as expected, gives us:
2
UPDATED 2022-09-01 To reflect discussion in comments.
To change the query so that only paths that visit each of the required colors at least once are returned, the previous steps leading up to the count need to be turned into a filter.
g.withSideEffect('want',['red','green']).
V('a1').
repeat(out()).
until(not(out())).
filter(
path().
by('color').
dedup(local).
unfold().
where(within('want')).
count().is(2)).
path()
which for our sample graph returns:
1 path[v[a1], v[a2], v[a3], v[a4], v[a5], v[a6]]
The query as written gets the job done and hopefully is not too hard to follow. There are some things we could change/improve.
Pass in the count for the is step as another parameter like the want list.
Rather than pass in a parameter, use the size of the want list instead. This makes the query a little more complex.
Use a sack as the query proceeds to collect the colors seen. The query gets more complex in that case as, while you can maintain a list in a sack, updating it requires a few extra steps.
Here is the query rewritten to use a sack. This assumes the start node has a color that should be included. If that is not the case, the first sack(assign) can be removed and a withSack([]) added after the withSideEffect.
g.withSideEffect('want',['red','green']).
V('a1').
sack(assign).by(values('color').fold()).
repeat(out().sack(assign).by(union(sack().unfold(),values('color')).fold())).
until(not(out())).
filter(
sack().
unfold().
dedup().
where(within('want')).
count().is(2)).
path()
I know gdb has several means of exploring data, some of them quite convenient. However, I cannot combine them to get that I need/want. I would like to display some custom string based on the first n values of a big array starting at <PT_arr>, and the last m values of the same array at a distance (in this case) 4096. Looking something like this:
table beginning:
0x804cfe0 <PT_arr>: 0x00100300 0x00200300 0x00300300 0x00400300
table end:
0x804cfe0 <PT_arr+4064>: 0x00500300 0x00600300 0x00700300 0x00800300
printf let's me add custom text (like table beginning)
the examine x gives me that nice alignment, let's me read many elements and group them by byte, words, etc; and shows addresses at the left (which is ideal for my case).
x aligns the content of regions of memory in an easy to read manner with the size and unit parameters. (what I want)
display is constantly printing. (what I want).
The issue with display (manual), is that unlike examine x (manual) it doesn't have a size or unit parameter.
Is there a way to accomplish that?
Thanks.
Having a bit of an issue and unsure if it's actually possible to do.
I'm working on a file that I will enter target progression vs actual target reporting the % outcome.
PAGE 1
¦NAME ¦TAR 1 %¦TAR 2 %¦TAR 3 %¦TAR 4 %¦OVERALL¦SUB 1¦SUB 2¦SUB 3¦
¦NAME1¦ 114%¦ 121%¦ 100%¦ 250%¦ 146%¦ 2¦ 0¦ 0%¦
¦NAME2¦ 88%¦ 100%¦ 90%¦ 50%¦ 82%¦ 0¦ 1¦ 0%¦
¦NAME3¦ 82%¦ 54%¦ 64%¦ 100%¦ 75%¦ 6¦ 6¦ 15%¦
¦NAME4¦ 103%¦ 64%¦ 56%¦ 43%¦ 67%¦ 4¦ 4¦ 24%¦
¦NAME5¦ 87%¦ 63%¦ 89%¦ 0%¦ 60%¦ 3¦ 2¦ 16%¦
Now I already have it sorting all rows by the Overall % column so I can quickly see at a glance but I am creating a second page that I need to reference points.
So on the second page I would like to somehow sort and reference different columns for example
PAGE 2
TOP TAR 1¦Name of top %¦Top %¦
TOP TAR 2¦Name of top %¦Top %¦
Is something like this possible to do?
Essentially I'm creating an Employee of the Month form that automatically works out who has topped what.
I'm willing to drop a paypal donation for whoever can figure this out for me as I've been doing it manually every month and would appreciate the time saved
I don't think a complicated array formula is necessary for this - I am suggesting a fairly standard Index/Match approach.
First set up the row titles - you can just copy and transpose them from Page 1, or use a formula in A2 of Page 2 like
=transpose('Page 1'!B1:E1)
The use them in an index/match to get the data in the corresponding column of the main sheet and find its maximum (in C2)
=max(index('Page 1'!A:E,0,match(A2,'Page 1'!A$1:E$1,0)))
Finally look up the maximum in the main sheet to find the corresponding name:
=index('Page 1'!A:A,match(C2,index('Page 1'!A:E,0,match(A2,'Page 1'!A$1:E$1,0)),0))
If you think there could be a tie for first place with two or more people getting the same score, you could use a filter to get the different names:
So if the max score is in B8 this time (same formula)
=max(index('Page 1'!A:E,0,match(A8,'Page 1'!A$1:E$1,0)))
the different names could be spread across the corresponding row using transpose (in C8)
=ArrayFormula(TRANSPOSE(filter('Page 1'!A:A,index('Page 1'!A:E,0,match(A8,'Page 1'!A$1:E$1,0))=B8)))
I have changed the test data slightly to show these different scenarios
Results
I'd like to use a custom directive to wrap certain table cells in a preformatted block.
For example, suppose I want to write documentation for my exciting new calculator:
.. Calculator-Operations:: sign examples
You'll love how great this awesome calculator is.
Check out these exciting innovations!
========= ==========
you type result
========= ==========
+ 1 1
- 1 -1
* 1 ERROR!
/ 1 ERROR!
I can retrieve each table cell node in my directive's implementation, but the node has already been processed by Sphinx (of course), so the first three cells are treated as bulleted lists.
I'd like the generated document to behave as if I had surrounded each "you type" cell with double backticks. I could accomplish this if I could retrieve the raw text of the node or if I could prevent Sphinx from transforming this particular node. (I could also accomplish this by parsing the entire block's content myself, but that sounds unpleasant.)
What is the best way of transforming the original, untransformed user input in these cells?
While investigating a ConflictError (see this previous question) I saw a lot of persistent.mapping.PersistentMapping conflicts.
Looking at a specific one it turned out to be a PersistentMapping for plone.scale.
Turns out that a random object with just one image has 562 keys on it, no wonder why it gets a conflict error...
Some context on the object that holds this plone.scale annotation:
- dexterity content type
- one of its behaviors has an image field (plone.namedfile.field.NamedBlobImage)
The code to see it is as following:
Start a debugging instance: ./bin/instance debug
from ZODB.utils import p64
OID = 0x568428 # got from zeo client logs
mapping = app._p_jar[p64(OID)]
len(mapping) # that returns 562
The mysterious part is that only 4 keys on that persistent mapping are tuples, while the other 558 are just hashes.
A brief look at plone.scale.storage.AnnotationStorage.scale method seems to imply that there should be only one to one relation from tuples and hashes keys on the persistent mapping.
Further investigating the elements reveals that, indeed, if you look at the width and height properties from all elements there are only 4 different combinations (the ones from the tuples itself).
As a new scale is generated whenever the modified time is bigger (see the scale method pointed above) and plone.namedfield.scaling.ImageScaling.modified uses context as the source for modified, that means that at every single update of the object a new scale will be generated?
So two questions arise from the previous:
my assumption of only 4 scales are really used and the other 558 are old and useless is true?
provided a yes on the previous, shouldn't they be cleaned up then?
You may be right, but surely the correct place to report this is https://dev.plone.org/newticket