Re: Newbie looking for elegant solution
On Wednesday, March 25, 2015 at 11:23:08 AM UTC+5:30, Paul Rubin wrote: kai.peters writes 1 bit images of a size of 1024 x 1280 need to be processed this way, so 1310720 list elements. Also needs to be 2.7 only. Where are these lists going to come from? Files? Process the file differently, probably. Use generators instead of lists, maybe. Some C-ish solutions and then two loop-unrollings: def foo(lst): i = 0 while i len(lst): acc = 0 for j in range(8): acc = 2*acc+lst[i] i += 1 yield acc def bar(lst): i = 0 while i len(lst): acc = 0 acc = 2*acc+lst[i] acc = 2*acc+lst[i+1] acc = 2*acc+lst[i+2] acc = 2*acc+lst[i+3] acc = 2*acc+lst[i+4] acc = 2*acc+lst[i+5] acc = 2*acc+lst[i+6] acc = 2*acc+lst[i+7] i += 8 yield acc def baz(lst): i = 0 while i len(lst): acc = (128*lst[i] + 64*lst[i+1] + 32*lst[i+2] + 16*lst[i+3] + 8*lst[i+4] + 4*lst[i+5] + 2*lst[i+6] + lst[i+7]) i += 8 yield acc -- https://mail.python.org/mailman/listinfo/python-list
Re: Newbie looking for elegant solution
otaksoftspamt...@gmail.com wrote: I have a list containing 9600 integer elements - each integer is either 0 or 1. Starting at the front of the list, I need to combine 8 list elements into 1 by treating them as if they were bits of one byte with 1 and 0 denoting bit on/off (the 8th element would be the rightmost bit of the first byte). The end result should be a new list that is 8 x shorter than the original list containing integers between 0 and 255. Speed is not of utmost importance - an elegant solution is. Any suggestions? Thanks for all input, Here's another way. Works in Python 2 and 3. x = [1, 0, 1, 1, 0, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 1, 0, 1, 0, 1] [int(''.join( str(y) for y in x[z:z+8]),2) for z in range(0, len(x), 8)] [177, 105, 117] -- https://mail.python.org/mailman/listinfo/python-list
Re: Newbie looking for elegant solution
On Mar 24, 2015, at 8:28 PM, Chris Angelico ros...@gmail.com wrote: On Wed, Mar 25, 2015 at 2:13 PM, otaksoftspamt...@gmail.com wrote: I have a list containing 9600 integer elements - each integer is either 0 or 1. Starting at the front of the list, I need to combine 8 list elements into 1 by treating them as if they were bits of one byte with 1 and 0 denoting bit on/off (the 8th element would be the rightmost bit of the first byte). Speed is not of utmost importance - an elegant solution is. Any suggestions? Oooh fun! l = [1, 0, 1, 1, 0, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 1, 0, 1, 0, 1] list(int(''.join(str(i) for i in l),2).to_bytes(len(l)//8,'big')) [177, 105, 117] Convert it into a string, convert the string to an integer (interpreting it as binary), then convert the integer into a series of bytes, and interpret those bytes as a list of integers. Example works in Python 3. For Python 2, you'll need ord() to get the integers at the end. I'm not sure how elegant this is, but it's a fun trick to play with :) Next idea please! I love these kinds of threads. Me too. These are my favorite threads. Here’s my entry: [sum(b (7 - i) for i, b in enumerate(bits)) for bits in zip(*[l[n::8] for n in range(8)])] I think there has to be a better way to do the left hand part, but I liked the zipped iterators on 8 slices. -- https://mail.python.org/mailman/listinfo/python-list
Re: Newbie looking for elegant solution
kai.pet...@gmail.com writes: im.getdata() = sequence Returns the contents of an image as a sequence object containing pixel values. The sequence object is flattened, so that values for line one follow directly after the values of line zero, and so on. And this is a list of 1's and 0's, I guess for a bitonal picture? Anyway, the code I posted should be able to take in the sequence directly (lazily) without needing an intermediate list. If you change the outer list comprehension to a generator expression (i.e. in Python 2.x, replace the square brackets with parentheses) it will produce a lazy sequence at the output, that you can then process one line at a time or whatever. Also, on computers these days, a million element list isn't a big problem. What are you going to do with the output? That might also help people find suggestions. -- https://mail.python.org/mailman/listinfo/python-list
Re: Newbie looking for elegant solution
On 26-3-2015 0:14, kai.pet...@gmail.com wrote: On Tuesday, 24 March 2015 20:14:06 UTC-7, otaksoft...@gmail.com wrote: I have a list containing 9600 integer elements - each integer is either 0 or 1. Starting at the front of the list, I need to combine 8 list elements into 1 by treating them as if they were bits of one byte with 1 and 0 denoting bit on/off (the 8th element would be the rightmost bit of the first byte). The end result should be a new list that is 8 x shorter than the original list containing integers between 0 and 255. Speed is not of utmost importance - an elegant solution is. Any suggestions? Thanks for all input, Kai The list comes from PILLOW: getdata # im.getdata() = sequence Don't you want to use Image.tobytes() instead? Or, Image.save() directly if you want to store the image somewhere else perhaps? In other words, what are you going to do with the -internal- data returned from getdata, perhaps you don't even want to call it, and skip dealing with the raw pixel bits altogether... Irmen -- https://mail.python.org/mailman/listinfo/python-list
Re: Newbie looking for elegant solution
On Tuesday, 24 March 2015 20:14:06 UTC-7, otaksoft...@gmail.com wrote: I have a list containing 9600 integer elements - each integer is either 0 or 1. Starting at the front of the list, I need to combine 8 list elements into 1 by treating them as if they were bits of one byte with 1 and 0 denoting bit on/off (the 8th element would be the rightmost bit of the first byte). The end result should be a new list that is 8 x shorter than the original list containing integers between 0 and 255. Speed is not of utmost importance - an elegant solution is. Any suggestions? Thanks for all input, Kai The list comes from PILLOW: getdata # im.getdata() = sequence Returns the contents of an image as a sequence object containing pixel values. The sequence object is flattened, so that values for line one follow directly after the values of line zero, and so on. Note that the sequence object returned by this method is an internal PIL data type, which only supports certain sequence operations, including iteration and basic sequence access. To convert it to an ordinary sequence (e.g. for printing), use list(im.getdata()). -- https://mail.python.org/mailman/listinfo/python-list
Re: Newbie looking for elegant solution
On Wednesday, 25 March 2015 18:10:00 UTC-7, Paul Rubin wrote: nobody writes: I though that the bytes type is Python 3 only? If so, I cannot use it. In Python 2, the regular string type (str) is a byte vector, though it is immutable. Do you send one scan line at a time to the rendering device, or the whole file all at once, or what? Do you want to dump the output to a disk file and send that to the rendering device as a separate step? Anyway, use the chr function to turn a number like 65 into a character like 'A'. The whole file. The device polls a storage area for incoming files and display them. -- https://mail.python.org/mailman/listinfo/python-list
Re: Newbie looking for elegant solution
kai.pet...@gmail.com writes: I though that the bytes type is Python 3 only? If so, I cannot use it. In Python 2, the regular string type (str) is a byte vector, though it is immutable. Do you send one scan line at a time to the rendering device, or the whole file all at once, or what? Do you want to dump the output to a disk file and send that to the rendering device as a separate step? Anyway, use the chr function to turn a number like 65 into a character like 'A'. -- https://mail.python.org/mailman/listinfo/python-list
Re: Newbie looking for elegant solution
On Tuesday, 24 March 2015 20:14:06 UTC-7, otaksoft...@gmail.com wrote: I have a list containing 9600 integer elements - each integer is either 0 or 1. Starting at the front of the list, I need to combine 8 list elements into 1 by treating them as if they were bits of one byte with 1 and 0 denoting bit on/off (the 8th element would be the rightmost bit of the first byte). The end result should be a new list that is 8 x shorter than the original list containing integers between 0 and 255. Speed is not of utmost importance - an elegant solution is. Any suggestions? Thanks for all input, Kai I though that the bytes type is Python 3 only? If so, I cannot use it. Using PILLOW, I am generating images from text and these are then sent to a black white image rendering device which expects 8 one bit pixels as one byte (as a condensed format I guess). This device then turns bits into pixels again and displays the image that way. If that is clear enough for you to suggest a better way to achieve what I am after, I'd like to hear it. Kai -- https://mail.python.org/mailman/listinfo/python-list
Re: Newbie looking for elegant solution
kai.pet...@gmail.com writes: The whole file. The device polls a storage area for incoming files and display them. If the storage area is on disk and you don't care about speed, then it's enough to convert the bit stream and write it out a character at a time. Some other posters mentioned possible alternative PIL interfaces you could use, to the one that gives you a bit stream. The bit stream interface sounds like a bad choice, but it's the only choice available then go for it. -- https://mail.python.org/mailman/listinfo/python-list
Newbie looking for elegant solution
I have a list containing 9600 integer elements - each integer is either 0 or 1. Starting at the front of the list, I need to combine 8 list elements into 1 by treating them as if they were bits of one byte with 1 and 0 denoting bit on/off (the 8th element would be the rightmost bit of the first byte). The end result should be a new list that is 8 x shorter than the original list containing integers between 0 and 255. Speed is not of utmost importance - an elegant solution is. Any suggestions? Thanks for all input, Kai -- https://mail.python.org/mailman/listinfo/python-list
Re: Newbie looking for elegant solution
On Wed, Mar 25, 2015 at 2:13 PM, otaksoftspamt...@gmail.com wrote: I have a list containing 9600 integer elements - each integer is either 0 or 1. Starting at the front of the list, I need to combine 8 list elements into 1 by treating them as if they were bits of one byte with 1 and 0 denoting bit on/off (the 8th element would be the rightmost bit of the first byte). Speed is not of utmost importance - an elegant solution is. Any suggestions? Oooh fun! l = [1, 0, 1, 1, 0, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 1, 0, 1, 0, 1] list(int(''.join(str(i) for i in l),2).to_bytes(len(l)//8,'big')) [177, 105, 117] Convert it into a string, convert the string to an integer (interpreting it as binary), then convert the integer into a series of bytes, and interpret those bytes as a list of integers. Example works in Python 3. For Python 2, you'll need ord() to get the integers at the end. I'm not sure how elegant this is, but it's a fun trick to play with :) Next idea please! I love these kinds of threads. ChrisA -- https://mail.python.org/mailman/listinfo/python-list
Re: Newbie looking for elegant solution
On Tuesday, March 24, 2015 at 8:29:24 PM UTC-7, Chris Angelico wrote: On Wed, Mar 25, 2015 at 2:13 PM, nobody wrote: I have a list containing 9600 integer elements - each integer is either 0 or 1. Starting at the front of the list, I need to combine 8 list elements into 1 by treating them as if they were bits of one byte with 1 and 0 denoting bit on/off (the 8th element would be the rightmost bit of the first byte). Speed is not of utmost importance - an elegant solution is. Any suggestions? Oooh fun! l = [1, 0, 1, 1, 0, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 1, 0, 1, 0, 1] list(int(''.join(str(i) for i in l),2).to_bytes(len(l)//8,'big')) [177, 105, 117] Convert it into a string, convert the string to an integer (interpreting it as binary), then convert the integer into a series of bytes, and interpret those bytes as a list of integers. Example works in Python 3. For Python 2, you'll need ord() to get the integers at the end. I'm not sure how elegant this is, but it's a fun trick to play with :) Next idea please! I love these kinds of threads. ChrisA Impressive - thanks! -- https://mail.python.org/mailman/listinfo/python-list
Re: Newbie looking for elegant solution
otaksoftspamt...@gmail.com writes: I have a list containing 9600 integer elements - each integer is either 0 or 1. Is that a homework problem? This works for me in Python 2.7 but I think Python 3 gratuitously broke tuple unpacking so it won't work there: from itertools import count, groupby old = [0, 0, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 1, 1, 1, 0, 0, 0, 1, 1, 0, 1, 0, 1] new = [reduce(lambda x,(y,i):x*2+y, g, 0) for k,g in groupby(zip(old,count()), lambda (a,b): b//8)] print new [18, 222, 53] -- https://mail.python.org/mailman/listinfo/python-list
Re: Newbie looking for elegant solution
On Tuesday, 24 March 2015 21:04:37 UTC-7, Paul Rubin wrote: nobody writes: I have a list containing 9600 integer elements - each integer is either 0 or 1. Is that a homework problem? This works for me in Python 2.7 but I think Python 3 gratuitously broke tuple unpacking so it won't work there: from itertools import count, groupby old = [0, 0, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 1, 1, 1, 0, 0, 0, 1, 1, 0, 1, 0, 1] new = [reduce(lambda x,(y,i):x*2+y, g, 0) for k,g in groupby(zip(old,count()), lambda (a,b): b//8)] print new [18, 222, 53] no homework - real life. thanks for your contribution -- https://mail.python.org/mailman/listinfo/python-list
Re: Newbie looking for elegant solution
On Tuesday, 24 March 2015 21:20:11 UTC-7, Chris Angelico wrote: On Wed, Mar 25, 2015 at 3:04 PM, Paul Rubin nobody wrote: This works for me in Python 2.7 but I think Python 3 gratuitously broke tuple unpacking so it won't work there: from itertools import count, groupby old = [0, 0, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 1, 1, 1, 0, 0, 0, 1, 1, 0, 1, 0, 1] new = [reduce(lambda x,(y,i):x*2+y, g, 0) for k,g in groupby(zip(old,count()), lambda (a,b): b//8)] print new [18, 222, 53] You don't need tuple unpacking. Here's the Py3 version of the above: from functools import reduce new = [reduce(lambda x,y:x*2+y[0], g, 0) for k,g in groupby(zip(old,count()), lambda a: a[1]//8)] ChrisA Now I have just read the latest spec and speed/memory may become issues: 1 bit images of a size of 1024 x 1280 need to be processed this way, so 1310720 list elements. Also needs to be 2.7 only. Any recommendations? -- https://mail.python.org/mailman/listinfo/python-list
Re: Newbie looking for elegant solution
Chris Angelico ros...@gmail.com writes: Of course, this does mean installing numpy. It is crushing the nut with the triphammer - an absurd extravagance of energy, but the nut is effectively crushed all the same. It also has the advantage that it hopefully won't be acceptable for a homework assignment. Whether homework assignment or not, the original poster is well advised to try the problem themselves, and present their code for us to discuss. -- \ “Skepticism is the highest duty and blind faith the one | `\ unpardonable sin.” —Thomas Henry Huxley, _Essays on | _o__) Controversial Questions_, 1889 | Ben Finney -- https://mail.python.org/mailman/listinfo/python-list
Re: Newbie looking for elegant solution
On Wednesday 25 March 2015 14:13, otaksoftspamt...@gmail.com wrote: I have a list containing 9600 integer elements - each integer is either 0 or 1. Starting at the front of the list, I need to combine 8 list elements into 1 by treating them as if they were bits of one byte with 1 and 0 denoting bit on/off (the 8th element would be the rightmost bit of the first byte). The end result should be a new list that is 8 x shorter than the original list containing integers between 0 and 255. Speed is not of utmost importance - an elegant solution is. Any suggestions? Collate the list into groups of 8. Here, I pad the list with zeroes at the end. If you prefer to drop any excess bits instead of padding them, use itertools.izip instead of izip_longest. import itertools mylist = [1, 1, 1, 0, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, 0, 1] grouped = itertools.izip_longest(*([iter(mylist)]*8), fillvalue=0) Now convert each group of eight into a byte: def byte(bits): n = 0 for b in bits: assert b in (0, 1) n = n*2 + b return n [byte(x) for x in grouped] Or if you prefer using built-ins: [int(''.join(str(b) for b in x), 2) for x in grouped] I have no idea which will be faster. Exercise for the reader: izip will drop any bits that don't make up an octet. izip_longest will pad with zeroes on the least-significant side, e.g. [1, 1] - 192. How to pad on the most-significant side, or equivalently, don't pad at all, so that [1, 1] - 3? -- Steve -- https://mail.python.org/mailman/listinfo/python-list
Re: Newbie looking for elegant solution
kai.pet...@gmail.com writes: 1 bit images of a size of 1024 x 1280 need to be processed this way, so 1310720 list elements. Also needs to be 2.7 only. Where are these lists going to come from? Files? Process the file differently, probably. Use generators instead of lists, maybe. Or process one scan line at a time instead of the whole image. Or something. Basically your plan and your question seem kind of naive. If you can describe the ACTUAL application, you might be able to get some better answers. E.g. if it's image conversion, maybe there's an existing tool for the formats you want. How many of these images do you want to process? If just a few, who cares if it takes a little while? If a lot, think about writing a C program. -- https://mail.python.org/mailman/listinfo/python-list
Re: Newbie looking for elegant solution
On Wed, Mar 25, 2015 at 3:46 PM, kai.pet...@gmail.com wrote: Now I have just read the latest spec and speed/memory may become issues: 1 bit images of a size of 1024 x 1280 need to be processed this way, so 1310720 list elements. Also needs to be 2.7 only. Any recommendations? 2.7 only? Then my solution won't work (I just tried to port it, and integers don't have to_bytes). Paul's solution works. Here's an alternative: import numpy list(numpy.packbits(numpy.array(l),-1)) [177, 105, 117] Of course, this does mean installing numpy. It is crushing the nut with the triphammer - an absurd extravagance of energy, but the nut is effectively crushed all the same. ChrisA -- https://mail.python.org/mailman/listinfo/python-list
Re: Newbie looking for elegant solution
On Wed, Mar 25, 2015 at 3:04 PM, Paul Rubin no.email@nospam.invalid wrote: This works for me in Python 2.7 but I think Python 3 gratuitously broke tuple unpacking so it won't work there: from itertools import count, groupby old = [0, 0, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 1, 1, 1, 0, 0, 0, 1, 1, 0, 1, 0, 1] new = [reduce(lambda x,(y,i):x*2+y, g, 0) for k,g in groupby(zip(old,count()), lambda (a,b): b//8)] print new [18, 222, 53] You don't need tuple unpacking. Here's the Py3 version of the above: from functools import reduce new = [reduce(lambda x,y:x*2+y[0], g, 0) for k,g in groupby(zip(old,count()), lambda a: a[1]//8)] ChrisA -- https://mail.python.org/mailman/listinfo/python-list