Zip together n number of lists - python

I am trying to display a list in vertically sorted columns with number of columns decided by the user. I want to use zip() but I can't seem to figure out how to tell it to go through n no of lists.
#!/usr/bin/env python
import random
lst = random.sample(range(100), 30)
lst = sorted(lst)
col_size = int(raw_input('How many columns do you want?: '))
sorting = 'Vertical'
if sorting == 'Vertical':
# vertically sorted
columns = []
n = len(lst)//col_size
for i in range(0, len(lst), n):
columns.append(lst[i:i+n])
print '\nVertically Sorted:'
print columns
print zip(*columns)
This gives this result:
How many columns do you want?: 4
Vertically Sorted:
[[0, 2, 4, 11, 12, 16, 23], [24, 31, 32, 36, 41, 48, 50], [52, 54, 61, 62, 63, 64, 67], [76, 80, 81, 89, 91, 92, 94], [96, 97]]
[(0, 24, 52, 76, 96), (2, 31, 54, 80, 97)]
If I knew the number of columns (e.g. 4), I could've coded:
for c1, c2, c3, c4 in zip(columns[0], columns[1], columns[2], columns[3]):
print str(c1), str(c2).rjust(8), str(c3).rjust(8), str(c4).rjust(8)
But since I don't, how do I use zip? As you can see I tried zip(*columns) but that failed due to unequal no. of items in the last list.

Zip doesn't do what you're after because the rows are different sizes. Map will transpose when rows are uneven.
See the following with code help from Create nice column output in python.
PROGRAM
import random
lst = random.sample(range(100), 30)
lst = sorted(lst)
col_size = int(raw_input('How many columns do you want?: '))
sorting = 'Vertical'
if sorting == 'Vertical':
# vertically sorted
columns = []
n = len(lst)//col_size
for i in range(0, len(lst), n):
columns.append(lst[i:i+n])
print '\nColumns:'
columns = map(None,*columns)
print columns
print '\nVertically Sorted:'
col_width = max(len(str(word)) for row in columns for word in row) + 2 # padding
for row in columns:
print "".join(str(word).ljust(col_width) for word in row if word is not None)
OUTPUT
How many columns do you want?: 4
Columns:
[(0, 19, 45, 62, 92), (1, 24, 47, 64, 93), (5, 29, 48, 72, None), (6, 31, 50, 80, None), (9, 34, 56, 85, None), (14, 36, 58, 87, None), (15, 37, 61, 90, None)]
Vertically Sorted:
0 19 45 62 92
1 24 47 64 93
5 29 48 72
6 31 50 80
9 34 56 85
14 36 58 87
15 37 61 90

Use the grouper recipe IT.izip_longest(*[iterable]*n) to collect the items in lst into groups of size n. (See this page for a more detailed explanation of how the grouper recipe works.)
import random
import itertools as IT
# lst = random.sample(range(100), 30)
lst = range(30)
lst = sorted(lst)
col_size = int(raw_input('How many columns do you want?: '))
sorting = 'Vertical'
if sorting == 'Vertical':
# vertically sorted
n = len(lst)//col_size
lst = iter(lst)
columns = IT.izip_longest(*[lst]*n, fillvalue='')
print '\nVertically Sorted:'
print('\n'.join(
[''.join(map('{:4}'.format, row))
for row in IT.izip(*columns)]))
yields
0 7 14 21 28
1 8 15 22 29
2 9 16 23
3 10 17 24
4 11 18 25
5 12 19 26
6 13 20 27

Extend last list with None elements to get equal length, zip, after remove None elements from result.

Related

How can I replace pd intervals with integers in python

How can I replace pd intervals with integers
import pandas as pd
df = pd.DataFrame()
df['age'] = [43, 76, 27, 8, 57, 32, 12, 22]
age_band = [0,10,20,30,40,50,60,70,80,90]
df['age_bands']= pd.cut(df['age'], bins=age_band, ordered=True)
output:
age age_bands
0 43 (40, 50]
1 76 (70, 80]
2 27 (20, 30]
3 8 (0, 10]
4 57 (50, 60]
5 32 (30, 40]
6 12 (10, 20]
7 22 (20, 30]
now I want to add another column to replace the bands with a single number (int). but I could not
for example this did not work :
df['age_code']= df['age_bands'].replace({'(40, 50]':4})
how can I get a column looks like this?
age_bands age_code
0 (40, 50] 4
1 (70, 80] 7
2 (20, 30] 2
3 (0, 10] 0
4 (50, 60] 5
5 (30, 40] 3
6 (10, 20] 1
7 (20, 30] 2
Assuming you want to the first digit from every interval, then, you can use pd.apply to achieve what you want as follows:
df["age_code"] = df["age_bands"].apply(lambda band: str(band)[1])
However, note this may not be very efficient for a large dataframe,
To convert the column values to int datatype, you can use pd.to_numeric,
df["age_code"] = pd.to_numeric(df['age_code'])
As the column contains pd.Interval objects, use its property left
df['age_code'] = df['age_bands'].apply(lambda interval: interval.left // 10)
You can do that by simply adding a second pd.cut and define labels argument.
import pandas as pd
df = pd.DataFrame()
df['age'] = [43, 76, 27, 8, 57, 32, 12, 22]
age_band = [0,10,20,30,40,50,60,70,80,90]
df['age_bands']= pd.cut(df['age'], bins=age_band, ordered=True)
#This is the part of code you need to add
age_labels = [0, 1, 2, 3, 4, 5, 6, 7, 8]
df['age_code']= pd.cut(df['age'], bins=age_band, labels=age_labels, ordered=True)
>>> print(df)
You can create a dictionary of bins and map it to the age_bands column:
bins_sorted = sorted(pd.cut(df['age'], bins=age_band, ordered=True).unique())
bins_dict = {key: idx for idx, key in enumerate(bins_sorted)}
df['age_code'] = df.age_bands.map(bins_dict).astype(int)

finding consecutive numbers in a matrix with python numpy

I am practicing some exercises and have been going in circles trying to figure it out. The first part is to create a 5x5 matrix with NumPy giving it random values, and I’ve already solved it.
Now I need to see if the matrix, either horizontally or vertically, has consecutive numbers
(for example: The matrix of the attached image does not have consecutive numbers).
Here is there are 4 consecutive numbers in the first column:
[[50 92 78 84 36]
[51 33 94 73 32]
[52 94 35 47 9]
[53 5 60 55 67]
[83 51 56 99 18]]`
Here are 4 consecutive numbers in the last row
[[50 92 78 84 36]
[41 33 94 73 32]
[72 94 35 47 9]
[55 5 60 55 67]
[84 85 86 87 18]]"
The last step is to continue randomizing the array until you find those consecutive numbers.
Here is a naive approach to check whether each row/column of a given matrix has a given amount (4 in this case) of consecutive numbers:
import numpy as np
def has_consecutive_number(M, num_consecutive=4):
for v in np.vstack((M, M.T)): # You need to check both columns and rows
count = 1 # Record how many consecutive numbers found
current_num = 0 # Recording 1 or -1
for i in range(1, len(v)):
diff = v[i] - v[i-1]
if diff == 1: # if diff is 1
if current_num != 1: # if previous diff is not 1, reset counter
count = 1
current_num = 1
count += 1
elif diff == -1:
if current_num != -1: count = 1
current_num = -1
count += 1
else: # reset counter
current_num = 0
count = 1
if count == num_consecutive:
return True
return False
M1 = np.array([ [10, 43, 74, 32, 69],
[20, 19, 69, 83, 8],
[89, 31, 62, 61, 17],
[35, 3, 77, 22, 29],
[52, 59, 86, 55, 73] ])
print(has_consecutive_number(M1, 4))
M2 = np.array([ [10, 43, 74, 32, 69],
[20, 19, 69, 83, 8],
[89, 31, 62, 61, 17],
[35, 3, 77, 22, 29],
[52, 53, 54, 55, 73] ])
print(has_consecutive_number(M2, 4))
Output is False for first matrix and True for second matrix
False
True

Maximize consumption Energy

There are three types of foods were provided i.e. meat, cake and pizza
and N different stores selling it where, i can only pick one type of food from
each store. Also I can only buy items in A, B and C numbers where 'A' means, Meat from total 'A' number of different stores (see example). My task is
to consume food, so that i can have maximum amount of energy.
example,
10 <= number of stores <br>
5 3 2 <= out of 10 stores I can pick meat from 5 stores only. Similarly,
I can pick cake from 3 out of 10 stores...
56 44 41 1 <= Energy level of meat, cake and pizza - (56, 44, 41) for first store.<br>
56 84 45 2
40 98 49 3
91 59 73 4
69 94 42 5
81 64 80 6
55 76 26 7
63 24 22 8
81 60 44 9
52 95 11 10
So to maximize my energy, I can consume...
Meat from store numbers:
[1, 4, 7, 8, 9] => [56, 91, 55, 63, 81]
Cake from store numbers:
[3, 5, 10] => [98, 94, 95]
Pizza from store numbers:
[2, 6] => [45, 80]
This leads me to eventually obtain a maximum energy level of 758.
As I am new to dynamic programming, I tried to solve it by generating unique combinations like,
10C5 * (10-5)C3 * (10-5-3)C2 = 2520
Here is my code,
nStores = 10
a, b, c = 5, 3, 2
matrix = [
[56,44,41],
[56,84,45],
[40,98,49],
[91,59,73],
[69,94,42],
[81,64,80],
[55,76,26],
[63,24,22],
[81,60,44],
[52,95,11]
]
count = a + b + c
data = []
allOverCount = [i for i in range(count)]
def genCombination(offset, depth, passedData, reductionLevel = 3):
if (depth == 0):
first = set(data)
if reductionLevel == 3:
return genCombination(0,b,[i for i in allOverCount if i not in first], reductionLevel=2)
elif reductionLevel == 2:
return genCombination(0,c,[i for i in allOverCount if i not in first], reductionLevel=1)
elif reductionLevel == 1:
xAns = 0
for i in range(len(data)):
if i < a:
xAns += matrix[data[i]][0]
elif i < a + b:
xAns += matrix[data[i]][1]
else:
xAns += matrix[data[i]][2]
return xAns
oneData = 0
for i in range(offset, len(passedData) - depth + 1 ):
data.append(passedData[i])
oneData = max(oneData, genCombination(i+1, depth-1, passedData, reductionLevel))
del data[-1]
return oneData
passedData = [i for i in range(count)]
finalOutput = genCombination(0,a,passedData)
print(finalOutput)
I know this is not the right way to do it. How can I optimize it?
This is a solution using Linear Programming through pulp (https://pypi.org/project/PuLP) that gives me the optimal solution
Maximum energy level: 758.0
Mapping of stores per foodtype: {1: [9, 2, 4], 0: [3, 8, 0, 6, 7], 2: [1, 5]}
The performance should be better than a hand-coded exhaustive solver I think.
from collections import defaultdict
import pulp
# data
nStores = 10
a, b, c = max_stores = 5, 3, 2
matrix = [
[56, 44, 41],
[56, 84, 45],
[40, 98, 49],
[91, 59, 73],
[69, 94, 42],
[81, 64, 80],
[55, 76, 26],
[63, 24, 22],
[81, 60, 44],
[52, 95, 11]
]
# create an LP problem
lp = pulp.LpProblem("maximize energy", sense=pulp.LpMaximize)
# create the list of indices for the variables
# the variables are binary variables for each combination of store and food_type
# the variable alpha[(store, food_typeà] = 1 if the food_type is taken from the store
index = {(store, food_type) for store in range(nStores) for food_type in range(3)}
alpha = pulp.LpVariable.dicts("alpha", index, lowBound=0, cat="Binary")
# add the constrain on max stores
for food_type, n_store_food_type in enumerate(max_stores):
lp += sum(alpha[(store, food_type)] for store in range(nStores)) <= n_store_food_type
# only one food type can be taken per store
for store in range(nStores):
lp += sum(alpha[(store, food_type)] for food_type in range(3)) <= 1
# add the objective to maximise
lp += sum(alpha[(store, food_type)] * matrix[store][food_type] for store, food_type in index)
# solve the problem
lp.solve()
# collect the results
stores_for_foodtype = defaultdict(list)
for (store, food_type) in index:
# check if the variable is active
if alpha[(store, food_type)].varValue:
stores_for_foodtype[food_type].append(store)
print(f"Maximum energy level: {lp.objective.value()}")
print(f"Mapping of stores per foodtype: {dict(stores_for_foodtype)}")
It looks like a modification to knapsack would solve it.
let's define our dp table as 4-dimensional array dp[N+1][A+1][B+1][C+1]
now some cell dp[n][a][b][c] means that we have considered n shops, out of them we picked a shops for meat,
b shops for cake and c shops for pizza and it stores max energy we can have.
Transitions are easy too, from some state dp[n][a][b][c] we can move to:
dp[n+1][a][b][c] if we skip n+1 th shop
dp[n+1][a+1][b][c] if we buy
meat from shop n+1
dp[n+1][a][b+1][c] if we buy cake from shop n+1
dp[n+1][a][b][c+1] if we buy pizza from shop n+1
All that's left is to fill dp table. Sample code:
N = 10
A,B,C = 5,3,2
energy = [
[56, 44, 41],
[56, 84, 45],
[40, 98, 49],
[91, 59, 73],
[69, 94, 42],
[81, 64, 80],
[55, 76, 26],
[63, 24, 22],
[81, 60, 44],
[52, 95, 11]
]
dp = {}
for n in range(N+1):
for a in range(A+1):
for b in range(B+1):
for c in range(C+1):
dp[n,a,b,c]=0
answer = 0;
for n in range(N+1):
for a in range(A+1):
for b in range(B+1):
for c in range(C+1):
#Case 1, skip n-th shop
if (n+1,a,b,c) in dp: dp[n+1,a,b,c] = max(dp[n+1,a,b,c], dp[n,a,b,c])
#Case 2, buy meat from n-th shop
if (n+1,a+1,b,c) in dp: dp[n+1,a+1,b,c] = max(dp[n+1,a+1,b,c], dp[n,a,b,c] + energy[n][0])
#Case 3, buy cake from n-th shop
if (n+1,a,b+1,c) in dp: dp[n+1,a,b+1,c] = max(dp[n+1,a,b+1,c], dp[n,a,b,c] + energy[n][1])
#Case 4, buy pizza from n-th shop
if (n+1,a,b,c+1) in dp: dp[n+1,a,b,c+1] = max(dp[n+1,a,b,c+1], dp[n,a,b,c] + energy[n][2])
answer = max(answer,dp[n,a,b,c])
print(answer)

Print the numbers 1-100 in lines of 10 numbers

I want to print numbers 1-100 in this format
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
etc.
But I can't find out a way to do this effectively,
There are more efficient ways of doing it but seeing it looks like you are just starting out with python try using for loops to iterate through each row of 10.
for i in range(10):
for j in range(1, 11):
print(i * 10 + j, end=" ")
print()
You can try this
Code:
lst = list(range(1,11))
numrows = 5 #Decide number of rows you want to print
for i in range(numrows):
print [x+(i*10) for x in lst]
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, 25, 26, 27, 28, 29, 30]
[31, 32, 33, 34, 35, 36, 37, 38, 39, 40]
[41, 42, 43, 44, 45, 46, 47, 48, 49, 50]
I would check out how mods work in Python. Such as: How to calculate a mod b in python?
for i in range(1, 101):
print(i, end=" ")
if(i%10==0):
print("\n")
[print(i, end=" ") if i % 10 else print(i) for i in range(1, 101)]
This list comprehension is used only for its side effect (printing); the resulting list itself isn't used.

using the in operator and changing lists

Im trying to produce a table with one row with numbers increasing by one and another with the respective composites with the limit being 100 like:
Numbers----------composites
x---------------numbers 1-100 divisible by x
x+1---------------numbers 1-100 divisible by x+1 but aren't in x
x+2---------------numbers 1-100 divisible by x+2 but aren't in x or x+1 x+3---------------numbers 1-100 divisible by x+3 but aren't in x,x+1,or x+2 etc
Numbers is a permanent list that starts off as 2-100 I whittle down as I pull out every composite number within the function, at the end it should only contain prime numbers.
composites is a list I fill with composites of a certain number (2,3,4 etc) that I then wish to check with the current numbers list to make sure there are no duplicates. I print whats left, empty the list and increase the current variable by 1 and repeat.
This is the coding ive come up with, I understand its very sloppy but I literally know nothing about the subject and my professor likes us to learn trial by fire and this is what ive managed to scrounge up from the textbook. The main issue of my concern is the adding and removing of elements from certain lists
def main():
x=2
n=2
print("numbers"" ""composite")
print("------------------------")
cross_out(n,x)
def cross_out(n,x):
composites=[]
prime=[]
numbers=[]
while x<101:
numbers.append(x)
x=x+1
x=2
for x in range(2,102):
if x==101:
search=composites[0]
index=0
while index<=len(composites):
if search in numbers:
search=search+1
index=index+1
else:
if search in composites:
composites.remove(search)
else:
pass
print(n,"--->",composites)
x=2
composites=[]
n=n+1
index=0
elif x%n==0:
composites.append(x)
if x in numbers:
numbers.remove(x)
else:
pass
x=x+1
else:
x=x+1
main()
cross_out()
I think I'm understanding your description correctly, and this is what I came up with.
I used a set to keep track of the number you have added to the composites already. This makes the problem pretty simple. Also, advice when writing functions is to not overwrite your parameters. For example, in cross_out, you are doing x = <value> and n = <value> several times.
def cross_out(n,x):
composites=[]
seen = set()
numbers = range(x, 101)
primes = []
for num in numbers:
for val in numbers:
if val % num == 0 and val not in seen:
composites.append(val)
seen.add(val)
if composites:
primes.append(composites[0])
print(num,'--->',composites)
composites = []
print(primes)
def main():
print("numbers composite")
print("------------------------")
cross_out(2, 2)
main()
Sample Output
numbers composite
------------------------
2 ---> [2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 32, 34, 36, 38, 40, 42, 44, 46, 48, 50, 52, 54, 56, 58, 60, 62, 64, 66, 68, 70, 72, 74, 76, 78, 80, 82, 84, 86, 88, 90, 92, 94, 96, 98, 100]
3 ---> [3, 9, 15, 21, 27, 33, 39, 45, 51, 57, 63, 69, 75, 81, 87, 93, 99]
4 ---> []
5 ---> [5, 25, 35, 55, 65, 85, 95]
6 ---> []
7 ---> [7, 49, 77, 91]
8 ---> []
9 ---> []
10 ---> []
11 ---> [11]
12 ---> []
13 ---> [13]
14 ---> []
15 ---> []
16 ---> []
17 ---> [17]
18 ---> []
19 ---> [19]
20 ---> []
21 ---> []
22 ---> []
23 ---> [23]
24 ---> []
25 ---> []
Primes
[2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97]

Categories