Like so:
[ item for innerlist in outerlist for item in innerlist ]
Turning that directly into a string with separators:
','.join(str(item) for innerlist in outerlist for item in innerlist)
Yes, the order of 'for innerlist in outerlist' and 'for item in innerlist' is correct. Even though the "body" of the loop is at the start of the listcomp, the order of nested loops (and 'if' clauses) is still the same as when you would write the loop out:
for innerlist in outerlist:
for item in innerlist:
...
Answer from Thomas Wouters on Stack OverflowLike so:
[ item for innerlist in outerlist for item in innerlist ]
Turning that directly into a string with separators:
','.join(str(item) for innerlist in outerlist for item in innerlist)
Yes, the order of 'for innerlist in outerlist' and 'for item in innerlist' is correct. Even though the "body" of the loop is at the start of the listcomp, the order of nested loops (and 'if' clauses) is still the same as when you would write the loop out:
for innerlist in outerlist:
for item in innerlist:
...
Try that:
li=[[0,1,2],[3,4,5],[6,7,8]]
li2 = [ y for x in li for y in x]
You can read it like this:
Give me the list of every ys.
The ys come from the xs.
The xs come from li.
To map that in a string:
','.join(map(str,li2))
Solution
A one-liner will do:
b = '\n'.join('\t'.join('%0.3f' %x for x in y) for y in a)
Using a simpler example:
>>> a = np.arange(25, dtype=float).reshape(5, 5)
>>> a
array([[ 0., 1., 2., 3., 4.],
[ 5., 6., 7., 8., 9.],
[ 10., 11., 12., 13., 14.],
[ 15., 16., 17., 18., 19.],
[ 20., 21., 22., 23., 24.]])
This:
b = '\n'.join('\t'.join('%0.3f' %x for x in y) for y in a)
print(b)
prints this:
0.000 1.000 2.000 3.000 4.000
5.000 6.000 7.000 8.000 9.000
10.000 11.000 12.000 13.000 14.000
15.000 16.000 17.000 18.000 19.000
20.000 21.000 22.000 23.000 24.000
Explanation
You already used a list comprehension in your second method. Here we have a generator expression, which looks exactly like a list comprehension. The only syntactical difference is that the [] are replaced by (). A generator expression does not build the list but hands a so called generator to join. In the end it has the same effect but skips the step of building this intermediate list.
There can be multiple for in such an expression, which makes it nested.
This:
b = '\n'.join('\t'.join('%0.3f' %x for x in y) for y in a)
is equivalent to:
res = []
for y in a:
res.append('\t'.join('%0.3f' %x for x in y))
b = '\n'.join(res)
Performance
I use %%timeit in the IPython Notebook:
%%timeit
b = '\n'.join('\t'.join('%0.3f' %x for x in y) for y in a)
10 loops, best of 3: 42.4 ms per loop
%%timeit
b=''
for i in range(0,a.shape[0]):
for j in range(0,a.shape[1]-1):
b+=str(a[i,j])+'\t'
b+=str(a[i,-1])+'\n'
10 loops, best of 3: 50.2 ms per loop
%%timeit
b=''
for i in range(0,a.shape[0]):
b+='\t'.join(['%0.3f' %x for x in a[i,:]])+'\n'
10 loops, best of 3: 43.8 ms per loop
Looks like they are all about the same speed. Actually, the += is optimized in CPython. Otherwise, it would be much slower, than the join() approach. Other Python implementations such as Jython or PyPy can show much bigger time differences and can make the join() much faster compared to +=.
With Python3 I made it with one line:
str(a).replace('[','').replace(']','').replace('\n',' ')+' '
Output (fixed width):
'191.25 0. 0. 1. 191.251 0. 0. 1. 191.252 0. 0. 1. '
The challenge is to save not only the data buffer, but also the shape and dtype. np.fromstring reads the data buffer, but as a 1d array; you have to get the dtype and shape from else where.
In [184]: a=np.arange(12).reshape(3,4)
In [185]: np.fromstring(a.tostring(),int)
Out[185]: array([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11])
In [186]: np.fromstring(a.tostring(),a.dtype).reshape(a.shape)
Out[186]:
array([[ 0, 1, 2, 3],
[ 4, 5, 6, 7],
[ 8, 9, 10, 11]])
A time honored mechanism to save Python objects is pickle, and numpy is pickle compliant:
In [169]: import pickle
In [170]: a=np.arange(12).reshape(3,4)
In [171]: s=pickle.dumps(a*2)
In [172]: s
Out[172]: "cnumpy.core.multiarray\n_reconstruct\np0\n(cnumpy\nndarray\np1\n(I0\ntp2\nS'b'\np3\ntp4\nRp5\n(I1\n(I3\nI4\ntp6\ncnumpy\ndtype\np7\n(S'i4'\np8\nI0\nI1\ntp9\nRp10\n(I3\nS'<'\np11\nNNNI-1\nI-1\nI0\ntp12\nbI00\nS'\\x00\\x00\\x00\\x00\\x02\\x00\\x00\\x00\\x04\\x00\\x00\\x00\\x06\\x00\\x00\\x00\\x08\\x00\\x00\\x00\\n\\x00\\x00\\x00\\x0c\\x00\\x00\\x00\\x0e\\x00\\x00\\x00\\x10\\x00\\x00\\x00\\x12\\x00\\x00\\x00\\x14\\x00\\x00\\x00\\x16\\x00\\x00\\x00'\np13\ntp14\nb."
In [173]: pickle.loads(s)
Out[173]:
array([[ 0, 2, 4, 6],
[ 8, 10, 12, 14],
[16, 18, 20, 22]])
There's a numpy function that can read the pickle string:
In [181]: np.loads(s)
Out[181]:
array([[ 0, 2, 4, 6],
[ 8, 10, 12, 14],
[16, 18, 20, 22]])
You mentioned np.save to a string, but that you can't use np.load. A way around that is to step further into the code, and use np.lib.npyio.format.
In [174]: import StringIO
In [175]: S=StringIO.StringIO() # a file like string buffer
In [176]: np.lib.npyio.format.write_array(S,a*3.3)
In [177]: S.seek(0) # rewind the string
In [178]: np.lib.npyio.format.read_array(S)
Out[178]:
array([[ 0. , 3.3, 6.6, 9.9],
[ 13.2, 16.5, 19.8, 23.1],
[ 26.4, 29.7, 33. , 36.3]])
The save string has a header with dtype and shape info:
In [179]: S.seek(0)
In [180]: S.readlines()
Out[180]:
["\x93NUMPY\x01\x00F\x00{'descr': '<f8', 'fortran_order': False, 'shape': (3, 4), } \n",
'\x00\x00\x00\x00\x00\x00\x00\x00ffffff\n',
'@ffffff\x1a@\xcc\xcc\xcc\xcc\xcc\xcc#@ffffff*@\x00\x00\x00\x00\x00\x800@\xcc\xcc\xcc\xcc\xcc\xcc3@\x99\x99\x99\x99\x99\x197@ffffff:@33333\xb3=@\x00\x00\x00\x00\x00\x80@@fffff&B@']
If you want a human readable string, you might try json.
In [196]: import json
In [197]: js=json.dumps(a.tolist())
In [198]: js
Out[198]: '[[0, 1, 2, 3], [4, 5, 6, 7], [8, 9, 10, 11]]'
In [199]: np.array(json.loads(js))
Out[199]:
array([[ 0, 1, 2, 3],
[ 4, 5, 6, 7],
[ 8, 9, 10, 11]])
Going to/from the list representation of the array is the most obvious use of json. Someone may have written a more elaborate json representation of arrays.
You could also go the csv format route - there have been lots of questions about reading/writing csv arrays.
'[[ 0.5544 0.4456], [ 0.8811 0.1189]]'
is a poor string representation for this purpose. It does look a lot like the str() of an array, but with , instead of \n. But there isn't a clean way of parsing the nested [], and the missing delimiter is a pain. If it consistently uses , then json can convert it to list.
np.matrix accepts a MATLAB like string:
In [207]: np.matrix(' 0.5544, 0.4456;0.8811, 0.1189')
Out[207]:
matrix([[ 0.5544, 0.4456],
[ 0.8811, 0.1189]])
In [208]: str(np.matrix(' 0.5544, 0.4456;0.8811, 0.1189'))
Out[208]: '[[ 0.5544 0.4456]\n [ 0.8811 0.1189]]'
I'm not sure there's an easy way to do this if you don't have commas between the numbers in your inner lists, but if you do, then you can use ast.literal_eval:
import ast
import numpy as np
s = '[[ 0.5544, 0.4456], [ 0.8811, 0.1189]]'
np.array(ast.literal_eval(s))
array([[ 0.5544, 0.4456],
[ 0.8811, 0.1189]])
EDIT: I haven't tested it very much, but you could use re to insert commas where you need them:
import re
s1 = '[[ 0.5544 0.4456], [ 0.8811 -0.1189]]'
# Replace spaces between numbers with commas:
s2 = re.sub('(\d) +(-|\d)', r'\1,\2', s1)
s2
'[[ 0.5544,0.4456], [ 0.8811,-0.1189]]'
and then hand on to ast.literal_eval:
np.array(ast.literal_eval(s2))
array([[ 0.5544, 0.4456],
[ 0.8811, -0.1189]])
(you need to be careful to match spaces between digits but also spaces between a digit an a minus sign).
There are two parts to this.
First, how do you convert a number like 1 to a letter like 'a', according to your rule? Second, how do you apply a function to all elements of a list?
For the first, one way to write it is with the chr function. This function takes an number and gives you the single-character string for the character with that code point. In particular, chr(65) is 'a', chr(66) is 'b', etc. So, we could just do chr(n + 64).
Or we could use the ord function, which is the inverse of chr, so instead of hardcoding 64 and having to remember that's 1 less than 'a', we can write 1 less than 'a' directly:
def letter(n):
return chr(n + ord('a') - 1)
Of course this isn't the only way to do it. You could also, e.g., use string.ascii_lowercase[n-1].
(Note that either of these solutions not only works in Python 3, where the "code points" are always Unicode, but also in Python 2, where the "code points" are values in some unspecific 8-bit encoding, as long as the intended encoding has all of the lowercase letters in contiguous order, which is true for almost anything you're likely to ever encounter unless you've got some old EBCDIC files lying around.)
For the second, you can use a list comprehension. Your examples are flat (1D) lists, so we'd use a flat list comprehension:
numbers = [2, 3, 4]
letters = [letter(n) for n in numbers]
If you have 2D lists of lists, just use a nested list comprehension:
numbers = [[2, 3], [4, 5]]
letters = [[letter(n) for n in row] for row in numbers]
You can corresponding Alphabets by indexing string.ascii_lowercase which returns all lower case alphabets.
import string
myArray = [[1,2,3],[3,4,5]]
result_array = [[string.ascii_lowercase[element-1] for element in row] for row in myArray]
Result array:
[['a', 'b', 'c'], ['c', 'd', 'e']]
Simply you can use str method.
l = [[0,1,2],[3,4,5],[6,7,8]]
s = str(s)
print(s) # [[0,1,2],[3,4,5],[6,7,8]]
print(type(s)) # <class 'str'>
print(s[0]) # [
You can convert the string to JSON, to make output compact without spaces there is a line in the docs with details
To get the most compact JSON representation, you should specify (',', ':') to eliminate whitespace.
import json
json.dumps(list, separators=(',', ':')) # '[[0,1,2],[3,4,5],[6,7,8]]'