Cannot concatenate 'str' and 'int' objects python - python

I have this python program
Function:
def populate_year(self, cursor, user_id, context=None):
year_dropdown = ''
for y in range(2010, (datetime.datetime.now().year + 10)):
year_dropdown = year_dropdown + '(' + y, y + '),'
return year_dropdown
Field:
'year': fields.selection(populate_year,'Year',select=True, required=True),
I get this error:
TypeError: cannot concatenate 'str' and 'int' objects

You could convert the integer year to a string using str and then concatenate.
However, string formatting would do the type coercion for you:
>>> '({year}, {year})'.format(year=2014)
'(2014, 2014)'
You can also join together strings with a separator:
>>> ','.join(['a', 'b', 'c'])
'a,b,c'
Altogether:
this_year = datetime.datetime.now().year
year_dropdown = ','.join('{year}, {year}'.format(year=year)
for year in range(2010, this_year + 10)

You've got 2 problems in this line:
year_dropdown = year_dropdown + '(' + y, y + '),'
One is that you used ... + ... , ... + ... - did you want to use a plus sign there? Or quote the , part?
The other, which is where you see the error, is that year_dropdown is a string and y is an int. You can use str(y) instead in this case.

use str(y) instead of y in for loop
for y in range(2010, (datetime.datetime.now().year + 10)):
year_dropdown = year_dropdown + '(' + str(y), str(y) + '),' # use str(y)
'(' + y, y + '),' here you are concatinating string and int (y)
see what you doing
at first iteration y=2010
'(' + 2010, 2010 + '),'
you are concatinating string with y which is an int value.

Related

pandas iterate over column values at once and generate range

I have a pandas dataframe like as below
df1 = pd.DataFrame({'biz': [18, 23], 'seg': [30, 34], 'PID': [40, 52]})
I would like to do the below
a) pass all the values from each column at once to for loop
For ex:
I am trying the below
cols = ['biz','seg','PID']
for col in cols:
for i, j in df1.col.values:
print("D" + str(i) + ":" + "F" + str(j))
print("Q" + str(i) + ":" + "S" + str(j))
print("AB" + str(i) + ":" + "AD" + str(j))
but this doesn;t work and I get an error
TypeError: cannot unpack non-iterable numpy.int64 object
I expect my output to be like as below
D18:F23
Q18:S23
AB18:AD23
D30:F34
Q30:S34
AB30:AD34
D40:F52
Q40:S52
AB40:AD52
The mistake is in the innermost forloop.
You are requesting an iterator over a 1-dimensional array of values, this iterator yields scalar values and hence they can not be unpacked.
If your dataframe only has 2 items per column, then this should suffice
cols = ['biz','seg','PID']
for col in cols:
i, j = getattr(df1, col).values
print("D" + str(i) + ":" + "F" + str(j))
print("Q" + str(i) + ":" + "S" + str(j))
print("AB" + str(i) + ":" + "AD" + str(j))
Alternatives
Pandas using loc
This is actually the simplest way to solve it but only now it occurred to me. We use the column name col along with loc to get all rows (given by : in loc[:, col])
cols = ['biz','seg','PID']
for col in cols:
i, j = df1.loc[:, col].values
Attrgetter
We can use the attrgetter object from operator library to get a single (or as many attributes) as we want:
from operator import attrgetter
cols = ['biz','seg','PID']
cols = attrgetter(*cols)(df1)
for col in cols:
i, j = col.values
Attrgetter 2
This approach is similar to the one above, except that we select multiple columns and have the i and j in two lists, with each entry corresponding to one column.
from operator import attrgetter
cols = ['biz','seg','PID']
cols = attrgetter(*cols)(df1)
cols = [col.values for col in cols]
all_i, all_j = zip(*cols)
Pandas solution
This approach uses just pandas functions. It gets the column index using the df1.columns.get_loc(col_name) function, and then uses .iloc to index the values. In .iloc[a,b] we use : in place of a to select all rows, and index in place of b to select just the column.
cols = ['biz','seg','PID']
for col in cols:
index = df1.columns.get_loc(col)
i, j = df1.iloc[:, index]
# do the printing here
for i in range(len(df1)):
print('D' + str(df1.iloc[i,0]) + ':' + 'F' + str(df1.iloc[i+1,0]))
print('Q' + str(df1.iloc[i,0]) + ':' + 'S' + str(df1.iloc[i+1,0]))
print('AB' + str(df1.iloc[i,0]) + ':' + 'AD' + str(df1.iloc[i+1,0]))
print('D' + str(df1.iloc[i,1]) + ':' + 'F' + str(df1.iloc[i+1,1]))
print('Q' + str(df1.iloc[i,1]) + ':' + 'S' + str(df1.iloc[i+1,1]))
print('AB' + str(df1.iloc[i,1]) + ':' + 'AD' + str(df1.iloc[i+1,1]))
print('D' + str(df1.iloc[i,2]) + ':' + 'F' + str(df1.iloc[i+1,2]))
print('Q' + str(df1.iloc[i,2]) + ':' + 'S' + str(df1.iloc[i+1,2]))
print('AB' + str(df1.iloc[i,2]) + ':' + 'AD' + str(df1.iloc[i+1,2]))

Create string from vector

I have a numeric vector. I want to enumerate over the vector and create a string as the result. For example, if I have a vector
x = c(1, 3)
I want the resulting string to be:
y = '1x1 + 3x2'
In Python, I would do this:
l = [1, 3]
equation = ' + '.join(['{}x{}'.format(coef, i + 1) for i, coef in enumerate(l)])
str = 'y = {}'.format(equation)
How can the same thing be done in R?
You can do this:
x <- c(1, 3)
paste0(x, substitute(x), seq_along(x), collapse = " + ")
# [1] "1x1 + 3x2"
Explanation:
Get object name: substitute(x) (this returns "x")
Attach object name ("x") to x values and x index seq_alon(x) using paste0() with collapse = " + " argument.

Moving object in list

I made a list like this:
mapxy = [[0 for x in range(16)] for x in range(16)]
and I add object from another normal list like this:
for y in range(0, 16):
for x in range(0, 16):
mapxy[x][y] = mapList[o]
Then I want to move one object in the list both down and just change the first index moving it left and right in the list mapxy[x+1][y]
mapxy.pop(f_pos_x)
mapxy.insert(f_pos_x + 1, ["1"])
f_pos_x += 1
(this didn't work quite as I wanted it too, it ended up in-between/created another list inside the first list instead of inserting in the inner list like I wanted it to.)
but also up and down on y: mapxy[x][y+1].
How I want it to look:
Original
mapxy = [[" ", " ", "1"," "][" ", " ", " "," "][" ", " ", " "," "][" ", " ", " "," "]]
When i press right:
mapxy = [[" ", " ", " ","1"][" ", " ", " "," "][" ", " ", " "," "][" ", " ", " "," "]]
And when I press down:
mapxy = [[" ", " ", " "," "][" ", " ", " ","1"][" ", " ", " "," "][" ", " ", " "," "]]
mapxy is a list of lists (with apparently all "cells" initialized to the single item mapList[o], which is slightly strange). So pop and insert into it would remove and respectively add a whole list at a time, not a single item.
You say you want to "move" an item but not what should take its place. If you just want to copy the item, it's clearly just:
map[x+1][y] = map[x][y]
but if the previous map[x][y] must be filled w/something else you'll then have to assign to that, too, of course. Exactly the same for "moving" along y rather than along x.
Use a dictionary with a tuple as key:
map = {}
for x in range(16):
for y in range(16):
map[x, y] = 0
Actually, you could avoid the initialization and check whether an element is set or use a default value. Concerning this default value, consider None, too. With this dict, you can "move" elements easily:
map[1, 2] = 42
v = map.pop((1, 2))
map[3, 4] = v
Here is the full script that I think does what you want. But before I just paste it and run away, there two things worth saying. 1. You need to swap items in-place. 2. You need to cater for the out of range index errors.
To first i envisaged using a deque of deques with maxlen field set. deque is available from the collections library. So to shift left, you pop at the right and insert at the left and to shift to the right you pop at the left and append at the right. But then I had another idea.
You stick with the list of lists, you swap items in-place and avoid out of range errors by the new computed index is within the set of non-negative integers modulo length of the list containing the item.
Enough talking. To swap in-place in python, given:
x = [8, 21, 100, 9, 5]
You do:
x[2], x[3] = x[3], x[2]
Resulting in:
x = [8, 21, 9, 100, 5]
The script below keeps track of two indices, x corresponds to the index of the item, the string, being moved left and right and y corresponds to the index of the inner list item containing the the item to be moved left and right (the inner list itself is moved up and down). By index i mean position. So x points to the string, y points to the list.
To move up and down the containing list, you only need to know the index of the list to move, y. To move left and right the item (the string), you need to know both the containing list index y and the item index x.
#!/usr/bin/python
from collections import deque
def move_dowm(data, y):
old_y = y
y = (y + 1) % len(data)
data[old_y], data[y] = data[y], data[old_y]
return y
def move_up(data, y):
old_y = y
y = (y - 1) % len(data)
data[old_y], data[y] = data[y], data[old_y]
return y
def move_right(data, x, y):
old_x = x
x = (x + 1) % len(data[y])
data[y][old_x], data[y][x] = data[y][x], data[y][old_x]
return x
def move_left(data, x, y):
old_x = x
x = (x - 1) % len(data[y])
data[y][old_x], data[y][x] = data[y][x], data[y][old_x]
return x
if __name__ == '__main__':
dataset = [
[' ', ' ', ' ', ' '],
['1', ' ', ' ', ' '],
[' ', ' ', ' ', ' '],
[' ', ' ', ' ', ' '],
]
x, y = 0, 1
print dataset
print '-' * 90
y = move_up(dataset, y)
print dataset
print '-' * 90
y = move_dowm(dataset, y)
print dataset
print '-' * 90
x = move_left(dataset, x, y)
print dataset
print '-' * 90
x = move_right(dataset, x, y)
print dataset
print

Python won't convert tuple to string

so the below code is supposed to take the first element in the resulting tuple of x and convert it to a string to be used. However, when executing the last line it tells me it can't convert from tuple to str.
for x in filelink:
print(x[0])
item = str(x[0])
oldpath = root.wgetdir + "\\" + root.website.get() + "\\" + item
print(oldpath)
if os.path.exists(oldpath): shutil.copy(root.wgetdir + "\\" + root.website.get() + "\\" + x, keyworddir + "\\" + item)
This part:
root.wgetdir + "\\" + root.website.get() + "\\" + x
right here ^
is using the tuple instead of item.

Organize dictionary by frequency

I create a dictionary for the most used words and get the top ten. I need to sort this for the list, which should be in order. I can't do that without making a list, which I can't use. Here is my code. I am away dictionaries cannot be sorted, but i still need help.
most_used_words = Counter()
zewDict = Counter(most_used_words).most_common(10)
newDict = dict(zewDict)
keys = newDict.keys()
values = newDict.values()
msg = ('Here is your breakdown of your most used words: \n\n'
'Word | Times Used'
'\n:--:|:--:'
'\n' + str(keys[0]).capitalize() + '|' + str(values[0]) +
'\n' + str(keys[1]).capitalize() + '|' + str(values[1]) +
'\n' + str(keys[2]).capitalize() + '|' + str(values[2]) +
'\n' + str(keys[3]).capitalize() + '|' + str(values[3]) +
'\n' + str(keys[4]).capitalize() + '|' + str(values[4]) +
'\n' + str(keys[5]).capitalize() + '|' + str(values[5]) +
'\n' + str(keys[6]).capitalize() + '|' + str(values[6]) +
'\n' + str(keys[7]).capitalize() + '|' + str(values[7]) +
'\n' + str(keys[8]).capitalize() + '|' + str(values[8]) +
'\n' + str(keys[9]).capitalize() + '|' + str(values[9]))
r.send_message(user, 'Most Used Words', msg)
How would I do it so the msg prints the words in order from most used word on the top to least on the bottom with the correct values for the word?
Edit: I know dictionaries cannot be sorted on their own, so can I work around this somehow?
Once you have the values it's as simple as:
print('Word | Times Used')
for e, t in collections.Counter(values).most_common(10):
print("%s|%d" % (e,t))
Print something like:
Word | Times Used
e|4
d|3
a|2
c|2
From the Docs: most_common([n])
Return a list of the n most common elements and their counts from the
most common to the least. If n is not specified, most_common() returns
all elements in the counter. Elements with equal counts are ordered
arbitrarily:
>>> Counter('abracadabra').most_common(3)
[('a', 5), ('r', 2), ('b', 2)]
Your code can be:
from collections import Counter
c = Counter(most_used_words)
msg = "Here is your breakdown of your most used words:\n\nWords | Times Used\n:--:|:--:\n"
msg += '\n'.join('%s|%s' % (k.capitalize(), v) for (k, v) in c.most_common(10))
r.send_message(user, 'Most Used Words', msg)
import operator
newDict = dict(zewDict)
sorted_newDict = sorted(newDict.iteritems(), key=operator.itemgetter(1))
msg = ''
for key, value in sorted_newDict:
msg.append('\n' + str(key).capitalize() + '|' + str(value))
This will sort by the dictionary values. If you want it in the other order add reverse=True to sorted().

Categories