How to convert ASCII integers back to char within a loop? - python

I'm trying to convert multiple ASCII ints back to char and have it as a single string. I know how to do it one by one but I can't think of how to do it in a loop. This is the code I have to grab all the ascii ints in my ascii_message variable:
for c in ascii_message:
ascii_int = ord(c)
Thanks!

An efficient way to do this in Python 2 is to load the list into a bytearray object & then convert that to a string. Like this:
ascii_message = [
83, 111, 109, 101, 32, 65, 83, 67,
73, 73, 32, 116, 101, 120, 116, 46,
]
a = bytearray(ascii_message)
s = str(a)
print s
output
Some ASCII text.
Here's a variation that works correctly in both Python 2 & 3.
a = bytearray(ascii_message)
s = a.decode('ASCII')
However, in Python 3, it'd be more usual to use an immutable bytes object rather than a mutable bytearray.
a = bytes(ascii_message)
s = a.decode('ASCII')
The reverse procedure can also be done efficiently with a bytearray in both Python 2 and 3.
s = 'Some ASCII text.'
a = list(bytearray(s.encode('ASCII')))
print(a)
output
[83, 111, 109, 101, 32, 65, 83, 67, 73, 73, 32, 116, 101, 120, 116, 46]
If your "list of numbers" is actually a string, you can convert it to a proper list of integers like this.
numbers = '48 98 49 48 49 49 48 48 48 49 48 49 48 49 48 48'
ascii_message = [int(u) for u in numbers.split()]
print(ascii_message)
a = bytearray(ascii_message)
s = a.decode('ASCII')
print(s)
output
[48, 98, 49, 48, 49, 49, 48, 48, 48, 49, 48, 49, 48, 49, 48, 48]
0b10110001010100
That looks the binary representation of a 14 bit number. So I guess there are further steps to solving this puzzle. Good luck!

Related

Accessing required number of indices in an array

I have an array like:
a=np.array([20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67
68 69 70 71 72 73 74 75 76 77 78 79])
requirement:
I would to like to access 10 indices in an array
the above array length is 60,60/10=6. So, i need every 6th indices in an array a.
required output:[0,6,12,18,24,30,36,42,48,64,60]
Numpy is powerful i would recommend to read the Documentation about indexing in numpy
everySixthEntry=a[np.arange(0,a.shape[0],6)]
You can generate the indexes for any array a with np.arange(len(a)). To access every 6th index use the a slice a[start:stop:step]. Jack posted one way, here a bit more detailed.
import numpy as np
# define your data. a = [20, ..., 79]
a = np.arange(60) + 20
# generate indexes for the array, index start at 0 till len(a)-1
indexes = np.arange(len(a))
# reduce the indexes to every 6th index
indexes = indexes[::6] # [start:stop:step]
print(indexes)
# -> array([ 0, 6, 12, 18, 24, 30, 36, 42, 48, 54])
# 60 isn't included as the array is only 59 long
The same result a bit different. You can also use np.arange steps.
# the same result a bit different
indexes = np.arange(0, len(a), 6) # (start,stop,step)
print(indexes)
# -> array([ 0, 6, 12, 18, 24, 30, 36, 42, 48, 54])
and in case you want to access the values of your original array
print(a[indexes])
# -> array([20, 26, 32, 38, 44, 50, 56, 62, 68, 74])
Basics of slicing
a[start:stop:step] is equivalent to a[slice(start, stop, step)]. If you don't want to specify any of start, stop, step set it to None. start and stop takes values from 0 to len(a)-1 and negative represents the position from the end of the array.
Some Slice Examples:
step = 20
a[slice(None, None, step)], a[slice(0, -1, step)], a[0: -1: step], a[::step]
# all -> array([20, 40, 60])
# the first 4 elements
step = 1
start = 0 # or None
end = 5
a[slice(start, end, step)], a[slice(start, end)] , a[start: end: step] , a[start:end]
# all -> array([20, 21, 22, 23])
# the last 4 elements
step = 1
start = -4
end = None # -1 will cute the last entry
a[slice(start, end, step)], a[slice(start, end)] , a[start: end: step] , a[start:end]
# all -> array([76, 77, 78, 79]
I think you meant to say:
The required index values are [0,6,12,18,24,30,36,42,48,64,60]
Corresponding output values are [20, 26, 32, 38, 44, 50, 56, 62, 68, 74]
The code below should give you the values for every 6th index.
a=np.array([20,21,22,23,24,25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43,
44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67,
68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,])
Out=[]
for i in range(10):
Out.append(a[6*i])
print(Out)
Output is :
[20, 26, 32, 38, 44, 50, 56, 62, 68, 74]
If the Index values are required: Do the following
Out1=[]
for i in range(0,11): #for only 10 indices (going from 0 to 10)
print(6*i)
Out1.append(6*i)
print("The required index values is : {}".format(Out1))
This gives an output :
0
6
12
18
24
30
36
42
48
54
60
The required index values is : [0, 6, 12, 18, 24, 30, 36, 42, 48, 54, 60]

Remove elements in a list if difference with previous element less than value

Given a list of numbers in ascending order. It is necessary to leave only elements to get such a list where the difference between the elements was greater or equal than a certain value (10 in my case).
Given:
list = [10,15,17,21,34,36,42,67,75,84,92,94,103,115]
Goal:
list=[10,21,34,67,84,94,115]
you could use a while loop and a variable to track the current index you are currently looking at. So starting at index 1, check if the number at this index minus the number in the previous index is less than 10. If it is then delete this index but keep the index counter the same so we look at the next num that is now in this index. If the difference is 10 or more increase the index to look at the next num. I have an additional print line in the loop you can remove this is just to show the comparing.
nums = [10, 15, 17, 21, 34, 36, 42, 67, 75, 84, 92, 94, 103, 115]
index = 1
while index < len(nums):
print(f"comparing {nums[index-1]} with {nums[index]} nums list {nums}")
if nums[index] - nums[index - 1] < 10:
del nums[index]
else:
index += 1
print(nums)
OUTPUT
comparing 10 with 15 nums list [10, 15, 17, 21, 34, 36, 42, 67, 75, 84, 92, 94, 103, 115]
comparing 10 with 17 nums list [10, 17, 21, 34, 36, 42, 67, 75, 84, 92, 94, 103, 115]
comparing 10 with 21 nums list [10, 21, 34, 36, 42, 67, 75, 84, 92, 94, 103, 115]
comparing 21 with 34 nums list [10, 21, 34, 36, 42, 67, 75, 84, 92, 94, 103, 115]
comparing 34 with 36 nums list [10, 21, 34, 36, 42, 67, 75, 84, 92, 94, 103, 115]
comparing 34 with 42 nums list [10, 21, 34, 42, 67, 75, 84, 92, 94, 103, 115]
comparing 34 with 67 nums list [10, 21, 34, 67, 75, 84, 92, 94, 103, 115]
comparing 67 with 75 nums list [10, 21, 34, 67, 75, 84, 92, 94, 103, 115]
comparing 67 with 84 nums list [10, 21, 34, 67, 84, 92, 94, 103, 115]
comparing 84 with 92 nums list [10, 21, 34, 67, 84, 92, 94, 103, 115]
comparing 84 with 94 nums list [10, 21, 34, 67, 84, 94, 103, 115]
comparing 94 with 103 nums list [10, 21, 34, 67, 84, 94, 103, 115]
comparing 94 with 115 nums list [10, 21, 34, 67, 84, 94, 115]
[10, 21, 34, 67, 84, 94, 115]
You could build up the list in a loop. Start with the first number in the list. Keep track of the last number chosen to be in the new list. Add an item to the new list only when it differs from the last number chosen by at least the target amount:
my_list = [10,15,17,21,34,36,42,67,75,84,92,94,103,115]
last_num = my_list[0]
new_list = [last_num]
for x in my_list[1:]:
if x - last_num >= 10:
new_list.append(x)
last_num = x
print(new_list) #prints [10, 21, 34, 67, 84, 94, 115]
This problem can be solved fairly simply by iterating over your initial set of values, and adding them to your new list only when your difference of x condition is met.
Additionally, by putting this functionality into a function, you can get easily swap out the values or the minimum distance.
values = [10,15,17,21,34,36,42,67,75,84,92,94,103,115]
def foo(elements, distance):
elements = sorted(elements) # sorting the user input
new_elements = [elements[0]] # make a new list for output
for element in elements[1:]: # Iterate over the remaining elements...
if element - new_elements[-1] >= distance:
# this is the condition you described above
new_elements.append(element)
return new_elements
print(foo(values, 10))
# >>> [10, 21, 34, 67, 84, 94, 115]
print(foo(values, 5))
# >>> [10, 15, 21, 34, 42, 67, 75, 84, 92, 103, 115]
A few other notes here...
I sorted the array before I processed it. You may not want to do that for your particular application, but it seemed to make sense, since your sample data was already sorted. In the case that you don't want to sort the data before you build the list, you can remove the sorted on the line that I commented above.
I named the function foo because I was lazy and didn't want to think about the name. I highly recommend that you give it a more descriptive name.

How I can sum numbers until max height? [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 4 years ago.
Improve this question
There is height list it's total 1743 cm. I have 6 cells I want to put this numbers in cells. Max height is 300 cm. I use for loop for it it will take numbers inside height list and plus them until get closer 300 cm
height=[67, 67, 55, 65, 65, 65, 61, 58, 40, 40, 58, 53, 59, 63, 51, 57, 43, 65, 45, 65, 61, 58, 47, 58, 65, 74, 64, 28, 61, 46, 39]
max_height=300 #cm
sum1=0
count=0
for i in height:
sum1=height[count]+sum1
count+=1
if max_height>=sum1>=250:
print(sum1)
sum1=0
print(sum1)
print("\n",sum(height))
I expected it will get 6 sum but get 7 sum.
if you run you will see (254,289,273,261,289,292,85)
It is not full solution but i hope it can help you, main idea is find most nearest value to generate summ 300
height = [67, 67, 55, 65, 65, 65, 61, 58, 40, 40, 58, 53, 59, 63, 51, 57, 43, 65, 45, 65, 61, 58, 47, 58, 65, 74, 64, 28, 61, 46, 39]
elems = [height.pop(0)]
groups = []
while height:
while sum(elems) <= 300:
next_el = 0
for elem in height:
if sum(elems) + elem <= 300 and elem > next_el:
next_el = elem
if next_el:
elems.append(height.pop(height.index(next_el)))
else:
print(sum(elems))
print(elems)
groups.append(elems)
elems = []
break
print('Total: ', sum([sum(x) for x in groups]))
my result is:
273
[67, 74, 67, 65]
300
[65, 65, 65, 65, 40]
300
[65, 64, 63, 61, 47]
297
[61, 61, 59, 58, 58]
281
[58, 58, 57, 55, 53]
292
[51, 46, 45, 43, 40, 39, 28]
Total: 1743
The problem you are trying to solve is computationally complex. It looks like a variant of the Knapsack problem. This is a greedy approach, but it is fairly fast. Because it's greedy it is possible that it may fail to find a solution if one exists.
eg. [120, 120, 100, 80, 65, 65] with max height of 300 has a minimal solution of [[120, 100, 80], [120, 65, 65]], but this algorithm fails to find it, and instead returns [[120, 120], [100, 80, 65], [65]]
height=[67, 67, 55, 65, 65, 65, 61, 58, 40, 40, 58, 53, 59, 63, 51, 57, 43, 65, 45,
65, 61, 58, 47, 58, 65, 74, 64, 28, 61, 46, 39]
max_height=300 #cm
heights = sorted(height, reverse=True)
groups = []
while heights:
# whilst there are still items in heights, create a new group of heights
# with sum no more than 300.
group = []
# greedily fill up each group with largest possible values that can fit
for h in heights:
if sum(group) + h <= 300:
group.append(h)
# remove the values in the group from the list of candidate heights
for g in group:
heights.remove(g)
groups.append(tuple(group))
# output
for g in groups:
print(g, '->', sum(g))
gives:
(74, 67, 67, 65) -> 273
(65, 65, 65, 65, 40) -> 300
(65, 64, 63, 61, 47) -> 300
(61, 61, 59, 58, 58) -> 297
(58, 58, 57, 55, 53) -> 281
(51, 46, 45, 43, 40, 39, 28) -> 292
Note that the first group it found is actually the worst in terms of how close to the limit it is. This goes back to the initial point about this algorithm being greedy and not always finding the solution with the minimum number of groups.
This is an algorithmic problem.
The gotcha here seems to be that if you fill up one cell at a time then your values that may not fit in the latest cell may still fit in a previous cell. So you are not taking full advantage of each cell's size, for example, your first cell contains just 254 which means you can fit a whole extra 46 cms in there (which appears later in your list).
To solve it you need to actually create a representation for the cells (a list and/or counter, although you can always create a sum of the list...), and revisit cells to check if more data fits.
you need to find the combinations that are 6 elements long, and then you want to get is as close to 300 as possible
height=[67, 67, 55, 65, 65, 65, 61, 58, 40, 40, 58, 53, 59, 63, 51, 57, 43, 65, 45, 65, 61, 58, 47, 58, 65, 74, 64, 28, 61, 46, 39]
valid_combs = []
import itertools
for comb in itertools.combinations(height, 6):
#if sum(comb) <= 300 and sum(comb) >+ 290:
if sum(comb) == 300:
valid_combs.append(comb)
print(comb)
this will extract valid 6 length combinations from the set, and then check if it sums to 300. the commented out condition above it is if you want to have it within a range, such as 290 to 300 etc
you can modify the condition as necessary, such as if sum(comb) >= 250
I may have misunderstood the problem initially. But reconsidering the input, your goal is to group the data such that the sum of an unspecified length does not exceed some threshold. Using numpy this may be a good place to start:
edit: this assumes the order of the data needs to preserved, otherwise I would use a quantile based approach.
edit2: without order preservation
import numpy as np
height = np.array(\
[67, 67, 55, 65, 65, 65, 61, 58, 40, 40,\
58, 53, 59, 63, 51, 57, 43, 65, 45, 65,\
61, 58, 47, 58, 65, 74, 64, 28, 61, 46, 39])
height.sort()
threshold = 300
groupings = np.where(np.diff(height.cumsum() // threshold))[0]
ends = np.hstack((groupings, height.size))
starts = np.roll(ends.copy(), 1) + 1
starts[0] = 0
for start, end in zip(starts, ends):
print(f'Grouping: {height[start:end]} sum: {height[start:end].sum()}')
Output:
Grouping: [28 39 40 40 43 45] sum: 235
Grouping: [47 51 53 55] sum: 206
Grouping: [58 58 58 58 59] sum: 291
Grouping: [61 61 63] sum: 185
Grouping: [65 65 65 65] sum: 260
Grouping: [65 67 67 74] sum: 273
My approach is to find and use combinations that fill cells with exactly 300 total height. It is not optimal.
import itertools
height=[67, 67, 55, 65, 65, 65, 61, 58, 40, 40, 58, 53, 59, 63, 51, 57, 43, 65, 45, 65, 61, 58, 47, 58, 65, 74, 64, 28, 61, 46, 39]
def fill_cell(cells, comb):
cells.append(comb) #fill cell
for h in comb:
del height[height.index(h)] #delete elemets from heights array
cells = []
When first required combination is found - I fill_cell and delete used elements from height array.
As we don't have number of items per cell restriction - I will vary this number.
In this case there is combination of 7 items with total height sum - 300:
for comb in itertools.combinations(height, 7):
if sum(comb) == 300:
print(comb) #(55, 40, 40, 53, 45, 28, 39)
fill_cell(cells,comb)
print(len(height)) #24
break
After that I found few more combinations of 5 item and with 300 total height.
for comb in itertools.combinations(height, 5):
if sum(comb) == 300:
print(comb) #(67, 67, 65, 58, 43)
fill_cell(cells,comb)
print(len(height)) #19
break
for comb in itertools.combinations(height, 5):
if sum(comb) == 300:
print(comb)
fill_cell(cells,comb) #(65, 65, 61, 58, 51)
print(len(height)) #14
break
for comb in itertools.combinations(height, 5):
if sum(comb) == 300:
print(comb)
fill_cell(cells,comb) #(59, 63, 57, 47, 74)
print(len(height)) # 9
break
At this point I have 4 cells with directly 300 total height.
I didn't find more combinations with directly 300 total height.
I decided to manually define remaining cells:
print(cells)
print(height)
fill_cell(cells,height[:4])
fill_cell(cells,height[:])
print("Result:")
for c in cells:
print(sum(c), c)
print("Total height: ", sum([sum(c) for c in cells]))
Finally:
Result:
300 (55, 40, 40, 53, 45, 28, 39)
300 (67, 67, 65, 58, 43)
300 (65, 65, 61, 58, 51)
300 (59, 63, 57, 47, 74)
249 [65, 65, 61, 58]
294 [58, 65, 64, 61, 46]
Total height: 1743
Update:
Following code do the same. It iteratively changes combination parameters and reduces height limit if combination with 300 height didn't found:
import itertools
height=[67, 67, 55, 65, 65, 65, 61, 58, 40, 40, 58, 53, 59, 63, 51, 57, 43, 65, 45, 65, 61, 58, 47, 58, 65, 74, 64, 28, 61, 46, 39]
def fill_cell(cells, comb):
cells.append(comb) #fill cell
for h in comb:
del height[height.index(h)] #delete elemets from heights array
cells = []
max_height = 300
max_elements = 7
elements = max_elements
cell_filled = True
while height:
if cell_filled == False:
elements-=1
if elements==0:
elements = max_elements
max_height-=1
for comb in itertools.combinations(height, min(elements,len(height))):
if sum(comb) == max_height:
print(comb)
fill_cell(cells, comb)
print(len(height))
cell_filled = True
break
cell_filled = False
print("Result:")
for c in cells:
print(sum(c), c)
print("Total height: ", sum([sum(c) for c in cells]))

Save numpy array as binary to read from FORTRAN

I have a series of numpy array, i need to save these numpy array in a loop as a raw binary float32 (without any header information) which need to be read from FORTRAN.
import numpy as np
f=open('test.bin','wb+')
for i in range(0,10):
np_data=np.random.rand(10,5)
fortran_data=np.asfortranarray(np_data,'float32')
fortran_data.tofile(f)
f.close()
Is this the correct way so that I can read this binary file created in python from FORTRAN correctly. Your suggestions will be highly apprecitaed
The code you wrote is almost right, but the .tofile method always write the vector in C order. I don't know why the np.asfortranarray() avoids this when writing in the binary file, but I tested and unfortunately we need to transpose the matrix before writing to correct read in Fortran without any other concern (this means in Fortran you can give the actual matrix dimension without needing any transpose).
The code below is to illustrate with a 3D matrix (which I ussually need to use) what I am saying:
a = np.arange(1,10*3*4+1)
b = a.reshape(10,12,order='F')
array([[ 1, 11, 21, 31, 41, 51, 61, 71, 81, 91, 101, 111],
[ 2, 12, 22, 32, 42, 52, 62, 72, 82, 92, 102, 112],
[ 3, 13, 23, 33, 43, 53, 63, 73, 83, 93, 103, 113],
[ 4, 14, 24, 34, 44, 54, 64, 74, 84, 94, 104, 114],
[ 5, 15, 25, 35, 45, 55, 65, 75, 85, 95, 105, 115],
[ 6, 16, 26, 36, 46, 56, 66, 76, 86, 96, 106, 116],
[ 7, 17, 27, 37, 47, 57, 67, 77, 87, 97, 107, 117],
[ 8, 18, 28, 38, 48, 58, 68, 78, 88, 98, 108, 118],
[ 9, 19, 29, 39, 49, 59, 69, 79, 89, 99, 109, 119],
[ 10, 20, 30, 40, 50, 60, 70, 80, 90, 100, 110, 120]])
b is already in Fortran order
c=b.reshape(10,3,4, order='F')
print(c[:,:,0])
[[ 1 11 21]
[ 2 12 22]
[ 3 13 23]
[ 4 14 24]
[ 5 15 25]
[ 6 16 26]
[ 7 17 27]
[ 8 18 28]
[ 9 19 29]
[10 20 30]]
Then I save the matrix c in a binary file:
c.T.tofile('test_c.bin')
So, using this Fortran code I am able to read the binary data in the correct order I created the c matrix in Python:
PROGRAM read_saved_python
IMPLICIT NONE
INTEGER(KIND=8),ALLOCATABLE :: matrix(:,:,:)
INTEGER :: Nx, Ny, Nz
Nx = 10
Ny = 3
Nz = 4
ALLOCATE(matrix(Nx, Ny, Nz))
OPEN(33, FILE="/home/victor/test_c.bin",&
FORM="UNFORMATTED", STATUS="UNKNOWN", ACTION="READ", ACCESS='STREAM')
READ(33) matrix
write(*,*) matrix(:,1,1)
CLOSE(33)
DEALLOCATE(matrix)
END PROGRAM read_saved_python
Notice in Fortran the indexes start in 1 and the print shows in column order (in this case: print the first column, the second and then the third). If you don't transpose the matrix here c.T.tofile('test_c.bin') when reading in Fortran you'll notice that the matrix is not as you wanted, even if you use function np.asfortranarray as you did ( I even tried np.asfortranarray(c).T.tofile('/home/victor/teste_d.bin') (just to make sure) but the matrix is written in c order in the binary file.
You will need the meta data of the array to read it in FORTRAN. This website (https://scipy.github.io/old-wiki/pages/Cookbook/InputOutput.html) has some information on using libnpy to write and an example code fex.f95 to read the binary file.

Read contents of a text file into a dictionary

The contents of my text file are as follows:
a 0 45 124 234 53 12 34
a 90 294 32 545 190 87
a 180 89 63 84 73 63 83
How can I read the contents into a dictionary such that a0 becomes the key and the rest of them as values. I would want my dictionary to look like this:
{a0: [45, 124, 234, 53, 12, 34], a90: [294, 32, 545, 190, 87], a180: [89, 63, 84, 73, 63, 83]}
I have tried the conventional approach where I remove the delimiter and then
store it in the dictionary as shown below
newt = {}
newt = {t[0]: t[1:] for t in data}
But here I get only a as the key
This may help you out (it's about Christmas time after all)
d = {}
with open("dd.txt") as f:
for line in f:
els = line.split()
k = ''.join(els[:2])
d[k] = list(map(int,els[2:]))
print(d)
with an input file of
a 0 45 124 234 53 12 34
a 90 294 32 545 190 87
a 180 89 63 84 73 63 83
it produces
{'a90': [294, 32, 545, 190, 87],
'a180': [89, 63, 84, 73, 63, 83],
'a0': [45, 124, 234, 53, 12, 34]}
It essentially reads each line from the file, it then splits it into chunks ignoring whitespace.
It then uses the first two elements to compose the key and the rest to compose a list, converting each element into an integer.
I have assumed you want the numbers as integers. If you want them as strings you can ignore the conversion to int
d[k] = els[2:]
If you like one-liners (kind-of):
with open('my_file.txt') as f:
res = {''.join(r.split(None, 2)[:2]): [int(x) for x in r.split()[2:]] for r in f}
>>> res
{'a0': [45, 124, 234, 53, 12, 34],
'a180': [89, 63, 84, 73, 63, 83],
'a90': [294, 32, 545, 190, 87]}

Categories