Python list to tuple - python

I have this :
(([75, 0], [100, 0], [100, 370]), ([75, 0], [100, 370], [75, 370]))
that come from this :
[(array([75, 0]), array([100, 0]), array([100, 370])), (array([75, 0]), array([100, 370]), array([ 75, 370]))]
and I want to have :
[(x1, y1, x2 , y2 ,x3 ,y3), (x1, y1, x2 , y2 ,x3 ,y3), ...]
or
[(75, 0, 100, 0, 100, 370), (75, 0, 100, 0, 100, 370),.....]
Thanks for the help!

You can use itertools.chain:
import itertools
s = (([75, 0], [100, 0], [100, 370]), ([75, 0], [100, 370], [75, 370]))
final_s = [list(itertools.chain.from_iterable(i)) for i in s]
Output:
[[75, 0, 100, 0, 100, 370], [75, 0, 100, 370, 75, 370]]
or using reduce in Python2:
s = (([75, 0], [100, 0], [100, 370]), ([75, 0], [100, 370], [75, 370]))
new_s = [reduce(lambda x, y:list(x)+list(y), i) for i in s]
Output:
[[75, 0, 100, 0, 100, 370], [75, 0, 100, 370, 75, 370]]

You could use a list comprehension:
>>> t = (([75, 0], [100, 0], [100, 370]), ([75, 0], [100, 370], [75, 370]))
>>> [tuple(sub for el in l for sub in el) for l in t]
[(75, 0, 100, 0, 100, 370), (75, 0, 100, 370, 75, 370)]

Starting with this example:
from operator import add
from functools import reduce
reduce(add, (x for x in [[1, 2], [3, 4]]))
Outputs:
[1, 2, 3, 4]
Now just do this for each element in the tuple:
[tuple(reduce(add, x)) for x in data]
Outputs:
[(75, 0, 100, 0, 100, 370), (75, 0, 100, 370, 75, 370)]

Easy to understand version:
original = (([75, 0], [100, 0], [100, 370]), ([75, 0], [100, 370], [75, 370]))
final = []
for each_tuple in original:
final_child_list = []
for each_list in each_tuple:
final_child_list.extend(each_list)
final.append(final_child_list)
You'll get:
>>> final
[[75, 0, 100, 0, 100, 370], [75, 0, 100, 370, 75, 370]]
# if you prefer the inside element to be tuples
>>> [tuple(x) for x in final]
[(75, 0, 100, 0, 100, 370), (75, 0, 100, 370, 75, 370)]
There might be shorter versions using list comprehension, but less readability.

Related

Convert Bytes into BufferedReader object in Python?

The title of this question is the same as this one, and I have voted to reopoen the question.
I want to convert a byte object into a BufferedReader one, and here is my attempts(after referring to many articles):
import numpy as np
from PIL import Image as PILImage
from io import BytesIO
img_np = np.asarray([[[16, 16, 16], [2, 2, 2], [0, 0, 0], [6, 6, 6], [8, 8, 8], [0, 0, 0], [21, 21, 21], [3, 3, 3], [0, 0, 0], [62, 62, 62]], [[0, 0, 0], [71, 71, 71], [142, 142, 142], [107, 107, 107], [99, 99, 99], [101, 101, 101], [4, 4, 4], [86, 86, 86], [99, 99, 99], [146, 146, 146]], [[162, 162, 162], [203, 203, 203], [192, 192, 192], [228, 228, 228], [191, 191, 191], [178, 178, 178], [222, 222, 222], [200, 200, 200], [198, 198, 198], [182, 182, 182]], [[117, 117, 117], [178, 178, 178], [199, 199, 199], [214, 214, 214], [222, 222, 222], [208, 208, 208], [255, 255, 255], [251, 251, 251], [219, 219, 219], [255, 255, 255]], [[0, 0, 0], [0, 0, 0], [80, 80, 80], [169, 169, 169], [193, 193, 193], [238, 238, 238], [239, 239, 239], [243, 243, 243], [254, 254, 254], [230, 230, 230]], [[20, 20, 20], [20, 20, 20], [9, 9, 9], [1, 1, 1], [130, 130, 130], [194, 194, 194], [216, 216, 216], [255, 255, 255], [252, 252, 252], [255, 255, 255]], [[9, 9, 9], [0, 0, 0], [0, 0, 0], [0, 0, 0], [3, 3, 3], [44, 44, 44], [191, 191, 191], [217, 217, 217], [248, 248, 248], [225, 225, 225]], [[0, 0, 0], [11, 11, 11], [3, 3, 3], [11, 11, 11], [6, 6, 6], [15, 15, 15], [0, 0, 0], [153, 153, 153], [255, 255, 255], [253, 253, 253]], [[0, 0, 0], [5, 5, 5], [1, 1, 1], [4, 4, 4], [8, 8, 8], [4, 4, 4], [3, 3, 3], [0, 0, 0], [159, 159, 159], [241, 241, 241]], [[10, 10, 10], [9, 9, 9], [6, 6, 6], [2, 2, 2], [0, 0, 0], [0, 0, 0], [3, 3, 3], [20, 20, 20], [0, 0, 0], [185, 185, 185]]])
im = PILImage.fromarray(img_np.astype(np.uint8))
# im.save('./temp.jpeg', "JPEG")
# f = open('./temp.jpeg', 'rb')
# print(type(f))
#
b_handle = io.BytesIO()
im.save(b_handle, format="JPEG")
# b = im.tobytes()
print(type(b_handle))
b = b_handle.read()
print(type(b))
print(b)
im.save(b_handle, format="JPEG")
b_br = io.BufferedReader(b_handle)
print(type(b_br))
b = b_br.read()
print(type(b))
print(b)
The output is as below:
<class '_io.BytesIO'>
<class 'bytes'>
b''
<class '_io.BufferedReader'>
<class 'bytes'>
b''
It seems that the file like objects are empty. I know that for the b_handle I can get the value by b_handle.getvalue() but for the bufferedreader it doesn't work as a file object.
How can I convert a byte string into a bufferedreader object, the same as I open a file?
You are almost there. Once you save the image bytes into the buffer you need to seek(Change stream position) to byte offset 0 prior to the read call.
b_handle = io.BytesIO()
im.save(b_handle, format="JPEG")
b_handle.seek(0)
b_handle.name = "temp.jpeg"
b_br = io.BufferedReader(b_handle)
b = b_br.read()
Example,
>>> from io import BytesIO, BufferedReader
>>>
>>> b_handle = BytesIO()
>>> b_handle.write(b"Hello World")
11
>>> b_handle.seek(0) # This is important.
0
>>> br = BufferedReader(b_handle)
>>> br
<_io.BufferedReader>
>>> br.read()
b'Hello World'

Change Array starting at spefic index

my lists look something like this:
A_List= [0,1,2,3,4,5,6,7,8]
B_List=[0,10,20,30,40,50,60,70,80]
C_List=[0,100,200,300,400,500,600,700,800]
D_List = ...
And so on.
Each value is type np.float64.
The values here are random, I only wanted to show that they are all the same length.
I now tried to write a loop that changes these lists starting at a specific index in that way, that all numbers including and above index 4 are subtracted by the value written in index 4.
i=4
while i <= len(A_List):
A_List[i] = A_List[i]+A_List[4]
B_List[i] = B_List[i]+B_List[4]
C_List[i] = C_List[i]+C_List[4]
D_List[i] = D_List[i]+D_List[4]
...
i=i+1
Which just won't work. Error: can only concatenate str (not "numpy.float64") to str). I don't quite understand that, because I thought I'm substituting a float value with another float value.
Why don't you simply use numpy and not lists?
First create a 2D array:
A_List= [0,1,2,3,4,5,6,7,8]
B_List=[0,10,20,30,40,50,60,70,80]
C_List=[0,100,200,300,400,500,600,700,800]
a = np.c_[A_List, B_List, C_List]
array([[ 0, 0, 0],
[ 1, 10, 100],
[ 2, 20, 200],
[ 3, 30, 300],
[ 4, 40, 400],
[ 5, 50, 500],
[ 6, 60, 600],
[ 7, 70, 700],
[ 8, 80, 800]])
Then perform your subtraction:
>>> a-a[4]
array([[ -4, -40, -400],
[ -3, -30, -300],
[ -2, -20, -200],
[ -1, -10, -100],
[ 0, 0, 0],
[ 1, 10, 100],
[ 2, 20, 200],
[ 3, 30, 300],
[ 4, 40, 400]])
If you want to apply your transform only on rows ≥ 4:
mask = np.tile((np.arange(len(a))>=4), (a.shape[1], 1)).T
np.where(mask, a-a[4], a)
output:
array([[ 0, 0, 0],
[ 1, 10, 100],
[ 2, 20, 200],
[ 3, 30, 300],
[ 0, 0, 0],
[ 1, 10, 100],
[ 2, 20, 200],
[ 3, 30, 300],
[ 4, 40, 400]])

Compare element 0 of two lists of lists; make new list of lists with items in z[0] that are not in x

If i[0] of each list in z is not in x, put that z list in g and if it's already in x, put x in g.
x = [[68, 40000], [69, 40800.0], [70, 41616.0]]
z = [[62, 0], [63, 0], [64, 0], [65, 0], [66, 0], [67, 0], [68, 0], [69, 0], [70, 0]]
I want the result to be:
g = [[62, 0], [63, 0], [64, 0], [65, 0], [66, 0], [67,0], [68, 40000], [69, 40800], [70, 41616]]
I tried various combinations of:
g = [z for x, x in zip(z, x) if z[0] not in x]
but it does not work
x = [[68, 40000], [69, 40800.0], [70, 41616.0]]
z = [[62, 0], [63, 0], [64, 0], [65, 0], [66, 0], [67, 0], [68, 0], [69, 0], [70, 0]]
dct_x = {v[0]: v for v in x}
g = [dct_x.get(v[0], v) for v in z]
print(g)
Prints:
[[62, 0], [63, 0], [64, 0], [65, 0], [66, 0], [67, 0], [68, 40000], [69, 40800.0], [70, 41616.0]]

Reduce image dimension with mapping

I have a .png image with four colors in it. If I convert the image to a numpy array I get an array with the following dimensions: [length X height X 3], with length == height.
How can I reduce the dimension with mapping the colors?
This is the current structure:
array([[[ 0, 65, 101],
[ 0, 65, 101],
[ 0, 65, 101],
...,
[ 0, 65, 101],
[ 0, 65, 101],
[ 0, 65, 101]],
[[ 0, 65, 101],
[163, 219, 232],
[163, 219, 232],
...,
[ 0, 65, 101],
[163, 219, 232],
[ 0, 65, 101]],
[[ 0, 65, 101],
[163, 219, 232],
[ 0, 65, 101],
...,
[ 0, 65, 101],
[163, 219, 232],
[ 0, 65, 101]],
...,
[[ 0, 65, 101],
[163, 219, 232],
[ 0, 65, 101],
...,
[ 0, 65, 101],
[ 0, 65, 101],
[ 0, 65, 101]],
[[ 0, 65, 101],
[163, 219, 232],
[163, 219, 232],
...,
[163, 219, 232],
[163, 219, 232],
[ 0, 65, 101]],
[[ 0, 65, 101],
[ 0, 65, 101],
[ 0, 65, 101],
...,
[ 0, 65, 101],
[ 0, 65, 101],
[ 0, 65, 101]]], dtype=uint8)
And I would like an array with two dimensions, and every value in the i'th row and j'th column would correspond to the color it had in the third dimension. So if the original image had 7 X 7 X 3 dimension with four colors, the output would be something like this:
array([[0, 1, 1, 3, 3, 3, 0],
[0, 2, 1, 1, 1, 1, 0],
[0, 2, 0, 1, 2, 1, 0],
[0, 3, 1, 1, 3, 1, 0],
[0, 1, 0, 0, 3, 0, 0],
[0, 1, 1, 1, 1, 1, 0],
[0, 0, 0, 0, 0, 0, 0]])
The values in the forementioned arrays are all made up, so they don't correspond to each other, I have just tried to represent the concept.
I read the picture as:
from PIL import Image
import numpy as np
img = Image.open('image.png')
imgarray = np.asarray(img)
print(imgarray)
You can use numpy.unique for this. For example, here's a 3x5 image that has just three colors:
In [105]: img
Out[105]:
array([[[10, 20, 30],
[ 5, 5, 0],
[ 5, 5, 0],
[ 5, 5, 0],
[ 0, 0, 0]],
[[ 5, 5, 0],
[ 5, 5, 0],
[ 0, 0, 0],
[ 0, 0, 0],
[ 0, 0, 0]],
[[10, 20, 30],
[10, 20, 30],
[10, 20, 30],
[10, 20, 30],
[ 5, 5, 0]]])
Call numpy.unique on the reshaped image. The first two dimensions are flattened into a single dimension, and then axis=0 is used so we get the unique colors. inv will holds the array of "inverses", i.e. the indices into colors of the original values.
In [106]: colors, inv = np.unique(img.reshape(-1, 3), axis=0, return_inverse=True)
In [107]: colors
Out[107]:
array([[ 0, 0, 0],
[ 5, 5, 0],
[10, 20, 30]])
In [108]: inv
Out[108]: array([2, 1, 1, 1, 0, 1, 1, 0, 0, 0, 2, 2, 2, 2, 1])
Reshape inv to get the array of indices into colors with the same shape as the original image:
In [109]: inv.reshape(img.shape[:2])
Out[109]:
array([[2, 1, 1, 1, 0],
[1, 1, 0, 0, 0],
[2, 2, 2, 2, 1]])

Sorting by value in a dictionary if the value is a list

I know that dictionaries aren't sortable, that being said, I want the representation of the dictionary that is sorted upon that value which is a list. Example:
some_dict= {
"a": [0, 0, 0, 0, 0],
"b": [1400, 50, 30, 18, 0],
"c": [800, 30, 14, 14, 0],
"d": [5000, 100, 30, 50, .1],
"for fun": [140000, 1400, 140, 140, .42]
}
I want to sort by the first item in the list of each.
I tried something like:
sorted(some_dict.items(), key = lambda for x in some_dict: some_dict[x][0])
but I get invalid syntax.
Thanks in advance.
You're on the right track, but you can't put a for-loop in a lambda (hence the error):
>>> sorted(some_dict.items(), key=lambda x: x[1][0])
[('a', [0, 0, 0, 0, 0]), ('c', [800, 30, 14, 14, 0]), ('b', [1400, 50, 30, 18, 0]), ('d', [5000, 100, 30, 50, 0.1]), ('for fun', [140000, 1400, 140, 140, 0.42])]
If you want to keep this order in a dictionary, you can use collections.OrderedDict:
>>> from collections import OrderedDict
>>> mydict = OrderedDict(sorted(some_dict.items(), key=lambda x: x[1][0]))
>>> print(mydict)
OrderedDict([('a', [0, 0, 0, 0, 0]), ('c', [800, 30, 14, 14, 0]), ('b', [1400, 50, 30, 18, 0]), ('d', [5000, 100, 30, 50, 0.1]), ('for fun', [140000, 1400, 140, 140, 0.42])])
>>> print(mydict['a'])
[0, 0, 0, 0, 0]
lambdas are anonymous functions, but they can only execute expressions in Python:
lambda pair: pair[1][0]
You could also write it verbosely:
def sorting_func(pair):
key, value = pair
return value[0]
sorted(some_dict.items(), key=sorting_func)

Categories