I have a problem checking multiple conditions at once.
import itertools
def repeats(input1, input2):
return [int(dz) for dz in input1 if int(dz) in input2]
n_combs = [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]
filters = [[[1, 2, 3, 6, 7, 8, 11, 12, 16, 17, 21, 22], [5]], [[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12], [7]], [[20, 21, 22, 23, 24], [2]]]
combinacoes = itertools.combinations(n_combs, 15)
for comb in combinacoes:
for filtro, maxx in filters:
if len(repeats(filtro, comb)) in maxx:
print(comb)
Basically, I need a combination to only print if:
contain 5 items from this list: [1, 2, 3, 6, 7, 8, 11, 12, 16, 17, 21, 22]
contain 7 items from this list: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
contain 2 items from this list: [20, 21, 22, 23, 24]
The above code does not do the 3 validations at the same time and that's what I need.
I think your loop is working properly only that the last element in filters does not meet the conditions you have specified. Edit it to include smaller numbers like I have done below. Also, I have reduced the number of elements in n_combs so that my answer becomes easy to understand. This is because looping through the more than 3 million entries in 25 combination 15 is not a very good idea for demonstration purposes. Try to run the edited version below and you will see what I am saying.
import itertools
def repeats(input1, input2):
return [int(dz) for dz in input1 if int(dz) in input2]
n_combs = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20]
filters = [[[1, 2, 3, 6, 7, 8, 11, 12, 16, 17, 21, 22], [5]], [[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12], [7]], [[2, 4, 7,9], [2]]]
combinacoes = itertools.combinations(n_combs, 15)
for comb in combinacoes:
for filtro, maxx in filters:
if len(repeats(filtro, comb)) in maxx:
print(comb, maxx)
Let me know if this solves your problem.
I assume you want to apply an arbitrary number of tests to some value.
Since in Python functions are first class citizens, you can have a list of validator functions:
def iterable_contains_1(value):
return 1 in value
def iterable_contains_2(value):
return 2 in value
validators = [iterable_contains_1, iterable_contains_2]
Then you can call all your validations:
for item in ([1, 2, 3], [2, 3, 4], [1, 3, 4], [3, 4, 5]):
if all(validator(item) for validator in validators):
print('do something with', item)
This will print only do something with [1, 2, 3] as it is the only list passing both tests.
[edit]
I think you are looking for set.
def validator1(iterable):
return len(
set(iterable).intersection(
[1, 2, 3, 6, 7, 8, 11, 12, 16, 17, 21, 22]
)) >= 5
def validator2(iterable):
return len(
set(iterable).intersection(
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
)) >= 7
def validator3(iterable):
return len(
set(iterable).intersection(
[20, 21, 22, 23, 24]
)) >= 2
I found a resolution:
import itertools
def repeats(input1, input2):
return [int(dz) for dz in input1 if int(dz) in input2]
n_combs = [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]
filters = [[[1, 2, 3, 6, 7, 8, 11, 12, 16, 17, 21, 22], [5]], [[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12], [7]], [[20, 21, 22, 23, 24], [2]]]
combinacoes = itertools.combinations(n_combs, 15)
for comb in combinacoes:
if all([len(repeats(filtro, comb)) in qtd for filtro, qtd in filters]):
print(comb)
Remembering that the values used in this post were just examples, to simplify and better understand logic.
Now the algorithm is able to validate a combination on all filters at the same time, and allow one condition to be satisfied for all.
Related
I would like to obtain a list of integers whose cubes add up to a target number. The integers in the list must all be distinct. My code works for all cases except for
n=sum([n*n*n for n in range(1001)])
...where the expected result is [6303, 457, 75, 14, 9, 7,5, 4] instead my output in my program is [6303, 457, 75, 15, 8, 4, 3, 2, 1]. How can I correct my program to correctly output the expected result?
def sum_of_cubes(n):
original=n
i=1
lst=[]
tot=0
while i**3<=n:
i+=1
lst.append(i-1)
n-=(i-1)**3
for j in range(lst[0],0,-1):
if j**3<n:
lst.append(j)
n-=j**3
if n==1:
lst.append(n)
for i in lst:
tot+=i**3
#if original-tot>1:
#return None
return lst
n=sum([n*n*n for n in range(1001)])
print(sum_of_cubes(n))
You can implement a backtracking search algorithm using a stack (instead of recursion). Of course, being an exponential algorithm, it only works for inputs of relatively small size.
from math import *
def sum_of_cubes(n):
bag = []
stack = [(floor(n**(1/3)), n, [])] # simulated initial call
while stack:
(k, n, s) = stack.pop()
if n == 0: bag.append(s)
elif k > 0:
stack.append((k-1, n, s)) # simulated recursive call
if n-k**3 >= 0: stack.append((k-1, n-k**3, [k]+s)) # simulated recursive call
return bag
Examples:
>>> sum_of_cubes(8)
[[2]]
>>> sum_of_cubes(11)
[]
>>> sum_of_cubes(855)
[[1, 5, 9], [7, 8]]
>>> sum_of_cubes(3473)
[[9, 14], [1, 6, 8, 14], [1, 3, 4, 5, 8, 14], [2, 3, 8, 9, 13], [1, 2, 4, 5, 6, 11, 12], [1, 2, 3, 5, 7, 8, 9, 12], [2, 4, 5, 6, 9, 10, 11]]
>>> sum_of_cubes(sum(n**3 for n in range(11)))
[[1, 4, 6, 14], [2, 3, 4, 9, 13], [1, 2, 3, 4, 6, 8, 13], [1, 2, 6, 7, 9, 12], [1, 2, 3, 4, 5, 7, 9, 12], [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]]
>>> sum_of_cubes(15000)
[[2, 3, 5, 6, 9, 12, 23], [3, 5, 8, 10, 11, 14, 21], [3, 9, 11, 17, 20], [1, 3, 6, 8, 11, 17, 20], [2, 4, 5, 6, 7, 11, 17, 20], [2, 3, 5, 14, 16, 20], [3, 5, 9, 14, 15, 20], [1, 3, 5, 6, 8, 14, 15, 20], [6, 8, 11, 13, 14, 20], [3, 4, 5, 8, 11, 13, 14, 20], [2, 4, 5, 10, 11, 12, 14, 20], [5, 7, 9, 11, 12, 14, 20], [1, 5, 6, 7, 8, 11, 12, 14, 20], [5, 6, 7, 8, 9, 10, 11, 14, 20], [2, 3, 5, 7, 8, 9, 11, 12, 13, 20], [3, 5, 6, 8, 15, 17, 18], [5, 6, 7, 8, 11, 12, 17, 18], [1, 2, 5, 7, 8, 9, 11, 14, 15, 18], [2, 3, 5, 6, 8, 12, 15, 16, 17], [2, 3, 4, 5, 6, 11, 13, 14, 15, 17]]
Remark If you are interested in getting only one of the possible solutions, you can use this other version of the algorithm:
def sum_of_cubes(n):
stack = [(floor(n**(1/3)), n, [])]
while stack:
(k, n, s) = stack.pop()
if n == 0: return s
elif k > 0:
stack.append((k-1, n, s))
if n-k**3 >= 0: stack.append((k-1, n-k**3, [k]+s))
Example:
>>> sum_of_cubes(sum(n**3 for n in range(1001)))
[4, 5, 7, 9, 14, 75, 457, 6303]
The problem with your algorithm is this:
while i**3 <= n:
i += 1
lst.append(i-1)
It appends "15" which is lesser than "14"+"9", so your algorytm would not also work for n=3473 for example, wich is 14^3+9^3.
Solution: The only thing I can think of it is maybe to make the forbidden list, basically your algorithm first tries the original one, if it fails, try variants that exclude 1-all member/s of that unsuccessful list...or something like that maybe?
Also you should have checker like:
if original != tot:
doSomething()
lst=[]
etc....
This should get you to right track, good luck.
EDIT:
Ok so recursive function would solve the problem...if you had infinite CPU power/time, i will show solution to eliminate ONE black member, if there would be 2 or more numbers like 15, it will fail.
if original != tot:
lst= doSomething(original, lst)
doSomething(n,lst):
returnList=[]
newList=[]
orig=n
for blackMember in lst:
n=orig
#basicaly what you wrote before but try add before append and lowering n
if theNumberYOuWantToAdd != blackMember:
n -= theNumberYOuWantToAdd**3
newList.append(theNumberYOuWantToAdd)
....
....
....
if tot == original:
returnList = newList
#ofc if you want recursive functions you can do this just...it will freeze on big numbers:
#else:
#superBlastlist = newList + lst #dunno how to connect them, but you have idea
#returnList=doSomething(orig, superBlastlist)
return returnList
So you have idea...
So basically, for 1-2 levels of blacklisting numbers, it would be CPU acceptable, but i would reccomend dont go above 1e10 combinations, then even GPU helping would not save you :D
2nd Idea:
You can also make a list of A^3+B^3 where it's lower than n, then use that, but it will still be beatable by combinations of A+B+C etc..
[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]]
I am trying to implement a solution for outputting the sequence of moves for a 15-puzzle problem in Python. This is part of an optional assignment for a MOOC. The problem statement is given at this link.
I have a version of the program (given below) which performs valid transitions.
I am first identifying the neighbors of the empty cell (represented by 0) and putting them in a list. Then, I am randomly choosing one of the neighbors from the list to perform swaps with the empty cell. All the swaps are accumulated in a different list to record the sequence of moves to solve the puzzle. This is then outputted at the end of the program.
However, the random selection of numbers to make the swap with the empty cell is just going on forever. To avoid "infinite" (very long run) of loops, I have limited the number of swaps to 30 for now.
from random import randint
def find_idx_of_empty_cell(p):
for i in range(len(p)):
if p[i] == 0:
return i
def pick_random_neighbour_idx(neighbours_idx_list):
rand_i = randint(0, len(neighbours_idx_list)-1)
return neighbours_idx_list[rand_i]
def perform__neighbour_transposition(p, tar_idx, src_idx):
temp = p[tar_idx]
p[tar_idx] = p[src_idx]
p[src_idx] = temp
def solve_15_puzzle(p):
standard_perm = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,0]
neighbours_idx_list = []
moves_sequence = []
empty_cell_idx = find_idx_of_empty_cell(p)
previous_empty_cell_idx = empty_cell_idx
while (not(p == standard_perm) and len(moves_sequence) < 30):
if not (empty_cell_idx in [0,4,8,12]):
neighbours_idx_list.append(empty_cell_idx - 1)
if not (empty_cell_idx in [3,7,11,15]):
neighbours_idx_list.append(empty_cell_idx + 1)
if not (empty_cell_idx in [0,1,2,3]):
neighbours_idx_list.append(empty_cell_idx - 4)
if not (empty_cell_idx in [12,13,14,15]):
neighbours_idx_list.append(empty_cell_idx + 4)
if previous_empty_cell_idx in neighbours_idx_list:
neighbours_idx_list.remove(previous_empty_cell_idx)
chosen_neighbour_idx = pick_random_neighbour_idx(neighbours_idx_list)
moves_sequence.append(p[chosen_neighbour_idx])
perform__neighbour_transposition(p, empty_cell_idx, chosen_neighbour_idx)
previous_empty_cell_idx = empty_cell_idx
empty_cell_idx = chosen_neighbour_idx
neighbours_idx_list = []
if (p == standard_perm):
print("Solution: ", moves_sequence)
For the below invocation of the method, the expected output is [15, 14, 10, 13, 9, 10, 14, 15].
solve_15_puzzle([1, 2, 3, 4, 5, 6, 7, 8, 13, 9, 11, 12, 10, 14, 15, 0])
The 15-tiles problem is harder as it may seem at a first sight.
Computing the best (shortest) solution is a difficult problem and it has been proved than finding the optimal solution as N increases is NP-hard.
Finding a (non-optimal) solution is much easier. A very simple algorithm that can be made to work for example is:
Define a "distance" of the current position as the sum of the manhattan
distances of every tile from the position you want it to be
Start from the given position and make some random moves
If the distance after the moves improves or stays the same then keep the changes, otherwise undo them and return to the starting point.
This kind of algorithm could be described as a multi-step stochastic hill-climbing approach and is able to solve the 15 puzzle (just make sure to allow enough random moves to be able to escape a local minimum).
Python is probably not the best language to attack this problem, but if you use PyPy implementation you can get solutions in reasonable time.
My implementation finds a solution for a puzzle that has been mixed up with 1000 random moves in seconds, for example:
(1, 5, 43, [9, [4, 10, 14, 11, 15, 3, 8, 1, 13, None, 9, 7, 12, 2, 5, 6]])
(4, 17, 41, [9, [4, 10, 14, 11, 15, 3, 8, 1, 12, None, 6, 2, 5, 13, 9, 7]])
(7, 19, 39, [11, [4, 10, 14, 11, 15, 3, 1, 2, 12, 6, 8, None, 5, 13, 9, 7]])
(9, 54, 36, [5, [4, 14, 3, 11, 15, None, 10, 2, 12, 6, 1, 8, 5, 13, 9, 7]])
(11, 60, 34, [10, [4, 14, 3, 11, 15, 10, 1, 2, 12, 6, None, 8, 5, 13, 9, 7]])
(12, 93, 33, [14, [4, 14, 11, 2, 15, 10, 3, 8, 12, 6, 1, 7, 5, 13, None, 9]])
(38, 123, 31, [11, [4, 14, 11, 2, 6, 10, 3, 8, 15, 12, 1, None, 5, 13, 9, 7]])
(40, 126, 30, [13, [15, 6, 4, 2, 12, 10, 11, 3, 5, 14, 1, 8, 13, None, 9, 7]])
(44, 172, 28, [10, [15, 4, 2, 3, 12, 6, 11, 8, 5, 10, None, 14, 13, 9, 1, 7]])
(48, 199, 23, [11, [15, 6, 4, 3, 5, 12, 2, 8, 13, 10, 11, None, 9, 1, 7, 14]])
(61, 232, 22, [0, [None, 15, 4, 3, 5, 6, 2, 8, 1, 12, 10, 14, 13, 9, 11, 7]])
(80, 276, 20, [10, [5, 15, 4, 3, 1, 6, 2, 8, 13, 10, None, 7, 9, 12, 14, 11]])
(105, 291, 19, [4, [9, 1, 2, 4, None, 6, 8, 7, 5, 15, 3, 11, 13, 12, 14, 10]])
(112, 313, 17, [9, [1, 6, 2, 4, 9, 8, 3, 7, 5, None, 14, 11, 13, 15, 12, 10]])
(113, 328, 16, [15, [1, 6, 2, 4, 9, 8, 3, 7, 5, 15, 11, 10, 13, 12, 14, None]])
(136, 359, 15, [4, [1, 6, 2, 4, None, 8, 3, 7, 9, 5, 11, 10, 13, 15, 12, 14]])
(141, 374, 12, [15, [1, 2, 3, 4, 8, 6, 7, 10, 9, 5, 12, 11, 13, 15, 14, None]])
(1311, 385, 11, [14, [1, 2, 3, 4, 8, 5, 7, 10, 9, 6, 11, 12, 13, 15, None, 14]])
(1329, 400, 10, [13, [1, 2, 3, 4, 6, 8, 7, 10, 9, 5, 11, 12, 13, None, 15, 14]])
(1602, 431, 9, [4, [1, 2, 3, 4, None, 6, 8, 7, 9, 5, 11, 10, 13, 15, 14, 12]])
(1707, 446, 8, [5, [1, 2, 3, 4, 6, None, 7, 8, 9, 5, 15, 12, 13, 10, 14, 11]])
(1711, 475, 7, [12, [1, 2, 3, 4, 6, 5, 7, 8, 9, 10, 15, 12, None, 13, 14, 11]])
(1747, 502, 6, [8, [1, 2, 3, 4, 6, 5, 7, 8, None, 9, 10, 12, 13, 14, 15, 11]])
(1824, 519, 5, [14, [1, 2, 3, 4, 9, 6, 7, 8, 5, 10, 15, 12, 13, 14, None, 11]])
(1871, 540, 4, [10, [1, 2, 3, 4, 9, 6, 7, 8, 5, 10, None, 12, 13, 14, 15, 11]])
(28203, 555, 3, [9, [1, 2, 3, 4, 5, 6, 7, 8, 9, None, 10, 12, 13, 14, 11, 15]])
(28399, 560, 2, [10, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, None, 12, 13, 14, 11, 15]])
(28425, 581, 1, [11, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, None, 13, 14, 15, 12]])
(28483, 582, 0, [15, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, None]])
The last line means that after 24,483 experiments it found the target position after 582 moves. Note that 582 is for sure very far from optimal as it's known that no position in the classic version of the 15 puzzle requires more than 80 moves.
The number after the number of moves is the "manhattan distance", for example the fourth-last row is the position:
where the sum of manhattan distances from the solution is 3.
I have a list l=[2,3,4,5,6,99,7,8,9,10,11,12,100,13,14,15,16,17,18,101] and I will like to split l into sublists [2,3,4,5,6], [7,8,9,10,11,12],[13,14,15,16,17,18], meaning that I use 'separator' digits 99,100,101 that belong to separators = [99,100,101] as a flag to indicate where I should go on to the next list.
In particular, these sublists may not have the same number of elements, but are different in size of only 1 (5 or 6). Note: There may be more than 3 separators.
Is there an efficient way to do this in Python 3? I thought of first extracting the indices of the separator elements and then slice the list accordingly but it seems far too complex and computationally intensive..
Some insight will be great!
Add on (suggestion from #Netwave): My attempt (which clearly does not work):
g = []
for i in l:
if i in separators:
g += [l[:l.index(i)]]
Output:
>>> g
[[2, 3, 4, 5, 6], [2, 3, 4, 5, 6, 99, 7, 8, 9, 10, 11, 12], [2, 3, 4, 5, 6, 99, 7, 8, 9, 10, 11, 12, 100, 13, 14, 15, 16, 17, 18]]
Use groupby:
from itertools import groupby
separators = [99, 100, 101]
l = [2, 3, 4, 5, 6, 99, 7, 8, 9, 10, 11, 12, 100, 13, 14, 15, 16, 17, 18, 101]
splits = [list(values) for key, values in groupby(l, key=lambda x: x not in separators) if key]
print(splits)
Output
[[2, 3, 4, 5, 6], [7, 8, 9, 10, 11, 12], [13, 14, 15, 16, 17, 18]]
I hope you are looking for something similar to the below code. You need to iterate over your list and keep checking if the element is present in the separator list. This can be done other way around, as you said by iterating over the separator list and finding the index of the elements in the main list. For the sake of simplicity I took the former approach. (Make a note of the use of endindex variable):
l=[2,3,4,5,6,99,7,8,9,10,11,12,100,13,14,15,16,17,18,101]
seperator = [99,100,101]
list_of_list = []
endindex = 0
for i in range(0,len(l),1):
if l[i] in seperator:
list_of_list.append(l[endindex:i])
endindex = i + 1
print(list_of_list)
Ouput:
[[2, 3, 4, 5, 6], [7, 8, 9, 10, 11, 12], [13, 14, 15, 16, 17, 18]]
Easier for use in a function:
import itertools
def split(l,l2):
return [list(v) for k,v in itertools.groupby(l,lambda x: x in l2) if not k]
l = [2, 3, 4, 5, 6, 99, 7, 8, 9, 10, 11, 12, 100, 13, 14, 15, 16, 17, 18, 101]
print(split(l,[99, 100, 101]))
Output:
[[2, 3, 4, 5, 6], [7, 8, 9, 10, 11, 12], [13, 14, 15, 16, 17, 18]]
Realized a duplicate of Split a list into nested lists on a value
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