Indirection on components?

Close. I would recommend that you keep the two functions in a Script Library.

Really you should define another function in a script library that holds all of the actual code in a script library., but you don't have to.

If you choose to just define them in this script then, all of the imports should be on the first line, I just did it in each function for clarity (and so the functions by themselves can be used without modification).

So it should look like this:

def runAction(self, event):
	from itertools import repeat,izip_longest as zipl
	from itertools.chain import from_iterable as chainIt
	def chunks(it,size):
		return zipl(*[iter(it)] * size)
	def rangeGroup(it,start,n):
		for i,j in zip(chainIt(repeat(k,len(it)) for k in xrange(start,n)),chainIt(repeat(it,n))):
			yield (i,j)

    quad = ['A','B','C','D']
    path = '[default]Twisters/TW{}/Operator Assignments/Quad_{} {}'
    tags = ['J Shift Operator Name','J Shift Operator BadgeNum']
    paths = [path.format(i,n,tag) for i,n in rangeGroup(quad,0,66) for tag in tags]
    tagValues = [qv.value for qv in system.tag.readBlocking(paths)]
    #I incremented the end value here rather than in the loop.
    tw_ranges = [(1,13),(13,25),(25,41),(41,57),(57,66)]
    for cc_index,(tw_start,tw_end) in enumerate(tw_ranges):
        for tw_num,quad in rangeGroup(quad,tw_start,tw_end):
           cont = 'CoordinateContainer_{}'.format(cc_index)
           tw = 'TW{}'.format(tw_num)
           nameQuad = 'Quad_{}_OpName'.format(quad)
           numQuad = 'Quad_{}_OpNum'.format(quad)
           for opName,opNum in chunks(tagValues,2):
               self.parent.getChild(cont).getChild(tw).props.params[nameQuad] = opName
               self.parent.getChile(cont).getChild(tw).props.params[numQuad] = opNum

Honestly though, it should really look like this:

def runAction(self,event):
  1. Put chunks and rangeGroup in a project library script, with the import at the top of the file.
  2. call them from your runAction script.
  3. the indentation in your script is way off.

In my project those functions are part of my script utils library, and the imports are all at the top of the file.

But with the imports that way, as smelly as it is, the functions will work as is no matter where they're pasted.

I'm guessing quad should be it ?

I don't think you need yield here. Returning a zip object should be just as good I believe.
I think zip produced a list in Cpython 2, but I don't think it's the case with Jython.
And if it does produce a list, it's going to produce it anyway in your function, whether you yield its results or not.

I think product is better for this use case:

def group_range(start, n, it):
    return product(range(start, n), it)

much simpler, and returns an iterator. Frankly it even makes having a function for it almost useless.

itertools has an izip that returns an iterator. I'm not sure exactly what is the class 'zip' that zip returns in jython...

1 Like

Yes you're correct, I missed those.

Honestly, didn't know about product until you used.

I have to say, I'm surprised at how fun this problem is from a code optimization standpoint. Below is my take. Definitely learned some new things!

from itertools import product

def get_iterator(op_strings):
	quads = ['A','B','C','D']
	return product(range(1,66), quads, op_strings)

path = '[default]Twisters/TW{}/Operator Assignments/Quad_{} J Shift Operator {}'
paths = [path.format(*p) for p in get_iterator(['Name','BadgeNum'])]
tag_qvals = system.tag.readBlocking(paths)

cc_idx, tw_breaks = 0, [12,24,40,56,65]
for i,p in enumerate(get_iterator(['Name','Num'])):
	cc_idx += int(p[0] > tw_breaks[cc_idx])
	cc_str = 'CoordinateContainer_{}'.format(cc_idx)
	tw_str = 'TW{}'.format(p[0])
	pm_str = 'Quad_{}_Op{}'.format(p[1],p[2])
	self.parent.getChild(cc_str).getChild(tw_str).props.params[pm_str] = tag_qvals[i].value
1 Like

I was actually thinking about opening a thread to propose little challenges like this. I'm still figuring out how that would work, but it could be a fun way of learning new things.


Here's a neat little thing (though in this particular case I'd just use a direct call to product):

from functools import partial

prod = partial(product, "ABCD", xrange(1, 66))

When you want to wrap a function to give it predefined arguments, partial is a handy thing.

I wouldike to thank everyone who has helped me with this! You guys have been really great!

One last question for the group:

Is there a length limit to how many lines the jython code can be?

For future reference.

Not a length limit, but a compiled (to jython bytecode) size limit. 64k, IIRC.

Thanks again, I wish I could buy everyone here a round for the help!