List comprehension in python with multiple if statements - python

I am trying to build list similar to this
Position = [1, 1, 1, 1, 1, 1, 1,
2, 2, 2, 2, 2, 2, 2,
3, 3, 3, 3, 3, 3, 3,
4, 4, 4, 4, 4, 4, 4,
5, 5, 5, 5, 5, 5, 5,
6, 6, 6, 6, 6, 6, 6,
7, 7, 7, 7, 7, 7, 7,
8, 8, 8, 8, 8, 8, 8,
9, 9, 9, 9, 9, 9, 9,
10, 10, 10, 10, 10, 10, 10,
11, 11, 11, 11, 11, 11, 11,
12, 12, 12, 12, 12, 12, 12,
13, 13, 13, 13, 13, 13, 13,
14, 14, 14, 14, 14, 14, 14,
15, 15, 15, 15, 15, 15, 15]
With the list comprehension like below (with one if statement), only the first 7 elements can be created. How can I add multiple if statements?
d = 1
position = [d if i<7 else d+1 for i in range (105)]

No need for even a single if; just use integer division
[1+i//7 for i in range (7*15)]

Use numpy for creating a list of some value with some repetition, append them together
import numpy as np
numbers_i_want = np.arange(1, 16, 1, dtype=int) #last number not included
arr = np.array([])
for n in numbers_i_want:
temp = np.full(
shape=10, # how many ints
fill_value=n #what int
)
arr= np.concatenate((arr,temp))
print(arr)

The simplest solution in the standard library is to chain multiple iterables together.
from itertools import chain, repeat
Position = list(chain.from_iterable(repeat(i, 7) for i in range(1, 16)))
or use two generators
Position = list(x for i in range(1, 16) for x in repeat(i, 7))
Or, since int values are immutable, list multiplication is a viable solution.
Position = list(chain.from_iterable([i]*7 for i in range(1, 16)))
Position = list(x for i in range(1, 16) for x in [i]*7)

Related

How to change a [1,2,3...20] list onto [[1,2..20], [20,19....1]] nested list?

[PYTHON] Hello i have to create a list which starts at 1 and ends at 20, and then convert this list into a nested list which should look like this: [[1,2,...,20],[20,19,...1]].
I did only this:
list = []
for i in range(1,21):
lista.append(i)
i += 1
which gives me a normal [1, ... 20] list,
but I don't know how to change it to a nested list with a reverse list.
You can use a list comprehension to simply do this (don't use list as variable name):
myList = [[x for x in range(1,21)],[y for y in range(21,0,-1)]]
Create a nested list to begin with:
l = [ [], [] ]
for i in range(20):
l[0].append(i+1) # fills the first inner list with 1...20
l[-1].append(20-i) # fills the last inner list with 20...1
print(l)
Output:
[[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20],
[20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1]]
my_list = [list(range(1, 21)), list(range(21, 0 ,-1))]
Reverse a list using slicing and concat both list.
arr = [1,2,3,4,5,6,7]
ans = [arr] + [arr[::-1]]
print(ans)
Output:
[[1, 2, 3, 4, 5, 6, 7], [7, 6, 5, 4, 3, 2, 1]]
Simple:
>>> x = [i for i in range(1, 21)]
>>> x
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20]
>>> r = [x, x[::-1]]
>>> r
[[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20], [20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1]]

TypeError: 'sage.rings.integer.Integer' object has no attribute '__getitem__'

I am trying to implement differential cryptanalysis on an sbox for a DES algorithm, and I'm receiving this error.
This is my code so far:
s1=[14, 4, 13, 1, 2, 15, 11, 8, 3, 10, 6, 12, 5, 9, 0, 7,
0, 15, 7, 4, 14, 2, 13, 1, 10, 6, 12, 11, 9, 5, 3, 8,
4, 1, 14, 8, 13, 6, 2, 11, 15, 12, 9, 7, 3, 10, 5, 0,
15, 12, 8, 2, 4, 9, 1, 7, 5, 11, 3, 14, 10, 0, 6, 13]
b=[]
for i in range(0, 63):
j=ZZ(i).binary().zfill(6)
b += [s1[ZZ('0b'+j[0]+j[5])][ZZ('0b'+j[1]+j[2]+j[3]+j[4])]]
s1=mq.SBox(b)
ddt=s1.difference_distribution_matrix()
for i in range(63):
print i,ddt[i]
The error is on
b += [s1[ZZ('0b'+j[0]+j[5])][ZZ('0b'+j[1]+j[2]+j[3]+j[4])]]
s1 is a list of a single dimension.
s1[ZZ('0b'+j[0]+j[5])][ZZ('0b'+j[1]+j[2]+j[3]+j[4])] is trying to index into the return of an index.
s1[ZZ('0b'+j[0]+j[5])] pulls back the integer value in s1 is position [ZZ('0b'+j[0]+j[5])].
Then you are trying to index into the integer at position [ZZ('0b'+j[1]+j[2]+j[3]+j[4])].
That is my best guess without knowing what is happening in ZZ().

Pick four cards and check if they sum to 24 - Python

I need a program that picks four cards from a deck and computes their sum.
Note that ace = 1, jack = 11, queen = 12, and king = 13. Upon computing their sum, check if that sum is equal to 24. If it is, record that. In the end, the program should display the number of combinations that sum to 24.
Here is what I have:
def selfour():
total = 0
cards = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13]
for a in range(52):
for b in range(1, 52):
for c in range(2, 52):
for d in range(3, 52):
print(cards[a], cards[b], cards[c], cards[d])
if (cards[a] + cards[b] + cards[c] + cards[d]) == 24:
total += 1
return total
def main():
print(selfour())
main()
I'm not too sure if this program yield the correct answer, but it is inefficient. If anybody can provide help to make this code more efficient, that would be great. I'm fairly certain that this does not yield a correct answer, so help with that would be great, too.
Thanks
Itertools is your friend. You can do this in a one liner:
import itertools
cards = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13]
def selfour():
return sum(sum(i) == 24 for i in itertools.combinations(cards, 4))
You are thinking about the cards not being equal to each other, but you're not quite getting it.
for a in range(52):
for b in range(1, 52):
needs to be something like:
for a in range(52):
for b in range(52):
if b == a:
continue
There is a module called itertools that has combinations that does what you want. With it your nested for loops can become:
from itertools import combinations
for a in combinations(cards, 4):
if sum(a) == 24:
total += 1
I'm not 100% sure if this is correct, but I was able to do:
from itertools import combinations
def sel(it, cnt=4, val=24):
return sum(sum(_) == val for _ in combinations(it, cnt))
cards = # ...
print(sel(cards, 4, 24)) # => 12517
Edit: Sorry, I'm sure new answers have been posted. I was writing this as soon as it came up but got distracted before I posted it.
This is what I ended up using for the code:
import itertools
cards = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13]
def selfour():
total = 0
for z in itertools.combinations(cards, 4):
if sum(z) == 24:
total += 1
return total
def main():
print(selfour())
main()
Thanks to help from users, this code is much more efficient and clean.
Also, other beginners can easily follow this if need -
-Thanks

Avoid chained numbers when printing lists

The code that I created generate a list with 15 numbers, from combinations, so after sorting it it's possible to see that some sequences comes with a lot of numbers chained like:
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 16, 20]
I'm trying to think a way to control it and print only lists with maximum 4 chained numbers:
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 16, 20]
(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11) >>>> 11 Chained numbers: 1 to 11.
So it won't be stored in file.txt.
[1, 2, 3, 6, 7, 8, 9, 11, 12, 16, 17, 18, 19, 22, 23]
(1, 2, 3) >>>> 3 chained, OK
(6, 7, 8, 9) >>>> 4 chained, OK
(11, 12) >>>> 2 chained, OK
(16, 17, 18, 19) >>>> 4 chained, OK
(22,23) 2 chained, OK.
So this list will be stored in the file
Could you guys give me an idea? A light?
Code that I created, it generate a file with all possible combinations of 15 numbers from a list of 25:
import itertools
my_file = open('file.txt', 'w')
ALL_25 = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25]
for subset in itertools.combinations(ALL_25, 15):
sort_subsets = sorted(subset)
my_file.write("{0}\n".format(sort_subsets))
print(sort_subsets)
my_file.close()
If you can convert the chain to its difference between consecutive elements it is easier to identify incremental sequences i.e, [1,2,3,4,7,8] gets converted to [1,1,1,3,1]. Further by converting it into a string it is easier to search for the pattern 111.
import numpy as np
import re
def validate(seq):
stl = "".join(np.diff(seq).astype(str))
for x in re.findall("[1]+",stl):
if len(x)>3:
return False
return True
print validate([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 16, 20])
print validate([1, 2, 3, 6, 7, 8, 9, 11, 12, 16, 17, 18, 19, 22, 23])
output
False
True

How to add multiple values to a list in one line in Python?

I have a list that I want to add multiple values to, and I use append(), as below, to add 10 more digits:
>>> x = [1, 2, 3, 4]
>>> x.append(5, 6, 7, 8, 9, 10, 11, 12, 13, 14)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: append() takes exactly one argument (10 given)
I kind of get what this means, so then I tried doing it with a list:
>>> x = [1, 2, 3, 4]
>>> x.append([5, 6, 7, 8, 9, 10, 11, 12, 13, 14])
>>> x
[1, 2, 3, 4, [5, 6, 7, 8, 9, 10, 11, 12, 13, 14]]
This isn't what I want though. It contains unnecessary square brackets. What I do want is this:
>>> x = [1, 2, 3, 4]
>>> x.what_I_want([5, 6, 7, 8, 9, 10, 11, 12, 13, 14])
>>> x
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14]
Is the first change that I made to take away the TypeError the correct change to make? Or is that why this isn't working?
It's called extend:
>>> x = [1, 2, 3, 4]
>>> x.extend([5, 6, 7, 8, 9, 10, 11, 12, 13, 14])
>>> x
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14]
http://docs.python.org/2/tutorial/datastructures.html#more-on-lists
http://docs.python.org/2/library/stdtypes.html#mutable-sequence-types
For completeness, your other options are creating a new list as a concatenation of the two lists:
>>> x = [1, 2, 3, 4]
>>> x + [5, 6, 7, 8, 9, 10, 11, 12, 13, 14]
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14]
>>> x += [5, 6, 7, 8, 9, 10, 11, 12, 13, 14]
>>> x
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14]
And assigning into the empty slice at the end:
>>> x = [1, 2, 3, 4]
>>> x[len(x):len(x)] = [5, 6, 7, 8, 9, 10, 11, 12, 13, 14]
>>> x
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14]
Use extend though.
Use extend():
>>> x = [1, 2, 3, 4]
>>> x.extend([5, 6, 7, 8, 9, 10, 11, 12, 13, 14])
>>> x
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14]
Instead of typing out the numbers from 5 through 15, use a range():
>>> x = [1, 2, 3, 4]
>>> x.extend(range(5, 15))
>>> x
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14]
The first edit that you made was correct, since you can only append one item at a time, not a tuple like (5, 6, 7, 8, 9, 10, 11, 12, 13, 14)
The list append() method takes a single argument, which is added to the list. Thus, when you pass it a list, that list becomes the new last element of the list to which it is appended. By maintaining such consistency Python allows us to conveniently create and process lists of lists and more complicated data structures. But it does mean append() is not the answer you are looking for.
The simplest answer to your problem I can think of is
x += range(15)
This will work fine in Python 2, but in Python 3 range() is a generator, so you have to use
x += list(range(15))
Lists can be added together as can tuples, and it works just like string concatenation.
There are several ways to do this in Python.
The most common and idiomatic approach is using the extend method, to extend the list in place.
x = [1, 2, 3, 4]
y = [5, 6, 7, 8, 9, 10, 11, 12, 13, 14]
x.extend(y)
print(x)
The addition operator can also be used to do this, though it creates a new list.
x = [1, 2, 3, 4]
y = [5, 6, 7, 8, 9, 10, 11, 12, 13, 14]
z = x + y # This creates a new list `z`
print(z)
Augmented assignment can also be used, to extend the list in place.
x = x_ = [1, 2, 3, 4]
y = [5, 6, 7, 8, 9, 10, 11, 12, 13, 14]
x += y # This doesn't create a new list
assert x is x_
print(x)
A particularly esoteric approach would involve using the slice assignment. You'd only want to do this if you're looking to confuse people.
x = [1, 2, 3, 4]
y = [5, 6, 7, 8, 9, 10, 11, 12, 13, 14]
x[len(x):] = y
print(x)

Categories

Resources