10 advance list comprehensions

- `https://www.youtube.com/watch?v=twxE0dEp3qQ` General syntax of list comprehension:
       [ f(x)  for  x  in  list
               if cond1
               if cond2
      	 ...
       ]
  Note: `f(x)` can be a conditional expression :
        val1(x) if cond(x) else val2(x)     # The else clause is mandatory

        This is equivalent to C's:  cond(x) ? val1(x) : val2(x)

Simple list comprehension

- Get a list of values:
      values = []

      for x in range(10):
          values.append(x)
- Solution with list comprehension:
      values = [ x for x in range(10) ]
  Output:
      [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
You can write a for-loop inside of a list.

DEMO: `progs/append01.py` + `append01-c.py`

Generalized list comprehension

- Simplest function with list comprehension:
      values = [ x for x in range(10) ]
- In general, we can use any function of x:
      values = [ f(x) for x in range(10) ]
  Example:
      def square(x):
           return x**2

      values = [ square(x) for x in range(10) ]

DEMO: `progs/append01-c2.py`

Comprehension condition

- Get the list of even values:
      evens = []

      for x in range(10):
          isEven = x % 2 == 0
          if isEven:
              evens.append(x)
- Solution with list comprehension:
      evens = [ x for x in range(10) if (x%2 == 0) ]
  Output:
      0, 2, 4, 6, 8]

DEMO: `progs/append02.py` + `append02-c.py`

Comprehension with multiple conditions

- Filter a list of strings and output only the ones that start with `"a"` and end in `"y"`:
      input = ["any", "albany", "apple", "baby", ""]

      output = []       # Initialize output

      for x in input:
         if len(x) == 0:   # Protect illegal access of x[0] and x[-1]
            continue
         if x[0] != "a":
            continue
         if x[-1] != "y":
            continue
         output.append(x)
- Solution with list comprehension:
      output = [x
                  for x in input  # You can use a list instead of a for-loop
                  if len(x) != 0
                  if x[0] == "a"
                  if x[-1] == "y"
               ]

DEMO: `progs/filter01.py` + `filter01-c.py`

Nested list comprehension

- Flatten a matrix (= list of lists)
      matrix = [ [1, 2, 3], [4, 5, 6], [7, 8, 9] ]

      out = []

      for row in matrix:
          for num in row:
              out.append(num)
- Solution with list comprehension:
      out = [num
                 for row in matrix      # No  ":" !!!
                     for num in row
            ]

DEMO: `progs/nested01.py` + `nested01-c.py`

`IF/ELSE` inside a comprehension

- Categorize a list of numbers as even or odd:
      input = [1, 2, 3, 4, 6]

      out = []

      for x in input:
          if x % 2 == 0:
              out.append("even")
          else:
              out.append("odd")
- Solution with list comprehension:
      out = [ "even" if x % 2 == 0 else "odd"     # else-clause is required
                     for x in input
            ]

DEMO: `progs/if-else01.py` + `if-else01-c.py` + `if-else01-c2.py`

`IF/ELSE` inside a comprehension

- Add 1 to all odd numbers in a list
      input = [1, 2, 3, 4, 6]

      out = []

      for x in input:
          if x % 2 == 0:
              out.append(x)
          else:
              out.append(x+1)    ### Add 1 when x is odd
- Solution with list comprehension:
      out = [ x if x % 2 == 0 else x+1     # else-clause is required
                for x in input
            ]

DEMO: `progs/if-else02-c.py`

Nested list comprehension

- Build a 3-dimensional list with list comprehension:
      out = []

      for a in range(3):
          l1 = []
          for b in range(4):
              l2 = []
              for x in range(2):
                  l2.append(x)       ## [0 1]
              l1.append(l2)          ## [ [0 1]  [0 1]  [0 1] ]
          out.append(l1)
- Solution with list comprehension:
      out = [ [ [
                  x  for x in range(2)
                ]
                for b in range(4)         ### We can use anonimous index var...
              ]
              for a in range(3)
            ]

How to read a nested list comprehension

- Nested list comprehension:
      out = [ [ [
                  x  for x in range(2)
                ]
                for b in range(4)         ### We can use anonimous index var...
              ]
              for a in range(3)
            ]
- The most outer for-loop in the list comprehension is at the right:
      out = [ [ [
                  x  for x in range(2)
                ]
                for b in range(4)
              ]
              for a in range(3)  Outer for-loop
            ]
The left-hand side of the for-loop will get added to the list (and recurse inside)

Dictionary comprehension

- Syntax of a dictionary comprehension:
        {
           key: value    for  key, value  in  list
        }
- Difference:
  - Use `{ .... }` to enclose the for-loop The elements before the for-loop is:
          f(k,v): g(k,v)
  The for-loop will use 2 indexes in a dictionary comprehension

Example of dictionary comprehension

- Making a dictionary from a list of pairs:
       List of pairs:

          pairs = [ ("a", 1),  ("b", 2),  ("c", 3) ]
                    ^^^^^^^    ^^^^^^^    ^^^^^^^
                     pair 1     pair 2     pair 3
- How to create a dictionary using list comprehension:
      pairs = [ ("a", 1),  ("b", 2),  ("c", 3) ]   # List of pairs

      myDict  = { k: v   for  k,v in pairs }

      myDict2 = { k+str(v): v*v   for  k,v in pairs }

DEMO: `progs/list2Dict01.py`

Set comprehension

- Syntax of a set comprehension:
        {
           value    for  value  in  list
        }
- Difference:
  - Use `{ .... }` to enclose the for-loop The elements before the for-loop is:
          f(value)
  The for-loop will use 1 index in a set comprehension

Example of set comprehension

- Making a set (no duplicates) from a list:
       List of numbers:

          nums = [ 1, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4 ]    # List has duplicates
- How to create a set using set comprehension:
      nums = [ 1, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4 ]

      mySet  = { x   for  x in nums }

DEMO: `progs/list2Set01.py`

Generators and lists

- The expression:
          f(x)  for  x  in  range(1000000)
- is a generator (that returns a value when needed) The expression:
          [ f(x)  for  x  in  range(1000000) ]
is a list (object) (and all its values are stored)

DEMO: `progs/genVSlist01.py` + `progs/genVSlist01b.py`

❮ ❯