Trinomial triangle (Python) - python

As part of my interest in learning Python, I've hit a stop when coming across an exercise that states:
Consider the expression (1 + x + x^2)^n and write a program which
calculates a modified Pascal’s triangle (known as the trinomial
triangle) for the coefficients of its expansion. Can you come up with
a simple rule (and prove that it works!) which would enable you to
write down the coefficients of this triangle?
So, I'm trying to write a code that prints out the trinomial triangle from a user input. This is the code I have so far:
import math
rows = 0 #We count how many rows we print
#We define a function that will calculate the triangle.
def calc(n, r):
if r == 0 or r == n:
return 1
return int(math.pow(1 + r + math.pow(r, 2), n))
#We define a function that append the values in an array.
def triangle(rows):
result = [] #We need an array to collect our results.
for count in range(rows): #For each count in the inputted rows
row = [] #We need a row element to collect the rows.
for element in range(count + 1):
#We add the function calculation to the row array.
row.append(calc(count, element))
#We add the row(s) to the result array.
result.append(row)
return result
number = int(input("How many rows do you want printed? "))
#We can now print the results:
for row in triangle(number):
rows += 1 #We add one count to the amount of rows
print("Row %d: %s" % (rows, row)) #Print everything
which returns
How many rows do you want printed? 5
Row 1: [1]
Row 2: [1, 1]
Row 3: [1, 9, 1]
Row 4: [1, 27, 343, 1]
Row 5: [1, 81, 2401, 28561, 1]
And as I understand it, the expected result should be:
1
1 1 1
1 2 3 2 1
1 3 6 7 6 3 1
1 4 10 16 19 16 10 4 1
I don't exactly know how to proceed from here. Any suggestions to point me in the right direction would be appreciated.

In the usual binomial version of Pascal's Triangle we can compute each value in a row by adding the two entries immediately above it. In the trinomial version we add three entries. The proof of this isn't hard, so I'll let you figure it out. ;)
Here's one way to do that in Python.
row = [1]
for i in range(8):
print(row)
row = [sum(t) for t in zip([0,0]+row, [0]+row+[0], row+[0,0])]
output
[1]
[1, 1, 1]
[1, 2, 3, 2, 1]
[1, 3, 6, 7, 6, 3, 1]
[1, 4, 10, 16, 19, 16, 10, 4, 1]
[1, 5, 15, 30, 45, 51, 45, 30, 15, 5, 1]
[1, 6, 21, 50, 90, 126, 141, 126, 90, 50, 21, 6, 1]
[1, 7, 28, 77, 161, 266, 357, 393, 357, 266, 161, 77, 28, 7, 1]

And just so that the line that I want to show appears as for example income 2 only shows me the second line of the triangle that is 1 1 1

Related

Use different list values in order to do the same sum with each

Please help, I need to have a moving value in my code based upon a list!
I have a list, the list is as follows:
my_list = [1, 2, 2, 3, 5, 6, 7, 7, 9, 10]
I have a part of my code which uses this list in order to do a sum, this is as follows:
val = my_list[0]+1
ans = val*9
What I want is to have val be replaced by each of the numbers in my_list i.e. the first time it would be 1x9 and then the next 2x9. However, I cannot find anywhere how to do this.
val = my_list[x]
val += 1
ans = val * 9
x += 1
this way you can just run your code, then add 1 to x
move the x += 1 line to whereever you want
Is your ans a list?
Do "(x+1)*9" for each elements?
ans = [(x+1)*9 for x in my_list]
What you want is vectorization - for which you can use the numpy package:
import numpy as np
my_list = [1, 2, 2, 3, 5, 6, 7, 7, 9, 10]
my_np_list = np.array(my_list)
ans = 9 * my_np_list
# vectorization applies to each element of my_np_list in parallel
# the `9 *` calculation.
## ans contains:
## array([ 9, 18, 18, 27, 45, 54, 63, 63, 81, 90])
## you can sum accross ans by the .sum() method
ans.sum() ## 468
It is as if you do:
ans = []
for x in my_list:
ans.append(9 * x)

Python: printing 1 row of Pascal Triangle

New to learning python and am having some trouble understanding a solution provided?
It has to do with Pascal Triangle and printing the rows when asking a user to "enter a row number"
There were bits of the solution provided and the rest I fit in (first for loop)..
n=int(input("Enter a row number: "))
a=[]
for i in range(n):
a.append([])
a[i].append(1)
for j in range(1,i):
a[i].append(a[i-1][j-1]+a[i-1][j])
if(n!=0):
a[i].append(1)
for i in range(n):
print(" "*(n-i),end=" ",sep=" ")
for j in range(0,i+1):
print('{:4}'.format(a[i][j]),end=" ")
print()
My question is which part of the code is printing the triangle structure? I assume the last for loop?
Also if I wanted to just print 1 row, what would I be changing?
EX: Input: 5 and output would be [1 4 6 4 1 ]
Thank you and any help/advice would be appreciated
You are right, the last loop is printing every row of the triangle. To print any specific row, jut run the second loop with specific value of i.
Before that, there is an easier way to more forward. Let's consider the output of below code:
n = 7
a = []
for i in range(n):
a.append([])
a[i].append(1)
for j in range(1, i):
a[i].append(a[i - 1][j - 1] + a[i - 1][j])
if (n != 0):
a[i].append(1)
print(a)
The output is:
[[1, 1], [1, 1], [1, 2, 1], [1, 3, 3, 1], [1, 4, 6, 4, 1], [1, 5, 10, 10, 5, 1], [1, 6, 15, 20, 15, 6, 1]]
From this 2d array, you can decide which single element you want to print. For example at index 4 you have [1, 4, 6, 4, 1]. From these values in the array a you can figure out which row to print.
Now for 5 if you want [1, 4, 6, 4, 1], you can simply do the following:
n = 7
a = []
for i in range(n):
a.append([])
a[i].append(1)
for j in range(1, i):
a[i].append(a[i - 1][j - 1] + a[i - 1][j])
if (n != 0):
a[i].append(1)
to_print = 5
for i in range(0, len(a[to_print-1])):
print(a[to_print-1][i], end=" ")
The output will be:
1 4 6 4 1
#riam_98, would you like to try this version: It's simplified the logic/flow to take advantage of Pascal key characteristics.
More reading can be found here - https://en.wikipedia.org/wiki/Pascal's_triangle
from typing import List
def getRow(index: int) -> List[int]:
row = [1] # firsts row
if index == 1: return row
for i in range(index-1):
for j in range(i, 0, -1):
row[j] = row[j] + row[j-1]
row.append(1)
return row
print(getRow(2))
print(getRow(3))
print(getRow(4))
print(getRow(5))
Outputs:
[1, 1]
[1, 2, 1]
[1, 3, 3, 1]
[1, 4, 6, 4, 1] # 5th
if I wanted to just print 1 row, what would I be changing?
I believe the answers given (and accepted) so far do too much work to obtain the values for an individual row. If we look at Calculating a row or diagonal by itself in the Wikipedia page that #DanielHao recommends, we can generate a simpler solution:
n = int(input("Enter a row number: "))
numbers = [1]
for k in range(1, n):
numbers.append(numbers[-1] * (n - k) // k)
print(numbers)
We don't need to generate the entire triangle up to the row we desire nor use nested loops to calculate it.
OUTPUT
> python3 test.py
Enter a row number: 5
[1, 4, 6, 4, 1]
> python3 test.py
Enter a row number: 10
[1, 9, 36, 84, 126, 126, 84, 36, 9, 1]
>
which part of the code is printing the triangle structure? I assume
the last for loop?
Yes, but note that it is a fragile, limited solution due to the hardcoding of the number width:
print('{:4}'.format(a[i][j]),end=" ")
For smaller values, the triangle is lopsided, and for values larger than 16, it loses all its symmetry. Here's an example of a Pascal's triangle output that self adjusts Compare it's output to the solution you're asking about.

How to print this number pattern in python? [duplicate]

As a learning experience for Python, I am trying to code my own version of Pascal's triangle. It took me a few hours (as I am just starting), but I came out with this code:
pascals_triangle = []
def blank_list_gen(x):
while len(pascals_triangle) < x:
pascals_triangle.append([0])
def pascals_tri_gen(rows):
blank_list_gen(rows)
for element in range(rows):
count = 1
while count < rows - element:
pascals_triangle[count + element].append(0)
count += 1
for row in pascals_triangle:
row.insert(0, 1)
row.append(1)
pascals_triangle.insert(0, [1, 1])
pascals_triangle.insert(0, [1])
pascals_tri_gen(6)
for row in pascals_triangle:
print(row)
which returns
[1]
[1, 1]
[1, 0, 1]
[1, 0, 0, 1]
[1, 0, 0, 0, 1]
[1, 0, 0, 0, 0, 1]
[1, 0, 0, 0, 0, 0, 1]
[1, 0, 0, 0, 0, 0, 0, 1]
However, I have no idea where to go from here. I have been banging my head against the wall for hours. I want to emphasize that I do NOT want you to do it for me; just push me in the right direction. As a list, my code returns
[[1], [1, 1], [1, 0, 1], [1, 0, 0, 1], [1, 0, 0, 0, 1], [1, 0, 0, 0, 0, 1], [1, 0, 0, 0, 0, 0, 1], [1, 0, 0, 0, 0, 0, 0, 1]]
Thanks.
EDIT: I took some good advice, and I completely rewrote my code, but I am now running into another problem. Here is my code.
import math
pascals_tri_formula = []
def combination(n, r):
return int((math.factorial(n)) / ((math.factorial(r)) * math.factorial(n - r)))
def for_test(x, y):
for y in range(x):
return combination(x, y)
def pascals_triangle(rows):
count = 0
while count <= rows:
for element in range(count + 1):
[pascals_tri_formula.append(combination(count, element))]
count += 1
pascals_triangle(3)
print(pascals_tri_formula)
However, I am finding that the output is a bit undesirable:
[1, 1, 1, 1, 2, 1, 1, 3, 3, 1]
How can I fix this?
OK code review:
import math
# pascals_tri_formula = [] # don't collect in a global variable.
def combination(n, r): # correct calculation of combinations, n choose k
return int((math.factorial(n)) / ((math.factorial(r)) * math.factorial(n - r)))
def for_test(x, y): # don't see where this is being used...
for y in range(x):
return combination(x, y)
def pascals_triangle(rows):
result = [] # need something to collect our results in
# count = 0 # avoidable! better to use a for loop,
# while count <= rows: # can avoid initializing and incrementing
for count in range(rows): # start at 0, up to but not including rows number.
# this is really where you went wrong:
row = [] # need a row element to collect the row in
for element in range(count + 1):
# putting this in a list doesn't do anything.
# [pascals_tri_formula.append(combination(count, element))]
row.append(combination(count, element))
result.append(row)
# count += 1 # avoidable
return result
# now we can print a result:
for row in pascals_triangle(3):
print(row)
prints:
[1]
[1, 1]
[1, 2, 1]
Explanation of Pascal's triangle:
This is the formula for "n choose k" (i.e. how many different ways (disregarding order), from an ordered list of n items, can we choose k items):
from math import factorial
def combination(n, k):
"""n choose k, returns int"""
return int((factorial(n)) / ((factorial(k)) * factorial(n - k)))
A commenter asked if this is related to itertools.combinations - indeed it is. "n choose k" can be calculated by taking the length of a list of elements from combinations:
from itertools import combinations
def pascals_triangle_cell(n, k):
"""n choose k, returns int"""
result = len(list(combinations(range(n), k)))
# our result is equal to that returned by the other combination calculation:
assert result == combination(n, k)
return result
Let's see this demonstrated:
from pprint import pprint
ptc = pascals_triangle_cell
>>> pprint([[ptc(0, 0),],
[ptc(1, 0), ptc(1, 1)],
[ptc(2, 0), ptc(2, 1), ptc(2, 2)],
[ptc(3, 0), ptc(3, 1), ptc(3, 2), ptc(3, 3)],
[ptc(4, 0), ptc(4, 1), ptc(4, 2), ptc(4, 3), ptc(4, 4)]],
width = 20)
[[1],
[1, 1],
[1, 2, 1],
[1, 3, 3, 1],
[1, 4, 6, 4, 1]]
We can avoid repeating ourselves with a nested list comprehension:
def pascals_triangle(rows):
return [[ptc(row, k) for k in range(row + 1)] for row in range(rows)]
>>> pprint(pascals_triangle(15))
[[1],
[1, 1],
[1, 2, 1],
[1, 3, 3, 1],
[1, 4, 6, 4, 1],
[1, 5, 10, 10, 5, 1],
[1, 6, 15, 20, 15, 6, 1],
[1, 7, 21, 35, 35, 21, 7, 1],
[1, 8, 28, 56, 70, 56, 28, 8, 1],
[1, 9, 36, 84, 126, 126, 84, 36, 9, 1],
[1, 10, 45, 120, 210, 252, 210, 120, 45, 10, 1],
[1, 11, 55, 165, 330, 462, 462, 330, 165, 55, 11, 1],
[1, 12, 66, 220, 495, 792, 924, 792, 495, 220, 66, 12, 1],
[1, 13, 78, 286, 715, 1287, 1716, 1716, 1287, 715, 286, 78, 13, 1],
[1, 14, 91, 364, 1001, 2002, 3003, 3432, 3003, 2002, 1001, 364, 91, 14, 1]]
Recursively defined:
We can define this recursively (a less efficient, but perhaps more mathematically elegant definition) using the relationships illustrated by the triangle:
def choose(n, k): # note no dependencies on any of the prior code
if k in (0, n):
return 1
return choose(n-1, k-1) + choose(n-1, k)
And for fun, you can see each row take progressively longer to execute, because each row has to recompute nearly each element from the prior row twice each time:
for row in range(40):
for k in range(row + 1):
# flush is a Python 3 only argument, you can leave it out,
# but it lets us see each element print as it finishes calculating
print(choose(row, k), end=' ', flush=True)
print()
1
1 1
1 2 1
1 3 3 1
1 4 6 4 1
1 5 10 10 5 1
1 6 15 20 15 6 1
1 7 21 35 35 21 7 1
1 8 28 56 70 56 28 8 1
1 9 36 84 126 126 84 36 9 1
1 10 45 120 210 252 210 120 45 10 1
1 11 55 165 330 462 462 330 165 55 11 1
1 12 66 220 495 792 924 792 495 220 66 12 1
1 13 78 286 715 1287 1716 1716 1287 715 286 78 13 1
1 14 91 364 1001 2002 3003 3432 3003 2002 1001 364 91 14 1
1 15 105 455 1365 3003 5005 6435 6435 5005 3003 1365 455 105 15 1
1 16 120 560 1820 4368 8008 11440 12870 11440 8008 4368 1820 560 120 16 1
1 17 136 680 2380 6188 12376 19448 24310 24310 19448 12376 6188 2380 680 136 17 1
1 18 153 816 3060 8568 18564 31824 43758 48620 43758 31824 18564 8568 3060 816 ...
Ctrl-C to quit when you get tired of watching it, it gets very slow very fast...
I know you want to implement yourself, but the best way for me to explain is to walk through an implementation. Here's how I would do it, and this implementation relies on my fairly complete knowledge of how Python's functions work, so you probably won't want to use this code yourself, but it may get you pointed in the right direction.
def pascals_triangle(n_rows):
results = [] # a container to collect the rows
for _ in range(n_rows):
row = [1] # a starter 1 in the row
if results: # then we're in the second row or beyond
last_row = results[-1] # reference the previous row
# this is the complicated part, it relies on the fact that zip
# stops at the shortest iterable, so for the second row, we have
# nothing in this list comprension, but the third row sums 1 and 1
# and the fourth row sums in pairs. It's a sliding window.
row.extend([sum(pair) for pair in zip(last_row, last_row[1:])])
# finally append the final 1 to the outside
row.append(1)
results.append(row) # add the row to the results.
return results
usage:
>>> for i in pascals_triangle(6):
... print(i)
...
[1]
[1, 1]
[1, 2, 1]
[1, 3, 3, 1]
[1, 4, 6, 4, 1]
[1, 5, 10, 10, 5, 1]
Without using zip, but using generator:
def gen(n,r=[]):
for x in range(n):
l = len(r)
r = [1 if i == 0 or i == l else r[i-1]+r[i] for i in range(l+1)]
yield r
example:
print(list(gen(15)))
output:
[[1], [1, 1], [1, 2, 1], [1, 3, 3, 1], [1, 4, 6, 4, 1], [1, 5, 10, 10, 5, 1], [1, 6, 15, 20, 15, 6, 1], [1, 7, 21, 35, 35, 21, 7, 1], [1, 8, 28, 56, 70, 56, 28, 8, 1], [1, 9, 36, 84, 126, 126, 84, 36, 9, 1], [1, 10, 45, 120, 210, 252, 210, 120, 45, 10, 1], [1, 11, 55, 165, 330, 462, 462, 330, 165, 55, 11, 1], [1, 12, 66, 220, 495, 792, 924, 792, 495, 220, 66, 12, 1], [1, 13, 78, 286, 715, 1287, 1716, 1716, 1287, 715, 286, 78, 13, 1], [1, 14, 91, 364, 1001, 2002, 3003, 3432, 3003, 2002, 1001, 364, 91, 14, 1]]
DISPLAY AS TRIANGLE
To draw it in beautiful triangle(works only for n < 7, beyond that it gets distroted. ref draw_beautiful for n>7)
for n < 7
def draw(n):
for p in gen(n):
print(' '.join(map(str,p)).center(n*2)+'\n')
eg:
draw(10)
output:
1
1 1
1 2 1
1 3 3 1
1 4 6 4 1
1 5 10 10 5 1
for any size
since we need to know the max width, we can't make use of generator
def draw_beautiful(n):
ps = list(gen(n))
max = len(' '.join(map(str,ps[-1])))
for p in ps:
print(' '.join(map(str,p)).center(max)+'\n')
example (2) :
works for any number:
draw_beautiful(100)
Here is my attempt:
def generate_pascal_triangle(rows):
if rows == 1: return [[1]]
triangle = [[1], [1, 1]] # pre-populate with the first two rows
row = [1, 1] # Starts with the second row and calculate the next
for i in range(2, rows):
row = [1] + [sum(column) for column in zip(row[1:], row)] + [1]
triangle.append(row)
return triangle
for row in generate_pascal_triangle(6):
print row
Discussion
The first two rows of the triangle is hard-coded
The zip() call basically pairs two adjacent numbers together
We still have to add 1 to the beginning and another 1 to the end because the zip() call only generates the middle of the next row
# combining the insights from Aaron Hall and Hai Vu,
# we get:
def pastri(n):
rows = [[1]]
for _ in range(1, n+1):
rows.append([1] +
[sum(pair) for pair in zip(rows[-1], rows[-1][1:])] +
[1])
return rows
# thanks! learnt that "shape shifting" data,
# can yield/generate elegant solutions.
def pascal(n):
if n==0:
return [1]
else:
N = pascal(n-1)
return [1] + [N[i] + N[i+1] for i in range(n-1)] + [1]
def pascal_triangle(n):
for i in range(n):
print pascal(i)
Beginner Python student here. Here's my attempt at it, a very literal approach, using two For loops:
pascal = [[1]]
num = int(input("Number of iterations: "))
print(pascal[0]) # the very first row
for i in range(1,num+1):
pascal.append([1]) # start off with 1
for j in range(len(pascal[i-1])-1):
# the number of times we need to run this loop is (# of elements in the row above)-1
pascal[i].append(pascal[i-1][j]+pascal[i-1][j+1])
# add two adjacent numbers of the row above together
pascal[i].append(1) # and cap it with 1
print(pascal[i])
Here is an elegant and efficient recursive solution. I'm using the very handy toolz library.
from toolz import memoize, sliding_window
#memoize
def pascals_triangle(n):
"""Returns the n'th row of Pascal's triangle."""
if n == 0:
return [1]
prev_row = pascals_triangle(n-1)
return [1, *map(sum, sliding_window(2, prev_row)), 1]
pascals_triangle(300) takes about 15 ms on a macbook pro (2.9 GHz Intel Core i5). Note that you can't go much higher without increasing the default recursion depth limit.
I am cheating from the popular fibonacci sequence solution. To me, the implementation of Pascal's triangle would have the same concept of fibonacci's. In fibonacci we use a single number at a time and add it up to the previous one. In pascal's triangle use a row at a time and add it up to the previous one.
Here is a complete code example:
>>> def pascal(n):
... r1, r2 = [1], [1, 1]
... degree = 1
... while degree <= n:
... print(r1)
... r1, r2 = r2, [1] + [sum(pair) for pair in zip(r2, r2[1:]) ] + [1]
... degree += 1
Test
>>> pascal(3)
[1]
[1, 1]
[1, 2, 1]
>>> pascal(4)
[1]
[1, 1]
[1, 2, 1]
[1, 3, 3, 1]
>>> pascal(6)
[1]
[1, 1]
[1, 2, 1]
[1, 3, 3, 1]
[1, 4, 6, 4, 1]
[1, 5, 10, 10, 5, 1]
Note: to have the result as a generator, change print(r1) to yield r1.
# call the function ! Indent properly , everything should be inside the function
def triangle():
matrix=[[0 for i in range(0,20)]for e in range(0,10)] # This method assigns 0's to all Rows and Columns , the range is mentioned
div=20/2 # it give us the most middle columns
matrix[0][div]=1 # assigning 1 to the middle of first row
for i in range(1,len(matrix)-1): # it goes column by column
for j in range(1,20-1): # this loop goes row by row
matrix[i][j]=matrix[i-1][j-1]+matrix[i-1][j+1] # this is the formula , first element of the matrix gets , addition of i index (which is 0 at first ) with third value on the the related row
# replacing 0s with spaces :)
for i in range(0,len(matrix)):
for j in range(0,20):
if matrix[i][j]==0: # Replacing 0's with spaces
matrix[i][j]=" "
for i in range(0,len(matrix)-1): # using spaces , the triangle will printed beautifully
for j in range(0,20):
print 1*" ",matrix[i][j],1*" ", # giving some spaces in two sides of the printing numbers
triangle() # calling the function
would print something like this
1
1 1
1 2 1
1 3 3 1
1 4 6 4 1
Here is a simple way of implementing the pascal triangle:
def pascal_triangle(n):
myList = []
trow = [1]
y = [0]
for x in range(max(n,0)):
myList.append(trow)
trow=[l+r for l,r in zip(trow+y, y+trow)]
for item in myList:
print(item)
pascal_triangle(5)
Python zip() function returns the zip object, which is the iterator of tuples where the first item in each passed iterator is paired together, and then the second item in each passed iterator are paired together. Python zip is the container that holds real data inside.
Python zip() function takes iterables (can be zero or more), makes an iterator that aggregates items based on the iterables passed, and returns the iterator of tuples.
I did this when i was working with my son on intro python piece. It started off as rather simple piece, when we targeted -
1
1 2
1 2 3
1 2 3 4
However, as soon as we hit the actual algorithm, complexity overshot our expectations. Anyway, we did build this -
1
1 1
1 2 1
1 3 3 1
1 4 6 4 1
1 5 10 10 5 1
1 6 15 20 15 6 1
Used some recursion -
def genRow(row:list) :
# print(f"generatig new row below {row}")
# printRow(row)
l = len(row) #2
newRow : list = []
i = 0
# go through the incoming list
while i <= l:
# print(f"working with i = {i}")
# append an element in the new list
newRow.append(1)
# set first element of the new row to 1
if i ==0:
newRow[i] = 1
# print(f"1:: newRow = {newRow}")
# if the element is in the middle somewhere, add the surroundng two elements in
# previous row to get the new element
# e.g. row 3[2] = row2[1] + row2[2]
elif i <= l-1:
# print(f"2:: newRow = {newRow}")
newRow[i] = row[i-1] + row[i]
else:
# print(f"3 :: newRow = {newRow}")
newRow[i] = 1
i+=1
# print(newRow)
return newRow
def printRow(mx : int, row:list):
n = len(row)
spaces = ' ' *((mx - n)*2)
print(spaces,end=' ')
for i in row:
print(str(i) + ' ',end = ' ')
print(' ')
r = [1,1]
mx = 7
printRow(mx,[1])
printRow(mx,r)
for a in range(1,mx-1):
# print(f"working for Row = {a}")
if len(r) <= 2:
a1 = genRow(r)
r=a1
else:
a2 = genRow(a1)
a1 = a2
printRow(mx,a1)
Hopefully it helps.

Packing a small number of packages into a fixed number of bins

I have a list of package sizes. There will be a maximum of around 5 different sizes and they may occur a few times (<50).
packages = [5,5,5,5,5,5,10,11]
I need to pack them into a fixed number of bins, for example 3.
number_of_bins = 3
The bins may vary in size (sum of the sizes of the packed packages) between 0 and, say, 2 (that is, the difference of the sum of the sizes of the packages in the bins must be equal or nearly equal). So having bins with [1,2] (=3) and [2] (=2) (difference is 1) is fine, having them with [10] (=10) and [5] (=5) (difference is 5) is not.
It is possible not to sort all packages into the bins, but I want the solution where a minimum number of packages remains unpacked.
So the best solution in this case (I think) would be
bins = [11,5],[10,5],[5,5,5]
remaining = [5]
There's probably a knapsack or bin-packing algorithm to do this, but I haven't found it. I'm fine with brute-forcing it, but I'm not sure what's an efficient way to do that.
Is there any efficient way of doing this easily? Did I just miss the relevant search term to find it?
Another example:
packages = [5,10,12]
number_of_bins = 2
leads to
bins = [12],[10]
remaining = [5]
because
bins = [12],[10,5]
has bin sizes of 12 and 15 which vary by more than 2.
Analog:
packages = [2,10,12]
number_of_bins = 3
leads to
bins = [2],[],[]
remaining = [12,10]
Here is a solution using pulp:
from pulp import *
packages = [18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 65, 65, 65]
number_of_bins = 3
bins = range(1, number_of_bins + 1)
items = range(0, len(packages))
x = LpVariable.dicts('x',[(i,b) for i in items for b in bins],0,1,LpBinary)
y = LpVariable('y', 0, 2, LpInteger)
prob=LpProblem("bin_packing",LpMinimize)
#maximize items placed in bins
prob.setObjective(LpAffineExpression([(x[i,b], -3) for i in items for b in bins] + [(y, 1)]))
#every item is placed in at most 1 bin
for i in items:
prob+= lpSum([x[i,b] for b in bins]) <= 1
for b in bins:
if b != 1: # bin 1 is the one with lowest sum
prob+= LpAffineExpression([(x[i,b], packages[i]) for i in items] + [(x[i,1], -packages[i]) for i in items]) >= 0
if b != number_of_bins: # last bin is the one with highest
prob+= LpAffineExpression([(x[i,number_of_bins], packages[i]) for i in items] + [(x[i,b], -packages[i]) for i in items]) >= 0
#highest sum - lowest sum <= 2 so every difference of bin sums must be under 2
prob += LpAffineExpression([(x[i,number_of_bins], packages[i]) for i in items] + [(x[i,1], -packages[i]) for i in items]) <= 2
prob += LpAffineExpression([(x[i,number_of_bins], packages[i]) for i in items] + [(x[i,1], -packages[i]) for i in items]) == y
prob.solve()
print(LpStatus[prob.status])
for b in bins:
print(b,':',', '.join([str(packages[i]) for i in items if value(x[i,b]) !=0 ]))
print('left out: ', ', '.join([str(packages[i]) for i in items if sum(value(x[i,b]) for b in bins) ==0 ]))
Tricky one, really not sure about an optimal solution. Below is a solution that just iterates all possible groups and halts at the first solution. This should be a minimal-remainder solution since we first iterate through all solutions without any remainder.
It also iterates over solutions as everything in the first bin, which could be excluded for a faster result.
import numpy as np
def int_to_base_list(x, base, length):
""" create a list of length length that expresses a base-10 integer
e.g. binary: int2list(101, 2, 10) returns array([0, 0, 0, 1, 1, 0, 0, 1, 0, 1])
"""
placeholder = np.array([0] * length) # will contain the actual answer
for i in reversed(range(length)):
# standard base mathematics, see http://www.oxfordmathcenter.com/drupal7/node/18
placeholder[i] = x % base
x //= base
return placeholder
def get_groups(packages, max_diff_sum, number_of_bins):
""" Get number_of_bins packaging groups that differ no more than max_diff_sum
e.g.
[5, 5, 5, 5, 5, 5, 10, 11] with 2, 3 gives [5,5,5], [10,5], [11,5]
[5, 10, 12] with 2, 2 gives [10], [12]
[2, 6, 12] with 2, 3 gives [2], [], []
We approach the problem by iterating over group indices, so the first
example above has solution [0 0 0 1 2 3 1 2] with the highest number being
the 'remainder' group.
"""
length = len(packages)
for i in range((number_of_bins + 1)**length - 1): # All possible arrangements in groups
index = int_to_base_list(i, number_of_bins + 1, length) # Get the corresponding indices
sums_of_bins = [np.sum(packages[index==ii]) for ii in range(number_of_bins)]
if max(sums_of_bins) - min(sums_of_bins) <= max_diff_sum: # the actual requirement
# print(index)
break
groups = [packages[index==ii] for ii in range(number_of_bins)]
# remainder = packages[index==number_of_bins+1]
return groups
On your examples:
packages = np.array([5, 5, 5, 5, 5, 5, 10, 11])
max_diff_sum = 2
number_of_bins = 3
get_groups(packages, max_diff_sum, number_of_bins)
>> [array([5, 5, 5]), array([ 5, 10]), array([ 5, 11])]
And
packages = np.array([5,10,12])
max_diff_sum = 2
number_of_bins = 2
get_groups(packages, max_diff_sum, number_of_bins)
>> [array([10]), array([12])]

Python "Arrays and Restrictions"

QUESTION:
Write the python code which does the following:
For a given array of positive numbers perform the following action:
a) Create a new array and copy the number from the first array to
the second array without copying the repeating numbers. (Second
array elements should be unique)
b) While creating second array place additional -1 integer for every 3 numbers that’s been added to the array. (After copying 5, 6, 7 from first array second array contents should be 5, 6, 7, -1)
After creating second array print it to console in a way that every
row will have only 3 elements of the second array.
Restrictions:
You are not allowed to use while loops.
You are not allowed to use [ and ] character in you code except for initialization of first and second array at the beginning of your code.
Example:
Input:
[5, 3, 20, 7, 32, 5, 2, 4, 19, 5, 45, 1, 7, 3, 2, 9, 5, 7, 6, 27, 74 ]
Resulting Array:
[5, 3, 20, -1, 7, 32, 2, -1, 4, 19, 45, -1, 1, 9, 6, -1, 27, 74]
output:
5 3 20
7 32 2
4 19 45
1 9 6
27 74
MY WORK:
A=[5,3,20,7,32,5,2,4,19,5,45,1,7,3,2,9,5,7,6,27,74]
B=[]
counter=0
n=1
for i in A:
if i not in B:
B.append(i)
counter+=1
if counter==3*n:
B.append(-1)
n+=1
print(B)
That is what i am getting as an output:
[5, 3, 20, -1, 7, 32, 2, -1, 4, 19, 45, -1, 1, 9, 6, -1, 27, 74]
I don't know how to print output as what they want without using brackets [].
I hope you can help me somehow.
You are very close! You just need to add another for loop in order to print your elements:
If i == -1 you print a new line to seperate these, if not you print the contents of the list B separated by end=" " (space character):
for i in B:
if i == -1:
# prints a new line character
# print("\n") if you need a blank line between entries
print()
else:
# end specifies how your elements will be seperated
print(i, end=" ")
Using your input, this prints:
5 3 20
7 32 2
4 19 45
1 9 6
27 74
You can iterate over arrays (and any other iterable) in Python by value in a simple for loop, thus
for element in B:
if element == -1:
print #this will just print new line marker
else:
print element, #notice the comma - it will not add new line marker
will print elements of your B container in a row, with new lines on -1 elements.
Print semantics used here assumes Python 2.X. If you are using Python 3.X then you need to change them to appropriate statements which prints new line print() and the one which does not print(element, end=' ')

Categories