Related
This question already has answers here:
How can I use `return` to get back multiple values from a loop? Can I put them in a list?
(2 answers)
Apply function to each element of a list
(4 answers)
Closed 6 months ago.
I'm trying to output the entire contents of multiple .pkt files, containing binary data, as a series of hexadecimal lists: (Adapted from How to open every file in a folder)
import glob
path = 'filepath'
for filename in glob.glob(os.path.join(path, '*.pkt')):
with open(os.path.join(os.getcwd(), filename), 'rb') as f:
pair_hex = ["{:02x}".format(c) for c in f.read()]
print(pair_hex)
Which outputs:
['09', '04', '04', '04', '04', '04', '04', '04', '04', '0b', '09']
['09', '04', 'bb']
['09', 'bb']
['bb']
['09', '04', '0b', '09']
That makes sense, because i'm looping through the files, but what I need is:
[['09', '04', '04', '04', '04', '04', '04', '04', '04', '0b', '09'],['09', '04', 'bb'],['09', 'bb'],['bb'],['09', '04', '0b', '09']]
So I can manipulate all the data.
I have tried to apply append(), "".join(), map() as well as the advice at How to merge multiple lists into one list in python?, but nothing changes the output. How can I get the desired list of lists?
untested but try
import glob, os
path = 'filepath'
ret = []
for filename in glob.glob(os.path.join(path, '*.pkt')):
with open(os.path.join(os.getcwd(), filename), 'rb') as f:
pair_hex = ["{:02x}".format(c) for c in f.read()]
ret.append(pair_hex)
print(ret)
the above prints the following on my console which is the same as your "desired output"
[['09', '04', '04', '04', '04', '04', '04', '04', '04', '0b', '09'], ['09', '04', 'bb'], ['09', 'bb'], ['bb'], ['09', '04', '0b', '09']]
and this is what I used to create the .pkt files on my machine with out set to a copy--paste of your "desired output"
out = [['09', '04', '04', '04', '04', '04', '04', '04', '04', '0b', '09'],['09', '04', 'bb'],['09', 'bb'],['bb'],['09', '04', '0b', '09']]
for i, a in enumerate(out):
with open(f"{i}.pkt", 'w') as f:
f.write(''.join(map(lambda s: chr(int(s, 16)), a)))
I would like to take a list input (could have a variety of lengths) and create new lists joining each potential consecutive pair.
For example:
mylist = ['07', '05', '66', '06755', '04']
Would return as follows:
['0705', '66', '06755', '04']
['07', '0566', '06755', '04']
['07', '05', '6606755', '04']
['07', '05', '66', '0675504']
I've written the code below, but I was hoping there could be a better approach, as I'm worried that the slicing could run into problems.
def joinConsecutive(nums):
parts = len(nums)
newNums = []
# Join 1st and 2nd parts
merge1 = [''.join(nums[0:2])] + nums[2:]
newNums.append(merge1)
# Join 2nd and 3rd parts, etc.
i = 1
while i <= parts - 2:
start = nums[0:i]
mid = [''.join(nums[i:i+2])]
# When joining 2nd-to-last and last parts, this end just gets ignored
end = nums[i+2:]
newNums.append(start + mid + end)
i += 1
return newNums
joinConsecutive(mylist)
[['0705', '66', '06755', '04'],
['07', '0566', '06755', '04'],
['07', '05', '6606755', '04'],
['07', '05', '66', '0675504']]
Use some index math and a nested list comprehension:
>>> [mylist[:i] + [mylist[i]+mylist[i+1]] + mylist[i+2:] for i in range(len(mylist)-1)]
[['0705', '66', '06755', '04'], ['07', '0566', '06755', '04'], ['07', '05', '6606755', '04'], ['07', '05', '66', '0675504']]
Don't worry about "slicing problems" as Python will automatically take care of out-of-range slice indices for you (by returning an empty list).
I think your approach is fine (slicing never raises an IndexError, it returns empty lists instead).
You could however improve readability by using try/except and enumerate:
def join_consecutive_values(mylist):
result = []
for i, value in enumerate(mylist):
try:
merged_value = value + mylist[i+1]
except IndexError: # we're done!
break
new_list = mylist[:i] + [merged_value] + mylist[i+2:]
result.append(new_list)
return result
def joinConsecutive(mylist):
output=[]
for i,val in enumerate(mylist[:-1]):
newlist=mylist.copy()
newlist[i]=val+newlist.pop(i+1)
output.append(newlist)
return(output)
joinConsecutive(mylist)
[['0705', '66', '06755', '04'],
['07', '0566', '06755', '04'],
['07', '05', '6606755', '04'],
['07', '05', '66', '0675504']]
Try this:
def joinConsecutive(nums):
newNums = []
for i in range(len(nums) - 1):
tmp = nums.copy()
tmp[i] = tmp[i] + tmp[i + 1]
tmp.pop(i + 1)
newNums.append(tmp)
return newNums
Want a function / statement, to check whether all the values of mylist are sequential or not, which is hexadecimal list.
For example:
def checkmylist(mylist):
#code returns True or False
mylist1 = ['03', '04', '05', '06', '07', '08', '09', '0a', '0b', '0c','0d', '0e', '0f']
mylist2 = ['03', '05', '06', '07', '08', '09', '0a', '0b', '0c','0d', '0e', '0f']
checkmylist(mylist1)
#expected to returns pass
checkmylist(mylist2)
#expected to returns fail
def checkmylist(mylist):
it = (int(x, 16) for x in mylist)
first = next(it)
return all(a == b for a, b in enumerate(it, first + 1))
With the first statement we convert the hex numbers to a generator of integers. With next(it) we take the first element of the generator. Then we enumerate the rest of the elements starting the numbering from first + 1. We conclude that we have a sequential list if the numbering of each element is the same as the element itself.
One hack to do it is. This finds the total elements in the list. As you mention that it has t be sequential, the last element must be length of the list more than the first element.
>>> def checkmylist(l):
... a = [int(i,16) for i in sorted(set(l))]
... return (len(a) == (a[-1]-a[0]+1))
...
>>> checkmylist(mylist1)
True
>>> checkmylist(mylist2)
False
>>> checkmylist(['2', '2', '4'])
False
You can use iter to create an iterator of your list (from second index to end) and then use all function to check if you have a sequence, note that int(next(it),16) (or as a more efficient way as mentioned in comment use functools.partial(int, base=16))will convert your string to integer with base 16 then you can do operation on them :
>>> import functools
>>> int16 = functools.partial(int, base=16)
>>> def checker(li):
... it=iter(li[1:])
... return all(int16(next(it))-int16(i)==1 for i in li[:-1])
Demo:
mylist1 = ['03', '04', '05', '06', '07', '08', '09', '0a', '0b', '0c','0d', '0e', '0f']
mylist2 = ['03', '05', '06', '07', '08', '09', '0a', '0b', '0c','0d', '0e', '0f']
>>> checker(mylist1)
True
>>> checker(mylist2)
False
mylist1 = ['03', '04', '05', '06', '07', '08', '09', '0a', '0b', '0c','0d', '0e', '0f']
mylist2 = ['03', '05', '06', '07', '08', '09', '0a', '0b', '0c','0d', '0e', '0f']
def checkmylist(li):
start=int(li[0],16)
for e in li[1:]:
a=int(e,16)
if a==start+1:
start=a
else:
return False
return True
assert checkmylist(mylist1)==True
#expected to returns pass
assert checkmylist(mylist2)==False
#expected to returns fail
Similar to #JuniorCompressor but using a list comprehension,
your base construct would be:
bool_match_to_myList = [1 if int(i, 16) else 0 for i in mylist]
You could check to see if that is true/false easy enough:
myList_is_sequential = sum([1 if int(i, 16) else 0 for i in mylist]) < 1
Or you can find the indexes where it is off (not sequential) with the help of numpy
import numpy as np
bool_match_to_myList_np = np.array([1 if int(i, 16) else 0 for i in mylist])
np.where(bool_match_to_myList == 0)[0]
Another option, using the "power" of Pandas:
def is_sequential(mylist):
serie = pd.Series(mylist).apply(lambda x: int(x,16))
return (serie.diff() > 1).sum() == 0
Transform the mylist variables in a int Series
Use the diff() function, to get the difference between the last and the current value
Sum all values more than 1 (the step that we wanted), so if the sum() is equal 0, all values are sequential
is_sequential(mylist1) # returns True
is_sequential(mylist2) # returns False
I just want to change a list (that I make using range(r)) to a list of strings, but if the length of the string is 1, tack a 0 on the front.
I know how to turn the list into strings using
ranger= map(str,range(r))
but I want to be able to also change the length of those strings.
Input:
r = 12
ranger = range(r)
ranger = magic_function(ranger)
Output:
print ranger
>>> ['00','01','02','03','04','05','06','07','08','09','10','11']
And if possible, my final goal is this:
I have a matrix of the form
numpy.array([[1,2,3],[4,5,6],[7,8,9]])
and I want to make a set of strings such that the first 2 characters are the row, the second two are the column and the third two are '01', and have matrix[row,col] of each one of these.
so the above values would look like such:
000001 since matrix[0,0] = 1
000101 since matrix[0,1] = 2
000101 since matrix[0,1] = 2
000201
000201
000201
etc
Use string formatting and list comprehension:
>>> lst = range(11)
>>> ["{:02d}".format(x) for x in lst]
['00', '01', '02', '03', '04', '05', '06', '07', '08', '09', '10']
or format:
>>> [format(x, '02d') for x in lst]
['00', '01', '02', '03', '04', '05', '06', '07', '08', '09', '10']
zfill does exactly what you want and doesn't require you to understand an arcane mini-language as with the various types of string formatting. There's a place for that, but this is a simple job with a ready-made built-in tool.
ranger = [str(x).zfill(2) for x in range(r)]
Here's my take on it:
>>> map('{:02}'.format, xrange(12))
['00', '01', '02', '03', '04', '05', '06', '07', '08', '09', '10', '11']
For your own enlightenment, try reading about the format string syntax.
Use string formatting:
>>> sr = []
>>> for r in range(11):
... sr.append('%02i' % r)
...
>>> sr
['00', '01', '02', '03', '04', '05', '06', '07', '08', '09', '10']
One liner in Python 3.x
>>> ranger = [f'{i:>02}' for i in range(1, 12)]
>>> print (ranger)
['01', '02', '03', '04', '05', '06', '07', '08', '09', '10', '11']
I need to generate a list of numbers in a specific format. The format is
mylist = [00,01,02,03,04,05,06,07,08,09,10,11,12,13,14,15]
#Numbers between 0-9 are preceded by a zero.
I know how to generate a normal list of numbers using range
>>> for i in range(0,16):
... print i
So, is there any built-in way in python to generate a list of numbers in the specified format.
Python string formatting allows you to specify a precision:
Precision (optional), given as a '.' (dot) followed by the precision.
In this case, you can use it with a value of 2 to get what you want:
>>> ["%.2d" % i for i in range(16)]
['00', '01', '02', '03', '04', '05', '06', '07', '08', '09', '10', '11', '12',
'13', '14', '15']
You could also use the zfill function:
>>> str(3).zfill(2)
'03'
or the string format function:
>>> "{0:02d}".format(3)
'03'
One liner in Python 3.x
[f'{i:>02}' for i in range(1, 16)]
Output:
['01', '02', '03', '04', '05', '06', '07', '08', '09', '10', '11', '12', '13', '14', '15']
in oracle write this query to generate 01 02 03 series
select lpad(rownum+1, decode(length(rownum),1,2, length(rownum)),0) from employees