fill a one dimension space with predefined values [closed] - python

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 6 years ago.
Improve this question
I would like to fill a length with predefined "subLengths".
let say my subLength are : 3,4,5,6,7,10.
To fill a length of 15 I can use "10+5" , "3+4+3+5" ,"7+4+4" ,"7+5+3" ....
How could I get as an array one of theses results ?
Better : how could I get an array for several good results ? My maximum length is 70 and I guess It could be time consuming to get all the good results for this value.
I am a 3d artist, my coding skill is quiet limited and I just don't know how to deal with this problem .I can use Python or a language looking like C for that.
this code seems to work in my software :
def fillBuild(length, subLengths):
for i in range(len(subLengths)):
if subLengths[i] == length:
yield subLengths[i:i + 1]
elif subLengths[i] < length:
for subResult in fillBuild(length - subLengths[i] ,subLengths[i:] ):
yield subLengths[i:i + 1] + subResult

Recursive generator function (Python) producing all possible sublist permutations (with repetitions) of pool adding up to total:
from pprint import pprint
def sub_lists(pool, total):
for i in range(len(pool)):
if pool[i] == total:
yield pool[i:i + 1]
elif pool[i] < total:
for sub_list in sub_lists(pool, total - pool[i]):
yield pool[i:i + 1] + sub_list
pprint(list(sub_lists([3, 4, 5, 6, 7, 10], 15)))
[[3, 3, 3, 3, 3],
[3, 3, 3, 6],
[3, 3, 4, 5],
[3, 3, 5, 4],
[3, 3, 6, 3],
[3, 4, 3, 5],
[3, 4, 4, 4],
[3, 4, 5, 3],
[3, 5, 3, 4],
[3, 5, 4, 3],
[3, 5, 7],
[3, 6, 3, 3],
[3, 6, 6],
[3, 7, 5],
[4, 3, 3, 5],
[4, 3, 4, 4],
[4, 3, 5, 3],
[4, 4, 3, 4],
[4, 4, 4, 3],
[4, 4, 7],
[4, 5, 3, 3],
[4, 5, 6],
[4, 6, 5],
[4, 7, 4],
[5, 3, 3, 4],
[5, 3, 4, 3],
[5, 3, 7],
[5, 4, 3, 3],
[5, 4, 6],
[5, 5, 5],
[5, 6, 4],
[5, 7, 3],
[5, 10],
[6, 3, 3, 3],
[6, 3, 6],
[6, 4, 5],
[6, 5, 4],
[6, 6, 3],
[7, 3, 5],
[7, 4, 4],
[7, 5, 3],
[10, 5]]

Here's a recursive solution, using Python 2.7:
def fill(length, sublengths):
# IMPORTANT: this function will produce INCORRECT RESULTS if sublengths
# is not a list of unique integers sorted increasingly.
fillings = []
for i, sublength in enumerate(sublengths):
if sublength > length:
# if sublength is greater than length, there are no more allowable
# fillings (because sublengths are unique and are sorted
# increasingly), so we return the fillings collected so far;
return fillings
elif sublength == length:
# if sublength is exactly equal to length, then only one filling is
# possible, namely [sublength]; we append this filling to the
# fillings;
fillings.append([sublength])
else:
# we generate all the fillings that begin with sublength by
# prepending sublength to all the allowable fillings of
# (length - sublength), which we obtain by making a recursive call.
fillings.extend([[sublength] + subresult
for subresult in
fill(length - sublength, sublengths[i:])])
Example:
In [2]: fill(15, [3, 4, 5, 6, 7, 10])
Out[2]:
[[3, 3, 3, 3, 3],
[3, 3, 3, 6],
[3, 3, 4, 5],
[3, 4, 4, 4],
[3, 5, 7],
[3, 6, 6],
[4, 4, 7],
[4, 5, 6],
[5, 5, 5],
[5, 10]]
BTW: fill(70, [3, 4, 5, 6, 7, 10])) produces 1657 possible fillings, so you may want some additional criterion to whittle down the alternatives.
Some notes:
in order to avoid repeating solutions, we will require that each filling be ordered increasingly;
the key idea is this: suppose that the length to fill is L, and a1 < a2 < ... < an are the available sublengths. To find all the possible fillings of L that begin with a1 is tantamount to prepending a1 to all the fillings of L - a1. This is the rationale for the recursive call in the else block of fill. (When a function calls itself, as fill does, the function is said to be recursive.)
Since fill requires sublengths to be free of duplicates and sorted increasingly, we can use the following front-end function to ensure these conditions are satisfied:
def do_fill(length, sublengths):
return fill(length, sorted(set(sublengths)))
(NB: Below is a fairly detailed explanation of what the code does. If you already understand the code, you can safely skip the rest of this post.)
To better see what's going on, go back to the example above, and start by grouping the solutions according to the first sublength; you'll get the three groups shown below:
# group I
[3, 3, 3, 3, 3]
[3, 3, 3, 6]
[3, 3, 4, 5]
[3, 4, 4, 4]
[3, 5, 7]
[3, 6, 6]
# group II
[4, 4, 7]
[4, 5, 6]
# group III
[5, 5, 5]
[5, 10]
Now, compare the fillings in group I, all of which begin with 3, with the fillings for 15-3 = 12, using the sublengths [3, 4, 5, 6, 7, 10]:
In [3]: fill(15 - 3, [3, 4, 5, 6, 7, 10])
Out[3]:
[[3, 3, 3, 3],
[3, 3, 6],
[3, 4, 5],
[4, 4, 4],
[5, 7],
[6, 6]]
If now you prepend 3 to all these fillings, you'll get exactly the fillings in group I.
Now consider the fillings in group II, all of which begin with 4. Compare them with the fillings for 15 - 4 = 11, using the sublengths [4, 5, 6, 7, 10]:
In [4]: fill(15 - 4, [4, 5, 6, 7, 10])
Out[4]:
[4, 7],
[5, 6]
Again, if you prepend 4 to all these fillings you get exactly the fillings in group II.
You may wonder, why did I use [4, 5, 6, 7, 10] as the sublengths in the last call to fill above, and not [3, 4, 5, 6, 7, 10]? This is because I am interested only in fillings that are increasingly ordered and that begin with 4. This rules out any fillings that include 3.
Finally, to get the fillings in group III, prepend 5 to all the fillings for 15 - 5 = 10, using sublengths [5, 6, 7, 10]:
In [5]: fill(15 - 5, [5, 6, 7, 10])
Out[5]:
[[5, 5],
[10]]
If you are so inclined you can repeat the same sort of analysis for each of the subgroups. For example, you can group the fillings generated by fill(15 - 3, [3, 4, 5, 6, 7, 10]) according to their first element; you'd get 4 groups:
[3, 3, 3, 3]
[3, 3, 6]
[3, 4, 5]
[4, 4, 4]
[5, 7]
[6, 6]
These groups are obtained by prepending 3, 4, 5, or 6, respectively, to the fillings produced by
fill((15 - 3) - 3, [3, 4, 5, 6, 7, 10])
fill((15 - 3) - 4, [ 4, 5, 6, 7, 10])
fill((15 - 3) - 5, [ 5, 6, 7, 10])
fill((15 - 3) - 6, [ 6, 7, 10])
The analysis above just does "by hand" exactly what the fill function does.
One important thing to note is that, with every recursive call, the problem becomes simpler.
For example, in the process of generating filling [3, 5, 7] the following calls to fill got executed:
fill(15, [3, 4, 5, 6, 7, 10]) = fill(15, [3, 4, 5, 6, 7, 10])
fill(15 - 3, [3, 4, 5, 6, 7, 10]) = fill(12, [3, 4, 5, 6, 7, 10])
fill(15 - 3 - 5, [ 5, 6, 7, 10]) = fill( 7, [ 5, 6, 7, 10])
Note in particular the last one, fill(7, [5, 6, 7, 10]). One can spot its solution by inspection: only one filling of 7 is possible from sublengths [5, 6, 7, 10]. The recursion always ends with the solutions of these trivial cases. The ultimate solutions get assembled from these trivial ones.

Related

Using itertools.product repeat multiple times

I am trying to generate a list of unique lists each 5 elements long, the order is not important but there can't be any repeated elements. The first 3 elements needs to be from [1,2,3,4] and elements 4 and 5 from [5,6,7,8]. for example [1,2,3,7,8] is valid but [1,2,2,7,8] is not nor is [1,2,7,8,9]
The below code works but I am wondering is there a better way of incorporating the product function? something like d = product([L1, repeat=3][L4,repeat=2). From reading the docs the repeat keyword can only be used once, like this: d = product(L1,L4,repeat=2).
Any ideas how i could do this?
Thanks
from itertools import product
L1 = [1,2,3,4]
L2 = [1,2,3,4]
L3 = [1,2,3,4]
L4 = [5,6,7,8]
L5 = [5,6,7,8]
d = product(L1,L2,L3,L4,L5)
result=[]
for x in d:
if x.count(1)<2 and x.count(2)<2 and x.count(3)<2 and x.count(4)<2 and x.count(5)<2 and x.count(6)<2 and x.count(7)<2 and x.count(8)<2:
result.append(sorted(x))
result2 = []
for x in result:
if x not in result2:
result2.append(x)
print(result2)
result2
[[1, 2, 3, 5, 6],
[1, 2, 3, 5, 7],
[1, 2, 3, 5, 8],
[1, 2, 3, 6, 7],
[1, 2, 3, 6, 8],
[1, 2, 3, 7, 8],
[1, 2, 4, 5, 6],
[1, 2, 4, 5, 7],
[1, 2, 4, 5, 8],
[1, 2, 4, 6, 7],
[1, 2, 4, 6, 8],
[1, 2, 4, 7, 8],
[1, 3, 4, 5, 6],
[1, 3, 4, 5, 7],
[1, 3, 4, 5, 8],
[1, 3, 4, 6, 7],
[1, 3, 4, 6, 8],
[1, 3, 4, 7, 8],
[2, 3, 4, 5, 6],
[2, 3, 4, 5, 7],
[2, 3, 4, 5, 8],
[2, 3, 4, 6, 7],
[2, 3, 4, 6, 8],
[2, 3, 4, 7, 8]]
I would instead use itertools.combinations in combination with itertools.product:
from itertools import chain, combinations, product
result = list(
map(
list,
map(
chain.from_iterable,
product(
combinations([1, 2, 3, 4], 3),
combinations([5, 6, 7, 8], 2),
),
),
),
)
the repeat is going to repeat the result two times, in case anyone is wondering about it .
the product takes 1 parameter, the second is optional
for more details :
https://blog.teclado.com/python-itertools-part-1-product/

2d array python print each row with square brackets still attached python

I have a matrix:
m = [
[5, 1, 7, 5],
[2, 4, 9, 5],
[3, 4, 5, 5],
[3, 4, 6, 7]]
When I print the matrix, the output is:
[[5, 1, 7, 5], [2, 4, 9, 5], [3, 4, 5, 5], [3, 4, 6, 7]]
How do you print this matrix to where the output is the same as the initial input
like this below:
[
[5, 1, 7, 5],
[2, 4, 9, 5],
[3, 4, 5, 5],
[3, 4, 6, 7]
]
Most answers I see erase the square brackets when printing. Is there a way to do this and still have the square brackets there like I did when I first defined the 2D array?
I think it will be dependent on your console/IDE. You could try to use pprint.
>>> m
[[5, 1, 7, 5], [2, 4, 9, 5], [3, 4, 5, 5], [3, 4, 6, 7]]
>>> pprint(m, width=40)
[[5, 1, 7, 5],
[2, 4, 9, 5],
[3, 4, 5, 5],
[3, 4, 6, 7]]
Attempt at a more general approach of determining the width (not sure how this would fair for other nested lists, but works here):
pprint(m, width=len(str(m))-1)

How to swap items in a list within a list python

I am trying to randomly swap 2 items in each list within a list, where those to be swapped are not in another list.
Here is my code
import random
def swap(mylist):
remain = [[1, 2], [4], [], [8, 2], [1, 4], [5, 2, 1], [], [9, 5], [7]]
for x in range(0, 9):
remaining = set(mylist[x]) - set(remain[x])
to_swap = random.sample(remaining, 2)
mylist[x][mylist[x].index(to_swap[0])], mylist[x][mylist[x].index(to_swap[1])] = mylist[x][mylist[x].index(to_swap[1])], mylist[x][mylist[x].index(to_swap[0])]
return mylist
print(swap([[8, 5, 4, 1, 3, 9, 7, 6, 2], [9, 3, 5, 6, 4, 7, 1, 2, 8], [7, 3, 2, 5, 4, 1, 9, 6, 8], [2, 1, 3, 8, 6, 9, 5, 7, 4], [1, 2, 3, 5, 7, 4, 9, 8, 6], [6, 9, 3, 1, 7, 4, 2, 8, 5], [1, 2, 7, 4, 3, 8, 5, 9, 6], [3, 7, 8, 4, 1, 5, 9, 6, 2], [4, 2, 6, 5, 7, 1, 9, 3, 8]]))
Whenever I run this and print out the result, it just prints out my input again.
Does anyone know what is wrong with my code?
Thanks.
Your code performs the swaps with about one half of the sublists. I wonder what the reason of this behavior is *(see below).
If you rewrite the swapping part like this:
i = mylist[x].index(to_swap[0])
j = mylist[x].index(to_swap[1])
mylist[x][i], mylist[x][j] = mylist[x][j], mylist[x][i]
then it works.
UPDATE:
There is no need to access the lists on the right-hand side of the assignment, since we already know the values, so the updated answer would be:
i = mylist[x].index(to_swap[0])
j = mylist[x].index(to_swap[1])
mylist[x][i], mylist[x][j] = to_swap[1], to_swap[0]
*UPDATE 2:
The above mentioned behavior is caused by the fact that in multiple assignments, expressions on the left-hand side are evaluated one by one from left to right. That means the OP's code didn't work in cases where index(to_swap[0]) < index(to_swap[1]).
Example: values 5 and 6 in the first sublist [8, 5, 4, 1, 3, 9, 7, 6, 2]. First, the program will do
mylist[x][mylist[x].index(5)] = 6
modifying the list to [8, 6, 4, 1, 3, 9, 7, 6, 2]. Second, the program will do
mylist[x][mylist[x].index(6)] = 5
modifying it back to [8, 5, 4, 1, 3, 9, 7, 6, 2].

Create a list of list with flexible input (Python) [duplicate]

This question already has answers here:
How can I make a for-loop pyramid more concise in Python? [duplicate]
(4 answers)
Closed 5 years ago.
I currently have a function that creates a list of lists like below using 3 nested for-loops.
[[1,1,1] , [1,1,2] , .... , [3,3,3]]
However, the problem is I can't use this function if someone wants the list of list to be something like
[[1,1,1,1,1,1,1] , ..... , [9,9,9,9,9,9,9]]
which has more numbers (from 1 - 9) and more elements (7 of 1's instead of 4).
Here's my current code:
def listofList():
temp = []
for i in range(1,4):
for j in range(1,4):
for k in range(1,4):
temp.append([i,j,k])
return temp
Can someone provide me with a better solution? I want my function listofList() to be flexible where it could receive an input for both the size of the list of list and the elements inside the list.
Try the following:
def listofList(subLen, totalLen):
final = [[item for i in range(subLen)] for item in range(1, totalLen+1)]
return final
>>> listofList(9, 9)
[[1, 1, 1, 1, 1, 1, 1, 1, 1], [2, 2, 2, 2, 2, 2, 2, 2, 2], [3, 3, 3, 3, 3, 3, 3, 3, 3], [4, 4, 4, 4, 4, 4, 4, 4, 4], [5, 5, 5, 5, 5, 5, 5, 5, 5], [6, 6, 6, 6, 6, 6, 6, 6, 6], [7, 7, 7, 7, 7, 7, 7, 7, 7], [8, 8, 8, 8, 8, 8, 8, 8, 8], [9, 9, 9, 9, 9, 9, 9, 9, 9]]
>>> listofList(9, 2)
[[1, 1, 1, 1, 1, 1, 1, 1, 1], [2, 2, 2, 2, 2, 2, 2, 2, 2]]
>>> listofList(2, 9)
[[1, 1], [2, 2], [3, 3], [4, 4], [5, 5], [6, 6], [7, 7], [8, 8], [9, 9]]
>>>

Better way to get sublist in python

I am working on the following problem:
This function returns a list of all possible sublists in L of length n without skipping elements in L. The sublists in the returned list should be ordered in the way they appear in L, with those sublists starting from a smaller index being at the front of the list.
Example 1, if L = [10, 4, 6, 8, 3, 4, 5, 7, 7, 2] and n = 4 then your function should return the list [[10, 4, 6, 8], [4, 6, 8, 3], [6, 8, 3, 4], [8, 3, 4, 5], [3, 4, 5, 7], [4, 5, 7, 7], [5, 7, 7, 2]]
My solution works but how can I make it shorter? What is a better way to do this?
def getSublists(L, n):
newN = n
myList = []
for i in range(len(L)):
orginalLen = L[i:n]
if(len(orginalLen) == n):
myList.append(L[i:n])
n = n + 1
else:
myList.append(L[i:n])
n = n + 1
if(newN == 1):
print(myList)
else:
print(myList[:len(myList)-(n-1)])
getSublists([10, 4, 6, 8, 3, 4, 5, 7, 7, 2],4)
getSublists([1], 1)
getSublists([0, 0, 0, 0, 0], 2)
OUTPUT
[[10, 4, 6, 8], [4, 6, 8, 3], [6, 8, 3, 4], [8, 3, 4, 5], [3, 4, 5, 7], [4, 5, 7, 7], [5, 7, 7, 2]]
[[1]]
[[0, 0], [0, 0], [0, 0], [0, 0]]
l = [1,2,3,4,5,6,87,9]
n = ..
print [l[i:i+n] for i in range(len(l)-n+1)]
maybe you need.
In one line:
get_sublists = lambda ls, n: [ls[x:x+n] for x in range(len(ls)-n+1)]
get_sublists([10, 4, 6, 8, 3, 4, 5, 7, 7, 2], 4)
[[10, 4, 6, 8], [4, 6, 8, 3], [6, 8, 3, 4], [8, 3, 4, 5], [3, 4, 5, 7], [4, 5, 7, 7], [5, 7, 7, 2]]
def get_sublists(L, n):
return [ L[i:i+n] for i in range(len(L)-n) ]
I completed the program a little better understanding of the reader.
def getSublists(L, n):
new_list = []
for i in range(len(L)-n+1):
a = L[i:i+n]
new_list.append(a)
return new_list
answer:
[[10, 4, 6, 8],
[4, 6, 8, 3],
[6, 8, 3, 4],
[8, 3, 4, 5],
[3, 4, 5, 7],
[4, 5, 7, 7],
[5, 7, 7, 2]]
This is pretty readable I think, to understand the concept. The idea here is to iterate through the numbers from 0 to the length of L, minus 4. And just take the sublist of L from your current index i, to i+4. Iterating to length-4 ensures you don't try to access an index out of bounds!
>>> for i in range(len(L)-4+1):
print L[i:i+4]
[10, 4, 6, 8]
[4, 6, 8, 3]
[6, 8, 3, 4]
[8, 3, 4, 5]
[3, 4, 5, 7]
[4, 5, 7, 7]
[5, 7, 7, 2]

Categories

Resources