Python - loop through list in specific order - python

I have a list defined as:
pad = [unhexlify('00' * (16-j) + ('%02d' % j) * j) for j in range(1, 17)]
This constructs a pad list for a padding oracle attack. Due to how this attack works I need to cycle through elements 2-16, then if I don't get a hit go back and try the 1st element. Here is the loop:
for padsel in pad: #increment pad
print(str(hexlify(padsel)) + "- selected pad")
for i in range(256): #increment guess
g = unhexlify("000000000000000000000000000000" + "{:02x}".format(i))
print(str(hexlify(g)) + "- guess")
if attack(g,padsel,ct_prev, ct_target):
m2 += "{:02x}".format(i)
print(m2)
break
else:
continue
m2 = m2[::-1]
print(m2 + "- m2")
How do I change the outer loop definition to do this?
Pseudo code:
for padsel in pad (items 2-16):
do stuff until hitting a break condition
else:
do stuff on element 1
Thanks.

Rather than use an else clause on the for loop, just modify the iterable (list) that you iterate over:
for padsel in (pad[1:16] + [pad[0]]):
print(str(hexlify(padsel)) + "- selected pad")
for i in range(256): #increment guess
g = unhexlify("000000000000000000000000000000" + "{:02x}".format(i))
print(str(hexlify(g)) + "- guess")
if attack(g,padsel,ct_prev, ct_target):
m2 += "{:02x}".format(i)
print(m2)
break
else:
continue
m2 = m2[::-1]
print(m2 + "- m2")
Using an else clause would require duplication of the code in the body of the for loop, or refactoring the body into a function so that duplication is not required. But, since the first item is processed in the same way as the other items, the simplest way is to organise for it to be processed last by iterating over items 2 through 16 and then item 1 if required.
>>> l = range(1,16+1)
>>> print l
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]
>>> print l[1:16] + [l[0]]
[2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 1]
The last statement effectively moved the first element of the list to the end of the list. If you don't mind if the list is modified, or even prefer it, you can do this:
>>> l = range(1,16+1)
>>> l.append(l.pop(0))
>>> print l
[2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 1]

If you need to keep original list untouched, try:
for item in items[1:16]: # iterate through elements 1-17 (list indexes starts at 0
do stuff
if condition:
break
else: # else in for loops will be run if loop ended normally (w/o `break`)
do stuff with items[0]
Keep in mind, that slicing lists (list[x:y]) will create a copy of existing list. This can become a memory issue, when used with huge lists.

Related

adding rows based on values of other rows

I have a list (in a dataframe) that looks like this:
oddnum = [1, 3, 5, 7, 9, 11, 23]
I want to create a new list that looks like this:
newlist = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 23]
I want to test if the distance between two numbers is 2 (if oddnum[index+1]-oddnum[index] == 2)
If the distance is 2, then I want to add the number following oddnum[index] and create a new list (oddnum[index] + 1)
If the distance is greater than two, keep the list as is
I keep getting key error because (I think) the list runs out of [index] and [index+1] no longer exists once it reaches the end of the list. How do I do this?
To pass errors, the best method is to use try and except conditions. Here's my code:
oddnum = [1, 3, 5, 7, 9, 11, 23]
res = [] # The new list
for i in range(len(oddnum)):
res.append(oddnum[i]) # Append the first value by default
try: # Tries to run the code
if oddnum[i] + 2 == oddnum[i+1]: res.append(oddnum[i]+1) # Appends if the condition is met
except: pass # Passes on exception (in our case KeyError)
print(res)
oddnum = [1, 3, 5, 7, 9, 11, 23]
new_list = []
for pos, num in enumerate(oddnum):
new_list.append(num)
try:
if num-oddnum[pos+1] in [2, -2]:
new_list.append(num+1)
except:
pass
print(new_list)
Use try: except: to prevent exceptions popping up and ignore it

Returning a list of the ordered elements with a conition in while loop structure

I am trying to solve a assignment where are 13 lights and starting from 1, light is turned off at every 5th light, when the count reaches 13, start from 1st item again. The function should return the order of lights turned off. In this case, for a list of 13 items, the return list would be [5, 10, 2, 8, 1, 9, 4, 13, 12, 3, 7, 11, 6]. Also, turned off lights would not count again.
So the way I was going to approach this problem was to have a list named turnedon, which is [1,2,3,4,5,6,7,8,9,10,11,12,13] and an empty list called orderoff and append to this list whenever a light gets turned off in the turnedon list. So while the turnedon is not empty, iterate through the turnedon list and append the light getting turned off and remove that turnedoff light from the turnedon list, if that makes sense. I cannot figure out what should go into the while loop though. Any idea would be really appreciated.
def orderoff():
n=13
turnedon=[]
for n in range(1,n+1):
turnedon.append(n)
orderoff=[]
while turneon !=[]:
This problem is equivalent to the well-known Josephus problem, in which n prisoners stand in a circle, and they are killed in a sequence where each time, the next person to be killed is k steps around the circle from the previous person; the steps are only counted over the remaining prisoners. A sample solution in Python can be found on the Rosetta code website, which I've adapted slightly below:
def josephus(n, k):
p = list(range(1, n+1))
i = 0
seq = []
while p:
i = (i+k-1) % len(p)
seq.append(p.pop(i))
return seq
Example:
>>> josephus(13, 5)
[5, 10, 2, 8, 1, 9, 4, 13, 12, 3, 7, 11, 6]
This works, but the results are different from yours:
>>> pos = 0
>>> result = []
>>> while len(result) < 13 :
... pos += 5
... pos %= 13
... if pos not in result :
... result.append(pos)
...
>>> result = [i+1 for i in result] # make it 1-based, not 0-based
>>> result
[6, 11, 3, 8, 13, 5, 10, 2, 7, 12, 4, 9, 1]
>>>
I think a more optimal solution would be to use a loop, add the displacement each time, and use modules to keep the number in range
def orderoff(lights_num,step):
turnd_off=[]
num =0
for i in range(max):
num =((num+step-1)%lights_num)+1
turnd_off.append(num)
return turnd_off
print(orderoff(13))

I am trying to delete every other element from a list, it is not working

def every_other (l):
alist = []
alist = l
for i in range (len (l)-1):
print (i)
if i % 2 == 1:
del (alist [i])
print (alist)
every_other ([0, -12, 4, 18, 9, 10, 11, -23])
output is [0, 4, 18, 10, 11]
when it should be: [0, 4, 9, 11]
Thanks in advance.
You can't remove items from a list and iterate through it at the same time, because that confuses the iterator. Either create a new list and add to it instead of removing items from the old one, or you can use Python's slice syntax to do this in one operation:
def every_other(l):
print l[::2]
Also, you can use list comprehension and filter the list based on its count:
the_list = [0, -12, 4, 18, 9, 10, 11, -23]
new_list = [i for a, i in enumerate(the_list) if a%2 == 0]
Below code will solve your logic:
a=[0, -12, 4, 18, 9, 10, 11, -23]
l=[]
for i,x in enumerate(a):
print "index : ",i,"data : ",x,">>>",i%2
if i%2!=1:
l.append(x)
you are deleting the same list that you are trying to iterate.so when your are at index 1 you delete-12 your new list is [0,4, 18, 9, 10,11,-23]
now you reach index 2 of iteration your value is 18 so its not deleted and same logic continues till the iteration completes.
This code should work if you only want to iterate every other element in a list;
def every_other(l):
return l[0::2]
But if you want to remove every other element then you should do that first before you print or return the list.
def remove_every_other(my_list):
del my_list[1::2]
return my_list

Insert a value to a sorted list via list comprehension Python

I have an assignment to add a value to a sorted list using list comprehension. I'm not allowed to import modules, only list comprehension, preferably a one liner. I'm not allowed to create functions and use them aswell.
I'm completely in the dark with this problem. Hopefully someone can help :)
Edit: I don't need to mutate the current list. In fact, I'm trying my solution right now with .pop, I need to create a new list with the element properly added, but I still can't figure out much.
try:
sorted_a.insert(next(i for i,lhs,rhs in enumerate(zip(sorted_a,sorted_a[1:])) if lhs <= value <= rhs),value)
except StopIteration:
sorted_a.append(value)
I guess ....
with your new problem statement
[x for x in sorted_a if x <= value] + [value,] + [y for y in sorted_a if y >= value]
you could certainly improve the big-O complexity
For bisecting the list, you may use bisect.bisect (for other readers referencing the answer in future) as:
>>> from bisect import bisect
>>> my_list = [2, 4, 6, 9, 10, 15, 18, 20]
>>> num = 12
>>> index = bisect(my_list, num)
>>> my_list[:index]+[num] + my_list[index:]
[2, 4, 6, 9, 10, 12, 15, 18, 20]
But since you can not import libraries, you may use sum and zip with list comprehension expression as:
>>> my_list = [2, 4, 6, 9, 10, 15, 18, 20]
>>> num = 12
>>> sum([[i, num] if i<num<j else [i] for i, j in zip(my_list,my_list[1:])], [])
[2, 4, 6, 9, 10, 12, 15, 18]

Split a Python list logarithmically

I am trying to do the following..
I have a list of n elements. I want to split this list into 32 separate lists which contain more and more elements as we go towards the end of the original list. For example from:
a = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
I want to get something like this:
b = [[1],[2,3],[4,5,6,7],[8,9,10,11,12]]
I've done the following for a list containing 1024 elements:
for i in range (0, 32):
c = a[i**2:(i+1)**2]
b.append(c)
But I am stupidly struggling to find a reliable way to do it for other numbers like 256, 512, 2048 or for another number of lists instead of 32.
Use an iterator, a for loop with enumerate and itertools.islice:
import itertools
def logsplit(lst):
iterator = iter(lst)
for n, e in enumerate(iterator):
yield itertools.chain([e], itertools.islice(iterator, n))
Works with any number of elements. Example:
for r in logsplit(range(50)):
print(list(r))
Output:
[0]
[1, 2]
[3, 4, 5]
[6, 7, 8, 9]
... some more ...
[36, 37, 38, 39, 40, 41, 42, 43, 44]
[45, 46, 47, 48, 49]
In fact, this is very similar to this problem, except it's using enumerate to get variable chunk sizes.
This is incredibly messy, but gets the job done. Note that you're going to get some empty bins at the beginning if you're logarithmically slicing the list. Your examples give arithmetic index sequences.
from math import log, exp
def split_list(_list, divs):
n = float(len(_list))
log_n = log(n)
indices = [0] + [int(exp(log_n*i/divs)) for i in range(divs)]
unfiltered = [_list[indices[i]:indices[i+1]] for i in range(divs)] + [_list[indices[i+1]:]]
filtered = [sublist for sublist in unfiltered if sublist]
return [[] for _ in range(divs- len(filtered))] + filtered
print split_list(range(1024), 32)
Edit: After looking at the comments, here's an example that may fit what you want:
def split_list(_list):
copy, output = _list[:], []
length = 1
while copy:
output.append([])
for _ in range(length):
if len(copy) > 0:
output[-1].append(copy.pop(0))
length *= 2
return output
print split_list(range(15))
# [[0], [1, 2], [3, 4, 5, 6], [7, 8, 9, 10, 11, 12, 13, 14]]
Note that this code is not efficient, but it can be used as a template for writing a better algorithm.
Something like this should solve the problem.
for i in range (0, int(np.sqrt(2*len(a)))):
c = a[i**2:min( (i+1)**2, len(a) )]
b.append(c)
Not very pythonic but does what you want.
def splitList(a, n, inc):
"""
a list to split
n number of sublist
inc ideal difference between the number of elements in two successive sublists
"""
zr = len(a) # remaining number of elements to split into sublists
st = 0 # starting index in the full list of the next sublist
nr = n # remaining number of sublist to construct
nc = 1 # number of elements in the next sublist
#
b=[]
while (zr/nr >= nc and nr>1):
b.append( a[st:st+nc] )
st, zr, nr, nc = st+nc, zr-nc, nr-1, nc+inc
#
nc = int(zr/nr)
for i in range(nr-1):
b.append( a[st:st+nc] )
st = st+nc
#
b.append( a[st:max(st+nc,len(a))] )
return b
# Example of call
# b = splitList(a, 32, 2)
# to split a into 32 sublist, where each list ideally has 2 more element
# than the previous
There's always this.
>>> def log_list(l):
if len(l) == 0:
return [] #If the list is empty, return an empty list
new_l = [] #Initialise new list
new_l.append([l[0]]) #Add first iteration to new list inside of an array
for i in l[1:]: #For each other iteration,
if len(new_l) == len(new_l[-1]):
new_l.append([i]) #Create new array if previous is full
else:
new_l[-1].append(i) #If previous not full, add to it
return new_l
>>> log_list([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
[[1], [2, 3], [4, 5, 6], [7, 8, 9, 10]]

Categories

Resources