2
\$\begingroup\$

I have a 2D Python array (list of lists). I treat this as a 'table'. Now I want to replace the first row and the top row with a header row and column. The row and the header are exactly the same.

I try this using list comprehension. It works out for the 'row' part, but the column part is not very Pythonic yet.

# The header that i want to add
headers = ['foo', 'bar', 'baz', 'other']
l = len(headers) + 1  # The final matrix is one element bigger

# square matrix of random size, filled with data
array = [['xxx' for i in range(l)] for j in range(l)]

# The concise one - add headers to top row
array[0] = ['Title'] + [category for category in headers]

# The ugly one - add headers for the rows
for i in range(l):
    array[i][0] = array[0][i]

The final output should look like this (which it does):

[['Title', 'foo', 'bar', 'baz', 'other'],
 ['foo', 'xxx', 'xxx', 'xxx', 'xxx'],
 ['bar', 'xxx', 'xxx', 'xxx', 'xxx'],
 ['baz', 'xxx', 'xxx', 'xxx', 'xxx'],
 ['other', 'xxx', 'xxx', 'xxx', 'xxx']]

I'm just not so happy with the 'for' loop. How can this be done more Pythonic?

\$\endgroup\$

2 Answers 2

2
\$\begingroup\$

Maybe this can help (if you don't want to use numpy):

headers = ['foo', 'bar', 'baz', 'other']
l = len(headers)

arr = [["xxx" for i in range(l)] for j in range(l)]

# adding top row
arr = [headers] + arr

# adding first column
headers_mod = ['Title'] + headers
new_arr = [[headers_mod[i]]+arr[i] for i in range(l+1)]

for i in new_arr:
  print(*i)

gives you the output as:

Title foo bar baz other
foo xxx xxx xxx xxx
bar xxx xxx xxx xxx
baz xxx xxx xxx xxx
other xxx xxx xxx xxx

Otherwise, when dealing with array manipulations in python try going with numpy, pandas, as they provide better operations like by giving option for axis, transpose, etc.

\$\endgroup\$
2
  • \$\begingroup\$ After rethinking you are right. I'm just not that familiar wit NumPy. I changed one of my matrices to a numpy array and surprisingly my code was still working. Thank you. \$\endgroup\$
    – grrfield
    Commented Feb 11, 2021 at 7:06
  • \$\begingroup\$ Yeah, mostly its the same but with very useful features for mathematical manipulations. \$\endgroup\$ Commented Feb 11, 2021 at 7:08
1
\$\begingroup\$

numpy is excellent for tables, but for a labeled table like this pandas might be better for your needs.

Solution using numpy:

import numpy as np

# The header that i want to add
headers = ['foo', 'bar', 'baz', 'other']

ll = len(headers)+1
data = [['xxx' for _ in range(ll)] for j in range(ll)]

data = np.array(data, dtype=object)

data[0,0] = 'Title'
data[0,1:] = headers
data[1:,0] = headers

print(data)

prints

[['Title' 'foo' 'bar' 'baz' 'other']
 ['foo' 'xxx' 'xxx' 'xxx' 'xxx']
 ['bar' 'xxx' 'xxx' 'xxx' 'xxx']
 ['baz' 'xxx' 'xxx' 'xxx' 'xxx']
 ['other' 'xxx' 'xxx' 'xxx' 'xxx']]

Setting dtype to object allows your array to mix strings and other data types you might want to use. If your data is just strings then you can use 'UN' as the dtype, where N is the longest string you plan to use. (Numpy, when making an all string array automatically picks your longest string as the maximum length for the strings, which is fine unless your strings are all shorter than the headers you plan to add.)

Alternate version of the above code:

import numpy as np

# The header that i want to add
headers = ['foo', 'bar', 'baz', 'other']

# Add Title to headers  to simply later assignment
headers = ['Title'] + headers

ll = len(headers)
data = [['xxx' for _ in range(ll)] for j in range(ll)]

data = np.array(data)

data[0,:] = headers
data[:,0] = headers

print(data)

pandas, on the other hand, is explicitly designed to handle headers

import numpy as np, pandas as pd

# The header that i want to add
headers = ['foo', 'bar', 'baz', 'other']

ll = len(headers) + 1
data = [['xxx' for _ in range(ll)] for j in range(ll)]

data = np.array(data)

data = pd.DataFrame(data[1:,1:], columns=headers, index=headers)
data.columns.name = 'Title'

data.loc['foo','bar'] = 'yes'
print(data)
print('')
print(data['bar'])
print('')
print(data.loc['foo',:])

prints

Title  foo  bar  baz other
foo    xxx  yes  xxx   xxx
bar    xxx  xxx  xxx   xxx
baz    xxx  xxx  xxx   xxx
other  xxx  xxx  xxx   xxx

foo      yes
bar      xxx
baz      xxx
other    xxx
Name: bar, dtype: object

Title
foo      xxx
bar      yes
baz      xxx
other    xxx
Name: foo, dtype: object
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.