<div dir="ltr"><div class="gmail_extra"><div class="gmail_quote">On Fri, Jul 13, 2018 at 12:38 PM, Michael Selik <span dir="ltr"><<a href="mailto:mike@selik.org" target="_blank">mike@selik.org</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="ltr"><div>Thanks for linking to these.</div></div></blockquote><div><br></div><div>yup -- real use cases are really helpful.</div><div><br></div><div>Though the other paradigm for grouping is use of setdefault() rather than defaultdict. So it would be nice to look for those, too.</div><div> <br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="ltr"><div> I looked at many of them in my own research, but for some reason didn't think to write down the links. I'll respond to each one separately.</div></div></blockquote><div> <br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="ltr"><div>Throughout, I'm going to use my proposed ``grouped`` builtin to demonstrate possible revisions. Note that I am *not* suggesting a replacement to defaultdict. The proposal is to make a common task easier and more reliable. It does not satisfy all uses of defaultdict.</div></div></blockquote><div><br></div><div>agreed -- and it shouldn't.</div><div><br></div><div>I"d like to see how some of these pan our with my proposed API:</div><div><br></div><div>either a Grouped class, or at least (key, value) iterables and/or a value function.</div><div><br></div><div>I don't have time now to do them all, but for the moment:</div><div><br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="ltr"><div class="gmail_quote"><span class=""><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="ltr"><div><div><div><div><div>I noticed recently that *all* examples for collection.defaultdict (<a href="https://docs.python.org/3.7/library/collections.html#collections.defaultdict" target="_blank">https://docs.python.org/3.7/<wbr>library/collections.html#<wbr>collections.defaultdict</a>) are cases of grouping (for an int, a list and a set) from an iterator with a key, value output. </div></div></div></div></div></div></blockquote></span></div></div></blockquote><div><br></div><div>and yet others on this thread think a (key, value) input would be rare -- I guess it depends on whether you are thinking dict-like already....</div><div> <br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="ltr"><div class="gmail_quote"><span class=""><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="ltr"><div><div><div><div><div><br></div></div></div></div></div></div></blockquote></span><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="ltr"><div><div><div><div><a href="https://frama.link/o3Hb3-4U" target="_blank">https://frama.link/o3Hb3-4U</a>,</div></div></div></div></div></blockquote><div><br></div><div><div>    accum = defaultdict(list)</div><div>    garbageitems = []</div><div><br></div><div>    for item in root:</div><div>        filename = findfile(opts.fileroot, item.attrib['classname'])</div><div>        accum[filename].append(float(<wbr>item.attrib['time']))</div><div>        if filename is None:</div><div>            garbageitems.append(item)</div><div><br></div><div><br></div><div>This might be more clear if separated into two parts.</div><div><br></div><div><div>    def keyfunc(item):</div><div>        return findfile(opts.fileroot, item.attrib['classname'])</div><div>    groups = grouped(root, keyfunc)</div><div>    groups = {k: [float(v.attrib['time']) for v in g] for k, g in groups.items()}</div><div>    garbage = groups.pop(None, [])</div></div></div></div></div></blockquote><div><br></div><div>so this one is a prime case for a value function -- I think post-processing the groups is a pretty common case -- why make people post-process it?</div><div><br></div><div><div style="font-size:small;background-color:rgb(255,255,255);text-decoration-style:initial;text-decoration-color:initial">    def keyfunc(item):</div><div style="font-size:small;background-color:rgb(255,255,255);text-decoration-style:initial;text-decoration-color:initial">        return findfile(opts.fileroot, item.attrib['classname'])</div><div style="font-size:small;background-color:rgb(255,255,255);text-decoration-style:initial;text-decoration-color:initial">   def valuefunc(item):</div><div style="font-size:small;background-color:rgb(255,255,255);text-decoration-style:initial;text-decoration-color:initial">        float(item.attrib['time'])</div><div style="font-size:small;background-color:rgb(255,255,255);text-decoration-style:initial;text-decoration-color:initial">    groups = grouped(root, keyfunc, valuefunc)</div><div style="font-size:small;background-color:rgb(255,255,255);text-decoration-style:initial;text-decoration-color:initial">    garbage = groups.pop(None, [])<br></div><br></div><div>And the post-processing is then mixing comprehension style with key function style (what to call that -- "functional" style?), so why not use a (key, value) iterable:</div><div><br></div><div><font face="monospace, monospace">groups = grouped((<span style="font-size:small;background-color:rgb(255,255,255);text-decoration-style:initial;text-decoration-color:initial;float:none;display:inline">findfile(opts.fileroot, item.attrib['classname'])</span>,</font></div><div><font face="monospace, monospace">                  <span style="font-size:small;background-color:rgb(255,255,255);text-decoration-style:initial;text-decoration-color:initial;float:none;display:inline">item.attrib['time']</span>)</font></div><div><font face="monospace, monospace">                  for item in root))</font></div><div><br></div><div>OK -- that's packing a bit too much into a line, so how about:</div><div><br></div><div><div style="font-size:small;text-decoration-style:initial;text-decoration-color:initial;background-color:rgb(255,255,255)"><font face="monospace, monospace">def keyfunc(item):</font></div><div style="font-size:small;text-decoration-style:initial;text-decoration-color:initial;background-color:rgb(255,255,255)"><font face="monospace, monospace">        return findfile(opts.fileroot, item.attrib['classname'])</font></div><div style="font-size:small;background-color:rgb(255,255,255);text-decoration-style:initial;text-decoration-color:initial"><font face="monospace, monospace"><br></font></div><div style="font-size:small;background-color:rgb(255,255,255);text-decoration-style:initial;text-decoration-color:initial"><font face="monospace, monospace">groups = grouped( (<span style="font-size:small;background-color:rgb(255,255,255);text-decoration-style:initial;text-decoration-color:initial;float:none;display:inline">keyfunc(item)</span>, item.attrib['time']) for item in root)</font></div></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="ltr"><div class="gmail_quote"><div><br></div><div><div>    self.mapping = collections.defaultdict(set)</div><div>    for op in (op for op in graph.get_operations()):</div><div>      if op.name.startswith(common.<wbr>SKIPPED_PREFIXES):</div><div>        continue</div><div>      for op_input in op.inputs:</div><div>        self.mapping[op_input].add(op)</div></div><div><br></div><div><br></div><div>This is a case of a single element being added to multiple groups, which is your section B, below. The loop and filter could be better. It looks like someone intended to convert if/continue to a comprehension, but stopped partway through the revision.</div></div></div></blockquote><div><br></div><div>yeah, this is weird -- <br><br></div><div>But it does make a case for having a class with the option f using a set to collect (which I have in an older commit of my prototype:</div><div><div style="font-size:small;background-color:rgb(255,255,255);text-decoration-style:initial;text-decoration-color:initial"><br></div><div style="font-size:small;background-color:rgb(255,255,255);text-decoration-style:initial;text-decoration-color:initial">    inputs = ((op_input, op) for op in ops for op_input in op.inputs)</div><div style="font-size:small;background-color:rgb(255,255,255);text-decoration-style:initial;text-decoration-color:initial">    groups = Grouping(inputs, key=itemgetter(0), collection=set)</div><div style="font-size:small;background-color:rgb(255,255,255);text-decoration-style:initial;text-decoration-color:initial"><br></div><div style="font-size:small;background-color:rgb(255,255,255);text-decoration-style:initial;text-decoration-color:initial">otherwise, you could have a method to do it:</div><div style="font-size:small;background-color:rgb(255,255,255);text-decoration-style:initial;text-decoration-color:initial">    groups.map_on_groups(set)</div><div style="font-size:small;background-color:rgb(255,255,255);text-decoration-style:initial;text-decoration-color:initial"><br></div><div style="font-size:small;background-color:rgb(255,255,255);text-decoration-style:initial;text-decoration-color:initial">(not sure I like that method name, but I hope you get the idea)</div></div><div style="font-size:small;background-color:rgb(255,255,255);text-decoration-style:initial;text-decoration-color:initial"><br></div><div style="font-size:small;background-color:rgb(255,255,255);text-decoration-style:initial;text-decoration-color:initial">OK, back to work.</div><div style="font-size:small;background-color:rgb(255,255,255);text-decoration-style:initial;text-decoration-color:initial"><br></div><div style="font-size:small;background-color:rgb(255,255,255);text-decoration-style:initial;text-decoration-color:initial">-CHB</div><div style="font-size:small;background-color:rgb(255,255,255);text-decoration-style:initial;text-decoration-color:initial"><br></div><div style="font-size:small;background-color:rgb(255,255,255);text-decoration-style:initial;text-decoration-color:initial"><br></div></div>-- <br><div class="gmail_signature" data-smartmail="gmail_signature"><br>Christopher Barker, Ph.D.<br>Oceanographer<br><br>Emergency Response Division<br>NOAA/NOS/OR&R            (206) 526-6959   voice<br>7600 Sand Point Way NE   (206) 526-6329   fax<br>Seattle, WA  98115       (206) 526-6317   main reception<br><br><a href="mailto:Chris.Barker@noaa.gov" target="_blank">Chris.Barker@noaa.gov</a></div>
</div></div>