Generate all tuple possible based on three lists - python

Interesting answers, allow me to modify the question.
After some change on the code I got this:
#coding:utf-8
import itertools
stuff = [1, 2, 3, 4, 5, 8, 10, 13, 16, 17, 18, 20, 21, 22, 25]
for L in range(5, 6):
for subset in itertools.combinations(stuff, L):
subset = list(subset)
subset.extend([7, 9, 11, 15, 19, 23, 6, 12, 14, 24])
print(subset)
the output of it is like this:
[1, 2, 3, 4, 5, 7, 9, 11, 15, 19, 23, 6, 12, 14, 24]
[1, 2, 3, 4, 8, 7, 9, 11, 15, 19, 23, 6, 12, 14, 24]
...
It generates approximately 3000 lines.
It did all possible combination with five numbers of the list stuff and add to every single combination (subset) the another list (subset.extend([7, 9, 11, 15, 19, 23, 6, 12, 14, 24])). It seems to be right, I'm not sure.
But what I really want it to do is:
1 - Input three lists (pair and unpair)
stuff = [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]
pair = [2 , 6, 12, 20, 16, 10, 22]
unpair = [1, 5, 11, 19, 23, 25, 13, 17]
2 - Than the program will generate all combinations of 4 numbers from the 7 numbers of pair and will do the same with unpair, generating all combinations of 4 numbers from the 8 numbers of unpair, and will bind it together generating a list with 8 number of al possible combinations of 4 numbers from pair combined with 4 number from unpair like:
[2, 12, 20, 10, 1, 5, 19, 23]
[2, 12, 20, 10, 5, 19, 25, 13]
...
3 - Than for each line from the combination of pair and unpair generated it will complete with a 7 numbers combination from the list stuff generating a list with 15 numbers without repeating a number like
[2, 12, 20, 10, 1, 5, 19, 23, 25, 3, 4, 8, 17, 21, 22]
[2, 12, 20, 10, 5, 19, 25, 13, 3, 4, 8, 17, 21, 22, 11]
...
Here is where I got stuck. How to generate a combination for each list and bind them generating a 15 numbers list without repeating a number and a sequence.

you can just manually code that logic in your for loop:
for combo in itertools.combinations(stuff, 15):
if set(combo).issuperset(pair) and set(combo).issuperset(unpair):
print(combo)
Note: This particular code only works when "stuff" has no duplicates

Related

Slicing Python Lists by Number [duplicate]

This question already has answers here:
Understanding slicing
(38 answers)
Closed 2 years ago.
I am new to Python, is there any best way to resolve below issue list slicing
I have main list called
result = [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, 26]
I would like to slice above list divide 12 and expecting to have the following output:
new_result = {
'One' : [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12],
'Two' : [13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24],
'Three' : [25, 26]
}
You can do something like this:
result = [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, 26]
chunk_size = 12
splitted_result = [result[x:x+chunk_size]
for x in range(0, len(result), chunk_size)]
for chunk in splitted_result:
print(chunk)
Result:
[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, 26]
Into the last for loop you can create the object with the correct keys.
The script logic is simple:
The range function takes three arguments:
start (0)
stop (length of the list)
step (increment between each returned value)
In your case you will have:
range(0, len(result), chunk_size)=[0,12,24]
and you just have to split the initial list in chunks that goes from:
result[0:0+12]
result[12:12+12]
result[24:24+12]
You can do the following:
result = [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, 26]
new_list = [result[n-1:n+11] for n in result[::12]]
new_result = {}
for n in range(1,len(new_list)+1):
new_result[n] = new_list[n-1]
new_result
{1: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12],
2: [13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24],
3: [25, 26]}
The new_list is just the list with the sliced lists. Then, I convert it into a dictionary called new_result, starting from '1' onwards

Is there another way to print multiple list elements where the list index increases by a given amount with each print?

I have a list containing hundreds of integers. I need to take 34 integers at a time, starting from the beginning of the list and print the integers in separate rows of 34.
The problem is that I have to use multiple print (list[x:y]) and continuously change the value for x and y.
I've tried specifying each index within the list to be printed, however, this is impractical since the list may contain hundreds of values.
integer = [
3,23,12,34,2,4,7,11,14,1,9,17,12,1,0,5,4,3,2,4,8,1,12,15,18,17,14,23,12,0,0
,12,34,2,21,22,24,23,1,0,4,7,3,13,16,15,3,5,11,22,9,14,20,16,3,6,2,0,10,1,12
,18,9,9,23,6,2,18,14,1,0,3,5,17,13,12,5,6,9,0,1,2,19,20,2,3,5,7,15,19,2,4,10
,15,18,17,2,6,5,3,6,12,15,18,12,15,6,20,0,9,4,1,5,4,3,7,9,0,12,3,5,7,8,17,19
,21,0,1,2,7,7,7,5,4,3,8,19,12,16,0,2,4,7,8,4,12,12,9,3,20,2,21,3,5,8,9,12,17
,8,7,3,4,6,3,14,18,21,4,3,9,19,19,3,6,8,7,13,14,18,13,15,3,4,8,7,12
]
print (integer[0:34])
print (integer[35:69])
print (integer[70:104])
Output:
[3, 23, 12, 34, 2, 4, 7, 11, 14, 1, 9, 17, 12, 1, 0, 5, 4, 3, 2, 4, 8, 1, 12, 15, 18, 17, 14, 23, 12, 0, 0, 12, 34, 2]
[22, 24, 23, 1, 0, 4, 7, 3, 13, 16, 15, 3, 5, 11, 22, 9, 14, 20, 16, 3, 6, 2, 0, 10, 1, 12, 18, 9, 9, 23, 6, 2, 18, 14]
[0, 3, 5, 17, 13, 12, 5, 6, 9, 0, 1, 2, 19, 20, 2, 3, 5, 7, 15, 19, 2, 4, 10, 15, 18, 17, 2, 6, 5, 3, 6, 12, 15, 18]
Assuming your expected output doesn't intentionally skip a value as shown, the following will print groups of 34 elements in a single line:
wholeLines = len(integer) // 34 * 34
for i in range( 0,wholeLines,34 ):
print(integer[i:i+34])
print( integer[wholeLines:] )
If you do not need to print out the remaining portion of the final line then you can omit the last line of code.
If you are just looking for an easy way to print chunks of size chunk_size of a list, use the following one-line list comprehension:
[print(data[chunk_size * index : chunk_size * index + chunk_size]) for index in range((len(data) // chunk_size) + 1)]
Change chunk_size to represent however large you would like your chunks to be.
Example:
In[2]: x = list(range(35))
In[3]: x
Out[3]: [0, 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, 26, 27, 28, 29, 30, 31, 32, 33, 34]
In[4]: chunk_size = 9
In[5]: [print(x[chunk_size * index : chunk_size * index + chunk_size]) for index in range((len(x) // chunk_size) + 1)]
[0, 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, 26]
[27, 28, 29, 30, 31, 32, 33, 34]
so you are looking to iteratively take 34 elements -- I'll assume you want to print the last elements of the list even if there aren't a full 34. The tool to use here is a Loop. Inside that for loop, you want to print 34 elements based on a current index, like so:
print intlist(n:n+34)
okay, so your iteration limits. the simplest way to do this is with a do-while loop (and remember to incremement your index variable each loop):
n=0
while n < len(intlist):
print intlist(n:n+34)
n += 34
there's a bug here, though. it won't print the last section of the list -- because you will get an IndexOutoFRange exception (when n+34 is too big). To fix that, you can wrap this in an try-except block, which will handle the special case by printing to the end of your list:
n=0
while n < len(intlist):
try:
print intlist(n:n+34)
except:
print intlist(n:)
n += 34

Not sure of what is wrong, trying to produce a 5x5 grid python 1-25

I am not sure what I am doing wrong, if anyone can see exactly, please inform me.
Tried:
grid = [[n in range(1,6)*5]]
and
grid [[]*5 for n in range(1,25)]
My code:
grid = [[x for x in range(1,25)] for y in range(5)]
Output:
[[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24], [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24], [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24], [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24], [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24]]
Desired:
[[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]]
It's fairly obvious that values in inner lists have to be related both to internal counter in each list (x) and position of list in outer list (y). Your code fails to take care about second requirement.
grid = [[1+x+5*y for x in range(5)] for y in range(5)]
You are iterating in a range from 1 to 24(inclusive) in your inner loop, which is why your lists are too long, and have the same values in them.
You somehow need to make the variable of your outer loop dictate the inner loop so each range within the inner loop start from a different point. Also, calibrating the length of the inner range is essential.
That being said, I suggest the following to get your desired output.
grid = [list(range(i, i+5)) for i in range(1, 26, 5)]
You can cut a list into sublist of 5, see this code
data=range(1,26)
len_sublist = 5
print [data[x:x+len_sublist] for x in xrange(0, len(data), len_sublist)]

Finding craters [descending/ ascending ints] in a python list of ints

I have a list of ints in python, and I would like the output to be a list of different "craters" in the sequence. I define a crater as a sequence of numbers that begins with descending ints that gradually grow bigger, until they reach a number that is equal to the first int of the crater or greater than the first int in the crater.
If the last number is equal or smaller than the first - it should be in the output at the end of the crater. If the last number is greater than the first number in the crater - it should not be appended to the end of the output list.
For example, for the list:
1,2,3,4,5,6,5,4,3,4,5,6,7,8,9
A "crater" would be:
6,5,4,3,4,5,6
My code:
def find_crater(my_list):
cur_crater = []
for i in range(len(my_list)-1):
#check if the numbers are decreasing
if (my_list[i] - my_list[i+1] > 0):
cur_crater.append(my_list[i])
#if increasing - check if we're in a crater
#and if current number is smaller than begining of crater
elif len(cur_crater) > 1 and my_list[i] <= cur_crater[0]:
cur_crater.append(my_list[i])
#print crater and empty list
elif len(cur_crater) > 1 and my_list[i+1] > cur_crater[0]:
print(cur_crater)
cur_crater = []
#continue if we're out of a crater
else:
continue
#catching the last crater in the list
if len(cur_crater) > 1:
#include last int
if my_list[i] - my_list[-1] < 0 and my_list[-1] <= cur_crater[0]:
cur_crater.append(my_list[-1])
print(cur_crater)
return
I have called the function on 2 lists. The 1st output is as expected:
ok_list = [12, 4, 7, 4, 2, 4, 5, 6, 5, 12, 21, 23,
24, 26, 25, 22, 10, 9, 8, 6, 9, 10, 11, 13, 12, 14,
17, 27, 28, 19, 17, 19, 21, 19, 12, 23, 25, 27]
Ok list output [edit: not so ok - it ommited the first '4' so turns out it's not so OK after all]:
[12, 7, 4, 2, 4, 5, 6, 5, 12]
[26, 25, 22, 10, 9, 8, 6, 9, 10, 11, 13, 12, 14, 17]
[28, 19, 17, 19, 21, 19, 12, 23, 25, 27]
However, the second list combines 2 lists of craters into 1 list in the output:
problematic = [12, 4, 7, 4, 2, 4, 5, 6, 5, 12, 21, 23,
24, 26, 25, 22, 10, 9, 8, 6, 9, 10, 11, 13, 12, 14,
17, 27, 19, 25, 19, 12, 23, 25, 27]
problematic Output:
[12, 7, 4, 2, 4, 5, 6, 5, 12]
[26, 25, 22, 10, 9, 8, 6, 9, 10, 11, 13, 12, 14, 17, 27, 19, 25, 19, 12, 23, 25]
I was expecting:
[12, 4, 7, 4, 2, 4, 5, 6, 5, 12]
[26, 25, 22, 10, 9, 8, 6, 9, 10, 11, 13, 12, 14, 17]
[27, 19, 25, 19, 12, 23, 25, 27]
I tried to take care of this by writing:
my_list[i+1] > cur_crater[0]
and thus checking the size of next int in the list - but that does not seem to fix it [I left it in the code even though it does not do the trick in hopes of someone explaining why is that wrong/ not working?].
In conclusion, my code can't handle it when there is a crater right after a crater with only one int in between.
If the input is:
[12, 4, 7, 4, 2, 4, 5, 6, 5, 12, 21, 10, 9, 8, 6, 9, 10]
Then the output is one long list, but I'd like to split it after list item 12 and before list item 21, but the output is one long list.
I would love to get info about any library or method that can give me more ideas regarding a better and more efficient solution.
Presuming your expected output is wrong which it seems to be, all you want to do is go until you find an element >= to the start of the chain and catch chains that only contain a single element:
def craters(lst):
it = iter(lst)
# get start of first chain
first = next(it)
tmp = [first]
# iterate over the remaining
for ele in it:
# >= ends chain
if ele >= first:
# if equal, add it and call
# next(it) to set the next first element.
if ele == first:
tmp.append(ele)
yield tmp
first = next(it)
tmp = [first]
# else yield the group if it has > 1 element.
# if it has 1 element it is not a descending start sequecne
else:
if len(tmp) > 1:
yield tmp
tmp = [ele]
first = ele
else:
tmp.append(ele)
if len(tmp) > 1: # catch single element last
yield tmp
Output:
In [5]: ok_list = [12, 4, 7, 4, 2, 4, 5, 6, 5, 12, 21, 23,
...: 24, 26, 25, 22, 10, 9, 8, 6, 9, 10, 11, 13, 12, 14,
...: 17, 27, 28, 19, 17, 19, 21, 19, 12, 23, 25, 27]
In [6]: problematic = [12, 4, 7, 4, 2, 4, 5, 6, 5, 12, 21, 23,
...: 24, 26, 25, 22, 10, 9, 8, 6, 9, 10, 11, 13, 12, 14,
...: 17, 27, 19, 25, 19, 12, 23, 25, 27]
In [7]: ex_ok = [[12, 4, 7, 4, 2, 4, 5, 6, 5, 12],
...: [26, 25, 22, 10, 9, 8, 6, 9, 10, 11, 13, 12, 14, 17],
...: [28, 19, 17, 19, 21, 19, 12, 23, 25, 27]]
In [8]: ex_p = [[12,4, 7, 4, 2, 4, 5, 6, 5, 12],
...: [26, 25, 22, 10, 9, 8, 6, 9, 10, 11, 13, 12, 14, 17],
...: [27, 19, 25, 19, 12, 23, 25, 27]]
In [9]: print(list(craters(problematic)) == ex_p)
True
In [10]: print(list(craters(ok_list)) == ex_ok)
True
In [11]: print(list(craters([12, 4, 7, 4, 2, 4, 5, 6, 5, 12, 21, 10, 9, 8, 6, 9, 10])))
[[12, 4, 7, 4, 2, 4, 5, 6, 5, 12], [21, 10, 9, 8, 6, 9, 10]]
In [12]: list(craters([1, 2, 3, 4, 5, 6, 5, 4, 3, 4, 5, 6, 7, 8, 9]))
Out[13]: [[6, 5, 4, 3, 4, 5, 6]]
That does not involve any slicing/indexing you can lazily return each group.
To simplify your algorithm, the steps are:
Start with the first element, then check if the next element is >=, if it is and it is equal add it to the group, if it is > set that to be the new start of the group.
If the new first is not greater than the next element the length of that group will be one as it does not satisfy sequence of numbers that begins with descending. So we keep consuming and setting the next element to be the first element of the sequence until we find one the is > the next element, that is what the call to next(it) is doing then we just need to wash and repeat.
Here is what I came with:
def find_crater(my_list):
previous = None
current_crater = []
crater_list = []
for elem in my_list:
#For the first element
if not previous:
previous = elem
continue
if len(current_crater) == 0:
if elem > previous:
previous = elem
else:
current_crater.append(previous)
previous = elem
else:
if elem > current_crater[0]:
current_crater.append(previous)
crater_list.append(current_crater)
current_crater = []
previous = elem
else:
current_crater.append(previous)
previous = elem
if len(current_crater) != 0:
if elem > current_crater[0]:
current_crater.append(previous)
crater_list.append(current_crater)
else:
current_crater.append(previous)
crater_list.append(current_crater)
return crater_list
That gave me the exact output you want:
In [5]: ok_list = [12, 4, 7, 4, 2, 4, 5, 6, 5, 12, 21, 23,
...: 24, 26, 25, 22, 10, 9, 8, 6, 9, 10, 11, 13, 12, 14,
...: 17, 27, 28, 19, 17, 19, 21, 19, 12, 23, 25, 27]
In [6]: find_crater(ok_list)
Out[6]:
[[12, 4, 7, 4, 2, 4, 5, 6, 5, 12],
[26, 25, 22, 10, 9, 8, 6, 9, 10, 11, 13, 12, 14, 17],
[28, 19, 17, 19, 21, 19, 12, 23, 25, 27]]
In [7]: problematic = [12, 4, 7, 4, 2, 4, 5, 6, 5, 12, 21, 23,
...: 24, 26, 25, 22, 10, 9, 8, 6, 9, 10, 11, 13, 12, 14,
...: 17, 27, 19, 25, 19, 12, 23, 25, 27]
In [8]: find_crater(problematic)
Out[8]:
[[12, 4, 7, 4, 2, 4, 5, 6, 5, 12],
[26, 25, 22, 10, 9, 8, 6, 9, 10, 11, 13, 12, 14, 17],
[27, 19, 25, 19, 12, 23, 25, 27]]
Try this:
We just slice the list finding start_index:end_index making three cases
When element is equal
When element is greater
Boundary case when last element even if smaller may need to be sliced
def find_crater(l):
result = []
start_index = 0
for i in range( start_index +1,len(l)):
start = l[start_index]
if i==len(l)-1 and l[i]!=start:
result = l[start_index:i+1]
print result
elif l[i]==start:
end_index = i+1
result = l[start_index:end_index]
start_index = end_index +1
if len(result)>1:
print result
elif l[i]>start:
end_index = i
result = l[start_index:end_index]
start_index = end_index
if len(result)>1:
print result
Input:
ok_list = [12, 4, 7, 4, 2, 4, 5, 6, 5, 12, 21, 23,
24, 26, 25, 22, 10, 9, 8, 6, 9, 10, 11, 13, 12, 14,
17, 27, 28, 19, 17, 19, 21, 19, 12, 23, 25, 27]
problematic = [12, 4, 7, 4, 2, 4, 5, 6, 5, 12, 21, 23,
24, 26, 25, 22, 10, 9, 8, 6, 9, 10, 11, 13, 12, 14,
17, 27, 19, 25, 19, 12, 23, 25, 27]
Output:
find_crater(ok_list)
find_crater(problematic)
[12, 4, 7, 4, 2, 4, 5, 6, 5, 12]
[25, 22, 10, 9, 8, 6, 9, 10, 11, 13, 12, 14, 17]
[28, 19, 17, 19, 21, 19, 12, 23, 25, 27]
[12, 4, 7, 4, 2, 4, 5, 6, 5, 12]
[25, 22, 10, 9, 8, 6, 9, 10, 11, 13, 12, 14, 17]
[27, 19, 25, 19, 12, 23, 25, 27]

Making list of all possible sums up to a certain value

I need to make an effective algorithm for getting all possible sums (EDIT: pairwise) of elements from one list (including themselves), and storing them into another list up to a certain value.
For instance, if the value is 30, and the list is [1,2,3,4,5,15,20], I want a list that is:
[1,2,3,4,5,6,7,8,9,10,15,16,17,18,19,20,21,22,23,24,25,30]
Right now I have a algorithm that works, yet is extremely ineffective (I need to do this up to 29000:
sumlist = [0]*60000
for j in range(0,len(abundlist)):
for i in range(j,len(abundlist)):
if sumlist[abundlist[i] + abundlist[j]] == 0: sumlist[abundlist[i] + abundlist[j]] = 1
Where I put a 1 if the sum has occurred, in order to avoid equal values.
I have also tried to eliminate all multiples from the abundlist first, but that didn't help at all.
I think I may be approaching this problem wrong. Any suggestions/optimizations/comments would be very helpful.
You don't need to initialise lists in python using the first line. And to sum every pait of digits is easy using list comprehension:
>>> x=[1,2,3,4,5,15,20]
>>> [i+j for i in x for j in x]
[2, 3, 4, 5, 6, 16, 21, 3, 4, 5, 6, 7, 17, 22, 4, 5, 6, 7, 8, 18, 23, 5, 6, 7, 8, 9, 19, 24, 6, 7, 8, 9, 10, 20, 25, 16, 17, 18, 19, 20, 30, 35, 21, 22, 23, 24, 25, 35, 40]
If you want to restrict this, you can add a simple filter to the end of the comprehension:
>>> [i+j for i in x for j in x if i+j<=30]
[2, 3, 4, 5, 6, 16, 21, 3, 4, 5, 6, 7, 17, 22, 4, 5, 6, 7, 8, 18, 23, 5, 6, 7, 8, 9, 19, 24, 6, 7, 8, 9, 10, 20, 25, 16, 17, 18, 19, 20, 30, 21, 22, 23, 24, 25]
And if they need to be unique, you can covnvert it to a set, then back to a list:
>>> list(set([i+j for i in x for j in x if i+j<=30]))
[2, 3, 4, 5, 6, 7, 8, 9, 10, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 30]
However, sets are unsorted, and the conversion back to a list may not neccessarily maintain order, so you can also sort it like so:
>>> sorted(list(set([i+j for i in x for j in x if i+j<=30])))
[2, 3, 4, 5, 6, 7, 8, 9, 10, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 30]
Regarding the efficiency of this:
Here is a fun little test that shows performing the mass sums, including casting to and from sets and lists multiple times. In essence it builds a list of numbers from 1 to 1000 (weighted more towards smaller numbers to match the numbers in the original question), then performs the sums as described above.
Building and running list, and summing it, 100 times takes under 2 seconds.
>>> timeit.timeit(
'x=sorted(list(set([randint(1,i) for i in range(2,1000)])));z=[i+j for i in x for j in x if i+j<=500]',
setup="from random import randint",number=100)
1.7806868553161621

Categories