3

I have two dictionaries created using dict comprehension. I am wondering if (a) there's a way to build it in a single pass, (b) is it advisable? and (c) is there a better approach?

templates_gray = {k:cv2.imread(v, 0) for (k, v) in static_templates.items()}

img_dimension = {k:v.shape for (k, v) in templates_gray.items()}
help-ukraine-now
  • 3,850
  • 4
  • 19
  • 36
doubleE
  • 31
  • 1

3 Answers3

2

A) You most certainly can do it in one line. On your second iteration you're really only getting an attribute for each value in your dictionary.

img_dimension = {k: cv2.imread(v, 0).shape for k, v in static_templates.items()}

B) It is getting a bit harder to read and I don't think I would do exactly that. You can do comprehensions over multiple lines, which might help a bit.

img_dimension = {
    k: cv2.imread(v, 0).shape
    for k, v in static_templates.items()
}

C) I think what I would do is combine the comprehension with a function. This keeps the logic out of the comprehension and I think is easier to read. I don't know if defining a function will break your desire for a single line of code or not.

def get_shape(v):
    x = cv2.imread(v, 0)
    return x.shape

img_dimension = {k: get_shape(v) for k, v in static_templates.items()}

Note: This assumes that templates_gray isn't something you need to use later.

Jacinator
  • 1,413
  • 8
  • 11
  • I second your answer - I myself do complex comprehensions (in B format for readability) when I don't need the sub-results (as per your Note). I use C approach when I do something I want to test or could be useful in another code (library/copy-paste). +Properly done "merging" (A) as opposed to literally doing two comprehensions inside each other (like in @Prune's answer) improve the performance (1 pass through the list vs 2 passes). – h4z3 Aug 16 '19 at 20:01
1

Do the direct substitution of the upper expression for templates_gray:

img_dimension = {k:v.shape for (k, v) in 
                    {k:cv2.imread(v, 0) for (k, v) in
                         static_templates.items()  
                    }.items()
                }

The advisability depends entirely on your usage and maintenance environment. I find this one-line version to be less readable. At the very least, it needs a comment to explain the holistic effect.

Prune
  • 76,765
  • 14
  • 60
  • 81
  • 1
    I agree, this one-liner is much less readable and there really is no performance improvement in this approach. – jpnadas Aug 16 '19 at 19:37
  • Your "one liner" doesn't improve the performance at all. It's still 2 passes through all items, while it could all be done in a single pass. Good merger of two or more comprehensions can improve the performance a lot, depending on the volume of your data. – h4z3 Aug 16 '19 at 20:02
0

For (a), I would say to check the top answer, for (b), I would say, the answers are one-liners but these are basically hard to read for me. So I recommend to expand them out to make more sense. For (c), other than Jacinator's answer which actually defines a function and not just a single line of code, I don't know. I would say there might be not any but that is just my conjecture. And, it depends on your definition of "best".

new Q Open Wid
  • 2,225
  • 2
  • 18
  • 34