How to imporve D-translation of these Python list comprehensions ?

xenon325 anm at programmer.net
Mon Jan 15 19:05:52 UTC 2018


A workmate has recently shown this piece of code to show how nice 
Python is (we are mostly C and growing C++ shop):

     import json
     from itertools import chain

     srv1 = {'acs': {'ver': '1.2.3', 'rev': '6f2260d'}, 'cms': 
{'ver': '4.5', 'rev': 'b17a67e'}, 'ots': {'ver': '6.7.80', 'rev': 
'4f487d2'}}
     srv2 = {'acs': {'ver': '1.2.3', 'rev': '6f2260d'}, 'cms': 
{'ver': '5.1', 'rev': '2a56c53'}, 'vaa': {'ver':    '0.7', 'rev': 
'00852cb'}}


     def aget(d, k1, k2):
         return d.get(k1, {}).get(k2, '')

     aa = ['ver', 'rev']
     kk = set(chain(srv1.keys(), srv2.keys()))
     dd = [dict(_name=k, **{a + str(i): aget(d, k, a) for a in aa 
for i, d in enumerate([srv1, srv2])}) for k in sorted(kk)]

     print(json.dumps(dd, indent=2, sort_keys=True))


Output is:

     [
       {
         "_name": "acs",
         "rev0": "6f2260d",
         "rev1": "6f2260d",
         "ver0": "1.2.3",
         "ver1": "1.2.3"
       },
       {
         "_name": "cms",
         "rev0": "b17a67e",
         "rev1": "2a56c53",
         "ver0": "4.5",
         "ver1": "5.1"
       },
       {
         "_name": "ots",
         "rev0": "4f487d2",
         "rev1": "",
         "ver0": "6.7.80",
         "ver1": ""
       },
       {
         "_name": "vaa",
         "rev0": "",
         "rev1": "00852cb",
         "ver0": "",
         "ver1": "0.7"
     ]
       }

Another coworker replied with Scala equivalent. So I thought, why 
wouldn't I join the party and translate that to D :)

My best take so far is (with some D-intro comments 
https://run.dlang.io/is/GxsauU):

     import std.stdio;
     import std.algorithm;
     import std.range;
     import std.array;
     import std.conv;
     import std.json;

     void main()
     {
         // not `immutable` to describe one less thing
         const srv1 = [
             "acs": ["ver": "1.2.3", "rev": "6f2260d"],
             "cms": ["ver": "4.5", "rev": "b17a67e"],
             "ots": ["ver": "6.7.80", "rev": "4f487d2"]];
         const srv2 = [
             "acs": ["ver": "1.2.3", "rev": "6f2260d"],
             "cms": ["ver": "5.1", "rev": "2a56c53"],
             "vaa": ["ver":    "0.7", "rev": "00852cb"]];

         string[string][] result;
         chain(srv1.keys, srv2.keys)
             .sort 					
             .uniq 					
             .each!( (uniqComp) {	
                 auto verInfo = ["_name": uniqComp];
                 [srv1, srv2]
                     .enumerate
                     .each!( serv =>
                             ["ver", "rev"].each!( prop =>
                                   verInfo[prop ~ 
serv.index.to!string]
                                   = serv.value.get(uniqComp, ["": 
""]).get(prop, ""))
                     );
                 /+ // The same as above and I like this better, 
actually
                 foreach(servIdx, serv; [srv1, srv2].enumerate){
                     foreach(prop; ["ver", "rev"])
                         verInfo[prop ~ servIdx.to!string]
                         = serv.get(uniqComp, ["": ""]).get(prop, 
"");
                 } +/

                 result ~= verInfo;
             });
         writeln("---");
         writeln(JSONValue(result).toPrettyString());
         writeln("---");
     }

I think, most clear code would be with tripple `foreach`, so I'll 
go with that. But probably someone will come up with something 
better and range-ier.

Suggestion are welcome!

---
Alexander


More information about the Digitalmars-d-learn mailing list