Skip to main content
Code Review

Return to Answer

added 453 characters in body
Source Link
Graipher
  • 41.6k
  • 7
  • 70
  • 134
  • You calculate some values multiple times (like str(A[0])), save those to a variable.

  • If you want to compare to None, use is (since it is a singleton).

  • No else needed after an if...return (this is a matter of personal style, I prefer not having the additional level of indentation).

  • Use str.rjust to add enough whitespace in front of your strings. You could also use str.format for this, but it looks less nice.

  • Your w has a weird structure, with the width of the first column being the last entry and the rest starting at zero.

  • Give the unicode values names. And then add functions to draw a line of specified length.

  • String addition is costly and slow. Try to consistently use building a list and str.joining it.

     UPPER_LEFT = u'\u250c'
     UPPER_RIGHT = u'\u2510'
     LOWER_LEFT = u'\u2514'
     LOWER_RIGHT = u'\u2518'
     HORIZONTAL = u'\u2500'
     VERTICAL = u'\u2502'
     def upper_line(width):
     return UPPER_LEFT + HORIZONTAL * (width - 2) + UPPER_RIGHT
     def lower_line(width):
     return LOWER_LEFT + HORIZONTAL * (width - 2) + LOWER_RIGHT
     def left_line(height):
     return "\n".join([UPPER_LEFT] + [VERTICAL] * (height - 2)] + [LOWER_LEFT])
     def right_line(height):
     return "\n".join([UPPER_RIGHT] + [VERTICAL] * (height - 2)] + [LOWER_RIGHT])
     def ndtotext(A, w=None, h=None):
     """Returns a string to pretty print the numpy.ndarray `A`.
     Currently supports 1 - 3 dimensions only.
     Raises a NotImplementedError if an array with more dimensions is passed.
     Describe `w` and `h`.
     """
     if A.ndim == 1:
     if w is None:
     return str(A)
     s = " ".join([str(value).rjust(width) for value, width in zip(A, w)])
     return '[{}]'.format(s)
     elif A.ndim == 2:
     widths = [max([len(str(s)) for s in A[:, i]]) for i in range(A.shape[1])]
     s = "".join([' ' + ndtotext(AA, w=widths) + '\n'' \n' for AA in A])
     w0 = sum(widths) + len(widths) - 1 + 2 # spaces between elements and corners
     return upper_line(w0) + '\n'  + s + lower_line(w0)
     elif A.ndim == 3:
     h = A.shape[1]
     strings = [left_line(h)]
     strings.extend(ndtotext(a) + '\n' for a in A)
     strings.append(right_line(h))
     return '\n'.join(''.join(pair) for pair in zip(*map(str.splitlines, strings)))
     raise NotImplementedError("Currently only 1 - 3 dimensions are supported")
    

Example usage:

x = np.arange(12)
print(ndtotext(x))
[ 0 1 2 3 4 5 6 7 8 9 10 11]
print(ndtotext(x.reshape(3, 4)))
┌───────────┐
 [0 1 2 3] 
 [4 5 6 7] 
 [8 9 10 11] 
└───────────┘
print(ndtotext(x.reshape(3, 2, 2)))
┌┌─────┐┌─────┐┌───────┐┐
│ [0 1] [4 5] [ 8 9] │
│ [2 3] [6 7] [10 11] │
└└─────┘└─────┘└───────┘┘
  • You calculate some values multiple times (like str(A[0])), save those to a variable.

  • If you want to compare to None, use is (since it is a singleton).

  • No else needed after an if...return (this is a matter of personal style, I prefer not having the additional level of indentation).

  • Use str.rjust to add enough whitespace in front of your strings. You could also use str.format for this, but it looks less nice.

  • Your w has a weird structure, with the width of the first column being the last entry and the rest starting at zero.

  • Give the unicode values names. And then add functions to draw a line of specified length.

  • String addition is costly and slow. Try to consistently use building a list and str.joining it.

     UPPER_LEFT = u'\u250c'
     UPPER_RIGHT = u'\u2510'
     LOWER_LEFT = u'\u2514'
     LOWER_RIGHT = u'\u2518'
     HORIZONTAL = u'\u2500'
     VERTICAL = u'\u2502'
     def upper_line(width):
     return UPPER_LEFT + HORIZONTAL * (width - 2) + UPPER_RIGHT
     def lower_line(width):
     return LOWER_LEFT + HORIZONTAL * (width - 2) + LOWER_RIGHT
     def left_line(height):
     return "\n".join([UPPER_LEFT] + [VERTICAL] * (height - 2)] + [LOWER_LEFT])
     def right_line(height):
     return "\n".join([UPPER_RIGHT] + [VERTICAL] * (height - 2)] + [LOWER_RIGHT])
     def ndtotext(A, w=None, h=None):
     """Returns a string to pretty print the numpy.ndarray `A`.
     Currently supports 1 - 3 dimensions only.
     Raises a NotImplementedError if an array with more dimensions is passed.
     Describe `w` and `h`.
     """
     if A.ndim == 1:
     if w is None:
     return str(A)
     s = " ".join([str(value).rjust(width) for value, width in zip(A, w)])
     return '[{}]'.format(s)
     elif A.ndim == 2:
     widths = [max([len(str(s)) for s in A[:, i]]) for i in range(A.shape[1])]
     s = "".join([' ' + ndtotext(AA, w=widths) + '\n' for AA in A])
     w0 = sum(widths) + len(widths) - 1 + 2 # spaces between elements and corners
     return upper_line(w0) + s + lower_line(w0)
     elif A.ndim == 3:
     h = A.shape[1]
     strings = [left_line(h)]
     strings.extend(ndtotext(a) + '\n' for a in A)
     strings.append(right_line(h))
     return '\n'.join(''.join(pair) for pair in zip(*map(str.splitlines, strings)))
     raise NotImplementedError("Currently only 1 - 3 dimensions are supported")
    
  • You calculate some values multiple times (like str(A[0])), save those to a variable.

  • If you want to compare to None, use is (since it is a singleton).

  • No else needed after an if...return (this is a matter of personal style, I prefer not having the additional level of indentation).

  • Use str.rjust to add enough whitespace in front of your strings. You could also use str.format for this, but it looks less nice.

  • Your w has a weird structure, with the width of the first column being the last entry and the rest starting at zero.

  • Give the unicode values names. And then add functions to draw a line of specified length.

  • String addition is costly and slow. Try to consistently use building a list and str.joining it.

     UPPER_LEFT = u'\u250c'
     UPPER_RIGHT = u'\u2510'
     LOWER_LEFT = u'\u2514'
     LOWER_RIGHT = u'\u2518'
     HORIZONTAL = u'\u2500'
     VERTICAL = u'\u2502'
     def upper_line(width):
     return UPPER_LEFT + HORIZONTAL * width + UPPER_RIGHT
     def lower_line(width):
     return LOWER_LEFT + HORIZONTAL * width + LOWER_RIGHT
     def left_line(height):
     return "\n".join([UPPER_LEFT] + [VERTICAL] * height + [LOWER_LEFT])
     def right_line(height):
     return "\n".join([UPPER_RIGHT] + [VERTICAL] * height + [LOWER_RIGHT])
     def ndtotext(A, w=None, h=None):
     """Returns a string to pretty print the numpy.ndarray `A`.
     Currently supports 1 - 3 dimensions only.
     Raises a NotImplementedError if an array with more dimensions is passed.
     Describe `w` and `h`.
     """
     if A.ndim == 1:
     if w is None:
     return str(A)
     s = " ".join([str(value).rjust(width) for value, width in zip(A, w)])
     return '[{}]'.format(s)
     elif A.ndim == 2:
     widths = [max([len(str(s)) for s in A[:, i]]) for i in range(A.shape[1])]
     s = "".join([' ' + ndtotext(AA, w=widths) + ' \n' for AA in A])
     w0 = sum(widths) + len(widths) - 1 + 2 # spaces between elements and corners
     return upper_line(w0) + '\n'  + s + lower_line(w0)
     elif A.ndim == 3:
     h = A.shape[1]
     strings = [left_line(h)]
     strings.extend(ndtotext(a) + '\n' for a in A)
     strings.append(right_line(h))
     return '\n'.join(''.join(pair) for pair in zip(*map(str.splitlines, strings)))
     raise NotImplementedError("Currently only 1 - 3 dimensions are supported")
    

Example usage:

x = np.arange(12)
print(ndtotext(x))
[ 0 1 2 3 4 5 6 7 8 9 10 11]
print(ndtotext(x.reshape(3, 4)))
┌───────────┐
 [0 1 2 3] 
 [4 5 6 7] 
 [8 9 10 11] 
└───────────┘
print(ndtotext(x.reshape(3, 2, 2)))
┌┌─────┐┌─────┐┌───────┐┐
│ [0 1] [4 5] [ 8 9] │
│ [2 3] [6 7] [10 11] │
└└─────┘└─────┘└───────┘┘
deleted 11 characters in body
Source Link
Graipher
  • 41.6k
  • 7
  • 70
  • 134
  • You calculate some values multiple times (like str(A[0])), save those to a variable.

  • If you want to compare to None, use is (since it is a singleton).

  • No else needed after an if...return (this is a matter of personal style, I prefer not having the additional level of indentation).

  • Use str.rjust to add enough whitespace in front of your strings. You could also use str.format for this, but it looks less nice.

  • Your w has a weird structure, with the width of the first column being the last entry and the rest starting at zero.

  • Give the unicode values names. And then add functions to draw a line of specified length.

  • String addition is costly and slow. Try to consistently use building a list and str.joining it.

     UPPER_LEFT = u'\u250c'
     UPPER_RIGHT = u'\u2510'
     LOWER_LEFT = u'\u2514'
     LOWER_RIGHT = u'\u2518'
     HORIZONTAL = u'\u2500'
     VERTICAL = u'\u2502'
     def upper_line(width):
     return UPPER_LEFT + HORIZONTAL * (width - 2) + UPPER_RIGHT
     def lower_line(width):
     return LOWER_LEFT + HORIZONTAL * (width - 2) + LOWER_RIGHT
     def left_line(height):
     return "\n".join([UPPER_LEFT] + [VERTICAL] * (height - 2)] + [LOWER_LEFT])
     def right_line(height):
     return "\n".join([UPPER_RIGHT] + [VERTICAL] * (height - 2)] + [symbols['lower_right']][LOWER_RIGHT])
     def ndtotext(A, w=None, h=None):
     """Returns a string to pretty print the numpy.ndarray `A`.
     Currently supports 1 - 3 dimensions only.
     Raises a NotImplementedError if an array with more dimensions is passed.
     Describe `w` and `h`.
     """
     if A.ndim == 1:
     if w is None:
     return str(A)
     s = " ".join([str(value).rjust(width) for value, width in zip(A, w)])
     return '[{}]'.format(s)
     elif A.ndim == 2:
     widths = [max([len(str(s)) for s in A[:, i]]) for i in range(A.shape[1])]
     s = "".join([' ' + ndtotext(AA, w=widths) + '\n' for AA in A])
     w0 = sum(widths) + len(widths) - 1 + 2 # spaces between elements and corners
     return upper_line(w0) + s + lower_line(w0)
     elif A.ndim == 3:
     h = A.shape[1]
     strings = [left_line(h)]
     strings.extend(ndtotext(a) + '\n' for a in A)
     strings.append(right_line(h))
     return '\n'.join(''.join(pair) for pair in zip(*map(str.splitlines, strings)))
     raise NotImplementedError("Currently only 1 - 3 dimensions are supported")
    
  • You calculate some values multiple times (like str(A[0])), save those to a variable.

  • If you want to compare to None, use is (since it is a singleton).

  • No else needed after an if...return (this is a matter of personal style, I prefer not having the additional level of indentation).

  • Use str.rjust to add enough whitespace in front of your strings. You could also use str.format for this, but it looks less nice.

  • Your w has a weird structure, with the width of the first column being the last entry and the rest starting at zero.

  • Give the unicode values names. And then add functions to draw a line of specified length.

  • String addition is costly and slow. Try to consistently use building a list and str.joining it.

     UPPER_LEFT = u'\u250c'
     UPPER_RIGHT = u'\u2510'
     LOWER_LEFT = u'\u2514'
     LOWER_RIGHT = u'\u2518'
     HORIZONTAL = u'\u2500'
     VERTICAL = u'\u2502'
     def upper_line(width):
     return UPPER_LEFT + HORIZONTAL * (width - 2) + UPPER_RIGHT
     def lower_line(width):
     return LOWER_LEFT + HORIZONTAL * (width - 2) + LOWER_RIGHT
     def left_line(height):
     return "\n".join([UPPER_LEFT] + [VERTICAL] * (height - 2)] + [LOWER_LEFT])
     def right_line(height):
     return "\n".join([UPPER_RIGHT] + [VERTICAL] * (height - 2)] + [symbols['lower_right']])
     def ndtotext(A, w=None, h=None):
     """Returns a string to pretty print the numpy.ndarray `A`.
     Currently supports 1 - 3 dimensions only.
     Raises a NotImplementedError if an array with more dimensions is passed.
     Describe `w` and `h`.
     """
     if A.ndim == 1:
     if w is None:
     return str(A)
     s = " ".join([str(value).rjust(width) for value, width in zip(A, w)])
     return '[{}]'.format(s)
     elif A.ndim == 2:
     widths = [max([len(str(s)) for s in A[:, i]]) for i in range(A.shape[1])]
     s = "".join([' ' + ndtotext(AA, w=widths) + '\n' for AA in A])
     w0 = sum(widths) + len(widths) - 1 + 2 # spaces between elements and corners
     return upper_line(w0) + s + lower_line(w0)
     elif A.ndim == 3:
     h = A.shape[1]
     strings = [left_line(h)]
     strings.extend(ndtotext(a) + '\n' for a in A)
     strings.append(right_line(h))
     return '\n'.join(''.join(pair) for pair in zip(*map(str.splitlines, strings)))
     raise NotImplementedError("Currently only 1 - 3 dimensions are supported")
    
  • You calculate some values multiple times (like str(A[0])), save those to a variable.

  • If you want to compare to None, use is (since it is a singleton).

  • No else needed after an if...return (this is a matter of personal style, I prefer not having the additional level of indentation).

  • Use str.rjust to add enough whitespace in front of your strings. You could also use str.format for this, but it looks less nice.

  • Your w has a weird structure, with the width of the first column being the last entry and the rest starting at zero.

  • Give the unicode values names. And then add functions to draw a line of specified length.

  • String addition is costly and slow. Try to consistently use building a list and str.joining it.

     UPPER_LEFT = u'\u250c'
     UPPER_RIGHT = u'\u2510'
     LOWER_LEFT = u'\u2514'
     LOWER_RIGHT = u'\u2518'
     HORIZONTAL = u'\u2500'
     VERTICAL = u'\u2502'
     def upper_line(width):
     return UPPER_LEFT + HORIZONTAL * (width - 2) + UPPER_RIGHT
     def lower_line(width):
     return LOWER_LEFT + HORIZONTAL * (width - 2) + LOWER_RIGHT
     def left_line(height):
     return "\n".join([UPPER_LEFT] + [VERTICAL] * (height - 2)] + [LOWER_LEFT])
     def right_line(height):
     return "\n".join([UPPER_RIGHT] + [VERTICAL] * (height - 2)] + [LOWER_RIGHT])
     def ndtotext(A, w=None, h=None):
     """Returns a string to pretty print the numpy.ndarray `A`.
     Currently supports 1 - 3 dimensions only.
     Raises a NotImplementedError if an array with more dimensions is passed.
     Describe `w` and `h`.
     """
     if A.ndim == 1:
     if w is None:
     return str(A)
     s = " ".join([str(value).rjust(width) for value, width in zip(A, w)])
     return '[{}]'.format(s)
     elif A.ndim == 2:
     widths = [max([len(str(s)) for s in A[:, i]]) for i in range(A.shape[1])]
     s = "".join([' ' + ndtotext(AA, w=widths) + '\n' for AA in A])
     w0 = sum(widths) + len(widths) - 1 + 2 # spaces between elements and corners
     return upper_line(w0) + s + lower_line(w0)
     elif A.ndim == 3:
     h = A.shape[1]
     strings = [left_line(h)]
     strings.extend(ndtotext(a) + '\n' for a in A)
     strings.append(right_line(h))
     return '\n'.join(''.join(pair) for pair in zip(*map(str.splitlines, strings)))
     raise NotImplementedError("Currently only 1 - 3 dimensions are supported")
    
Source Link
Graipher
  • 41.6k
  • 7
  • 70
  • 134

If A.ndim is not in 1, 2, 3, your code tries to return a non-existing string s. It would be better to be explicit about what your code supports atm:

def ndtotext(A, w=None, h=None):
 ...
 else:
 raise NotImplementedError("Currently only 1 - 3 dimensions are supported")
 return s

While we are at the point of having your code be clear about what is happening, you should add a docstring explaining what your code does:

def ndtotext(A, w=None, h=None):
 """Returns a string to pretty print the numpy.ndarray `A`.
 
 Currently supports 1 - 3 dimensions only.
 Raises a NotImplementedError if an array with more dimensions is passed.
 Describe `w` and `h`.
 """
 ...

Next, Python has an official style-guide, PEP8, which programmers are encouraged to follow. One of the things it recommends is surrounding operators with spaces (which I fixed in the rest of the code) and using lower_case for variables and functions (which I left as is for now).

Now, let's come to your actual code:

  • You calculate some values multiple times (like str(A[0])), save those to a variable.

  • If you want to compare to None, use is (since it is a singleton).

  • No else needed after an if...return (this is a matter of personal style, I prefer not having the additional level of indentation).

  • Use str.rjust to add enough whitespace in front of your strings. You could also use str.format for this, but it looks less nice.

  • Your w has a weird structure, with the width of the first column being the last entry and the rest starting at zero.

  • Give the unicode values names. And then add functions to draw a line of specified length.

  • String addition is costly and slow. Try to consistently use building a list and str.joining it.

     UPPER_LEFT = u'\u250c'
     UPPER_RIGHT = u'\u2510'
     LOWER_LEFT = u'\u2514'
     LOWER_RIGHT = u'\u2518'
     HORIZONTAL = u'\u2500'
     VERTICAL = u'\u2502'
     def upper_line(width):
     return UPPER_LEFT + HORIZONTAL * (width - 2) + UPPER_RIGHT
     def lower_line(width):
     return LOWER_LEFT + HORIZONTAL * (width - 2) + LOWER_RIGHT
     def left_line(height):
     return "\n".join([UPPER_LEFT] + [VERTICAL] * (height - 2)] + [LOWER_LEFT])
     def right_line(height):
     return "\n".join([UPPER_RIGHT] + [VERTICAL] * (height - 2)] + [symbols['lower_right']])
     def ndtotext(A, w=None, h=None):
     """Returns a string to pretty print the numpy.ndarray `A`.
     Currently supports 1 - 3 dimensions only.
     Raises a NotImplementedError if an array with more dimensions is passed.
     Describe `w` and `h`.
     """
     if A.ndim == 1:
     if w is None:
     return str(A)
     s = " ".join([str(value).rjust(width) for value, width in zip(A, w)])
     return '[{}]'.format(s)
     elif A.ndim == 2:
     widths = [max([len(str(s)) for s in A[:, i]]) for i in range(A.shape[1])]
     s = "".join([' ' + ndtotext(AA, w=widths) + '\n' for AA in A])
     w0 = sum(widths) + len(widths) - 1 + 2 # spaces between elements and corners
     return upper_line(w0) + s + lower_line(w0)
     elif A.ndim == 3:
     h = A.shape[1]
     strings = [left_line(h)]
     strings.extend(ndtotext(a) + '\n' for a in A)
     strings.append(right_line(h))
     return '\n'.join(''.join(pair) for pair in zip(*map(str.splitlines, strings)))
     raise NotImplementedError("Currently only 1 - 3 dimensions are supported")
    

This can probably be even more compactified, but I think it is a good start.

lang-py

AltStyle によって変換されたページ (->オリジナル) /