Class Notes: 2d Lists


  1. Creating 2d Lists [Pre-reading]
  2. Getting 2d List Dimensions [Pre-reading]
  3. Copying and Aliasing 2d Lists [Pre-reading]
  4. Printing 2d Lists [Pre-reading]
  5. Nested Looping over 2d Lists [Pre-reading]
  6. Accessing 2d Lists by Row or Column [Pre-reading]
  7. Non-Rectangular ("Ragged") 2d Lists [Pre-reading]
  8. 3d Lists


  1. Creating 2d Lists [Pre-reading]
  2.  

  3. Getting 2d List Dimensions [Pre-reading]
  4.  
    # Create an "arbitrary" 2d List
    a = [ [ 2, 3, 5] , [ 1, 4, 7 ] ]
    print("a = ", a)
    
    # Now find its dimensions
    rows = len(a)
    cols = len(a[0])
    print("rows =", rows)
    print("cols =", cols)

  5. Copying and Aliasing 2d Lists [Pre-reading]
  6.  

  7. Printing 2d Lists [Pre-reading]
  8.  
    1. Basic Version:
      # Here are two helpful functions:
      #    repr2dList(L): returns a nicely-formatted multiline string, and
      #    print2dList(L): prints a 2d list in that nicely-formatted way
      
      #######################################
      
      def repr2dList(L):
          if (L == []): return '[]'
          output = [ ]
          rows = len(L)
          cols = max([len(L[row]) for row in range(rows)])
          M = [['']*cols for row in range(rows)]
          for row in range(rows):
              for col in range(len(L[row])):
                  M[row][col] = repr(L[row][col])
          colWidths = [0] * cols
          for col in range(cols):
              colWidths[col] = max([len(M[row][col]) for row in range(rows)])
          output.append('[\n')
          for row in range(rows):
              output.append(' [ ')
              for col in range(cols):
                  if (col > 0):
                      output.append(', ' if col < len(L[row]) else '  ')
                  output.append(M[row][col].rjust(colWidths[col]))
              output.append((' ],' if row < rows-1 else ' ]') + '\n')
          output.append(']')
          return ''.join(output)
      
      def print2dList(L):
          print(repr2dList(L))
      
      #######################################
      
      # Let's give the new function a try!
      L = [ [ 1, 23, 'a' ] , [ 4, 5, 6789, 10, 100 ] ]
      
      assert(repr2dList(L) == '''\
      [
       [ 1, 23,  'a'          ],
       [ 4,  5, 6789, 10, 100 ]
      ]''')
      
      print2dList(L)

    2. Fancy Version (with outline and row and col labels):
      # Helper function for print2dList.
      # This finds the maximum length of the string
      # representation of any item in the 2d list
      def maxItemLength(a):
          maxLen = 0
          for row in range(len(a)):
              for col in range(len(a[row])):
                  maxLen = max(maxLen, len(repr(a[row][col])))
          return maxLen
      
      def print2dList(a):
          if a == []:
              print([])
              return
          print()
          rows, cols = len(a), len(a[0])
          maxCols = max([len(row) for row in a])
          fieldWidth = max(maxItemLength(a), len(f'col={maxCols-1}'))
          rowLabelSize = 5 + len(str(rows-1))
          rowPrefix = ' '*rowLabelSize+' '
          rowSeparator = rowPrefix + '|' + ('-'*(fieldWidth+3) + '|')*maxCols
          print(rowPrefix, end='  ')
          # Prints the column labels centered
          for col in range(maxCols):
              print(f'col={col}'.center(fieldWidth+2), end='  ')
          print('\n' + rowSeparator)
          for row in range(rows):
              # Prints the row labels
              print(f'row={row}'.center(rowLabelSize), end=' | ')
              # Prints each item of the row flushed-right but the same width
              for col in range(len(a[row])):
                  print(repr(a[row][col]).center(fieldWidth+1), end=' | ')
              # Prints out missing cells in each column in case the list is ragged
              missingCellChar = chr(10006)
              for col in range(len(a[row]), maxCols):
                  print(missingCellChar*(fieldWidth+1), end=' | ')
              print('\n' + rowSeparator)
          print()
      
      # Let's give the new function a try!
      a = [ [ 1, -1023, 3 ] , [ 4, 5, 678 ] ]
      b = [ [123, 4567, 891011], [567890, 'ABC'], ['Amazing!', True, '', -3.14, None]]
      print2dList(a)
      print2dList(b)

  9. Nested Looping over 2d Lists [Pre-reading]
  10.  
    # Create an "arbitrary" 2d List
    a = [ [ 2, 3, 5] , [ 1, 4, 7 ] ]
    print("Before: a =", a)
    
    # Now find its dimensions
    rows = len(a)
    cols = len(a[0])
    
    # And now loop over every element
    # Here, we'll add one to each element,
    # just to make a change we can easily see
    for row in range(rows):
        for col in range(cols):
            # This code will be run rows*cols times, once for each
            # element in the 2d list
            a[row][col] += 1
    
    # Finally, print the results
    print("After:  a =", a)

  11. Accessing 2d Lists by Row or Column [Pre-reading]
  12.  

  13. Non-Rectangular ("Ragged") 2d Lists [Pre-reading]
  14.  
    # 2d lists do not have to be rectangular
    a = [ [ 1, 2, 3 ] ,
          [ 4, 5 ],
          [ 6 ],
          [ 7, 8, 9, 10 ] ]
    
    rows = len(a)
    for row in range(rows):
        cols = len(a[row]) # now cols depends on each row
        print("Row", row, "has", cols, "columns: ", end="")
        for col in range(cols):
            print(a[row][col], " ", end="")
        print()

  15. 3d Lists
  16.  
    # 2d lists do not really exist in Python.
    # They are just lists that happen to contain other lists as elements.
    # And so this can be done for "3d lists", or even "4d" or higher-dimensional lists.
    # And these can also be non-rectangular, of course!
    
    a = [ [ [ 1, 2 ],
            [ 3, 4 ] ],
          [ [ 5, 6, 7 ],
            [ 8, 9 ] ],
          [ [ 10 ] ] ]
    
    for i in range(len(a)):
        for j in range(len(a[i])):
            for k in range(len(a[i][j])):
                print(f'a[{i}][{j}][{k}] = {a[i][j][k]}')