Python groupby itertools method - python

I am new to python programing.I am unable to create the following code:
Define a function even_or_odd, which takes an integer as input and returns the string even and odd, if the given number is even and odd respectively.
Categorise the numbers of list n = [10, 14, 16, 22, 9, 3 , 37] into two groups namely even and odd based on above defined function.
Hint : Use groupby method of itertools module.
Iterate over the obtained groupby object and print it's group name and list of elements associated with a group.
I have tried below code:
import itertools
def even_or_odd(n):
if n%2==0:
return 'even'
else:
return 'odd'
group=[]
uniquekeys=[]
n = [10, 14, 16, 22, 9, 3 , 37]
for k,g in itertools.groupby(n, even_or_odd(n)):
groups.append(list(g))
uniquekeys.append(k)
It is giving "TypeError: unsupported operand type(s) for %: 'list' and 'int' "

When you try to pass itertools.groupby even_or_odd you call it with n. even_or_odd takes an int, but n is a list. Just change it to itertools.groupby(n, even_or_odd)
Also you append to groups when I think you mean group.

Related

what type of data do *args accept? The function works with direct input, but errors if tuples/lists variables are entered (below: "numbers")

def add_unlimited(*args):
sum = 0
for n in args:
sum += n
print(sum)
numbers = [23, 45, 23, 56]
add_unlimited(23, 45, 23, 56)
def add_unlimited(*args) accepts an arbitrary amount of arguments. Inside the function, the arguments are accessible in the form of a list, which is named args.
Note that add_unlimited([23, 45, 23, 56]) is calling the function with one argument. That argument happens to be a list, [23, 45, 23, 56]. Inside the function, this will result in args = [[23, 45, 23, 56]]. The rest of your code inside the function doesn't work if each argument is not an integer, which is why you get an error.
You can pass a single list as several arguments by using the unpacking operator *:
add_unlimited(*[23, 45, 23, 56]) is equivalent to add_unlimited(23, 45, 23, 56)
Please note that *args does not have any type restriction, unlike other static languages like Go. You can even mix tuples of lists of integers, and plain strings together. This is equivalent to type annotating it like *args: Any - signifying that each argument can be any type.
However, in this case, it looks like your function depends on each argument being a number. So I would type annotate it like *args: Number, to hint to the caller that each argument passed in should be a valid number.
Usage can be as below:
from numbers import Number
def add_unlimited(*args: Number):
sum = 0
for n in args:
sum += n
print(sum)
numbers = [23, 45, 23, 56]
add_unlimited(*numbers)
sum=0
for n in args:
sum = 0 + [23, 45, 23, 56]
you can't add a list and zero.
you probably wanted something like
for x in args:
for n in x:
sum += n

List comprehension += operator

How to convert this for loop:
smoke_ray = [18, 14]
total = 0
for i in smoke_ray:
total += i
Into a list comprehension? I tried:
smoke_ray = [18, 14]
total = 0
[total += i for i in smoke_ray]
Is the problem the += operator?
that’s where I get an error
Updated with full code:
days = [
{ "day_name": "wed",
"smoked_at": {
'15:30': 1,
'16:30': 1,
'16:50': 2,
'17:30': 1,
'18:30': 1,
'20:20': 1,
'21:30': 1,
'22:30': 1,
'25:00': 5
}
},
{ "day_name": "thurs",
"smoked_at": {
'08:15': 1,
'08:40': 1,
'09:20': 1,
'10:00': 1,
'11:20': 1,
'11:38': 1,
'12:10': 1,
'13:00': 1,
'14:26': 1,
'15:40': 1,
'17:08': 1,
'18:10': 1,
'19:30': 1,
'20:20': 1,
'22:00': 1,
'23:00': 1,
'25:00': 2
}
}
]
smoke_ray = []
for i in days:
print(i["day_name"])
smokes = i["smoked_at"].values()
smokes_day = sum(smokes)
print(smokes_day)
smoke_ray.append(i)
total = 0
for i in smoke_ray:
total += i
print(total)
When trying to convert the last for loop to a list comprehension (are you telling me it’s not a shorthand way of writing a loop? I heard it was faster)
I get this error:
File "compiler.py", line 47
[total += i for i in smoke_ray]
^
SyntaxError: invalid syntax
When trying to use sum, it just won’t work:
sum(smoke_ray)
wed
14
thurs
18
Traceback (most recent call last):
File "compiler.py", line 47, in
sum(smoke_ray)
TypeError: unsupported operand type(s) for +: 'int' and 'dict'
You don't even need a list comprehension. Just use sum:
total = sum(smoke_ray)
Looking at the code you've now added for context, I think the issue you're having isn't actually in summing the list, it's in constructing the list itself. When I run your original code, with the for loop, that also fails for me.
I think the problem is in the line smoke_ray.append(i): Here, you're appending an entire element of the dictionary (e.g: { "day_name": "...", "smoked_at": { ... } }) to the smoke_ray list. Then, it doesn't make sense to sum over values in that list, since they're dictionaries. If you wanted to add each smokes_day to the list, and then sum over those, you'd do smoke_ray.append(smoke_day) within that loop. Then, you should be able to just use sum as mentioned in other answers to sum over the list.
Edit: This isn't to say that there aren't more improvements that could be done to the code btw, a simple change that would preserve the original structure would be to change your for loop to be something like this:
total = 0
for i in days:
print(i['day_name'])
smokes = i['smoked_at'].values()
smokes_day = sum(smokes)
print(smokes_day)
total += smokes_day
print(total)
That way you can sum the values like you want within one loop, without the need to construct another list/use a list comprehension.
If you want to see the sum value list wise then you can use
import itertools
smoke_ray = [18, 14]
print(list(itertools.accumulate(smoke_ray)))
This will show you the sum of the series by element
Output
[18, 32]
List comprehension is specifically an operation to transform an input list into an output list via two actions:
transformation of each element (also known as “mapping”)
filtering based on some filtering criterion
That’s it.
The operation you want is fundamentally different: you want to accumulate the elements in a list using a given operation. This action is also known as a “reduction” and is available in the Python library via functools.reduce.
So you could write
import functools
import operator
functools.reduce(operator.add, smoke_ray)
… but this is such a common operation that there’s a shorthand for it: as mentioned, you can also just use sum(smoke_ray).
You can do it in multiple ways, since you asking here for list comprehension (although list comprehension is a bad option here, a battery option is sum(your_list) ) try this:
sum([i for i in [18, 14]])
24

Iterating over a Python generator

I'm trying to write a function that will take as input a string of intervals e.g "0-0,4-8,20-21,43-45" to produce all numbers within each of the ranges meaning: [0, 4, 5, 6, 7, 8, 20, 21, 43, 44, 45]
The exercise requires to do so using generators. I managed to parse the input through a generator but I can't do the same for populating the numbers. I'm trying to int() each number so I could leverage the range() to produce all numbers within the edges.
Here's my conceptual code - how can I produce the numbers within each interval?
def parse_ranges(arg):
arg = arg.split(",")
parsed= (line.split("-") for line in arg)
#Trying to parse each character to int to use range()
intervals= (int(i) for i in number for number in parsed)
# Even if I had the characters parsed to int, I still don't know how to produce the range
ranges = (range(interval[0],interval[1]) interval for interval in intervals)
return ranges
print(list(parse_ranges("0-0,4-8,20-21,43-45")))
def parse_ranges(arg):
arg = arg.split(",")
parsed = ((line.split("-")) for line in arg)
for pair in parsed:
yield from range(int(pair[0]), int(pair[1])+1)
print(list(parse_ranges("0-0,4-8,20-21,43-45")))
Out: [0, 4, 5, 6, 7, 8, 20, 21, 43, 44, 45]
If you want to pass values from a generator INSIDE another generator directly out to the consumer of the outer generator, you need to use the "yield from" expression. (Also, note that you need to extend the "to" end of each range by +1, since the range endpoint is not inclusive.)
Two pieces that you seem to missing are: the second argument of range() needs to be one beyond what you want; you can pass control from one generator to another via yield from:
def parse_ranges(arg):
for start, stop in (interval.split('-') for interval in arg.split(',')):
yield from range(int(start), int(stop) + 1)
print(*parse_ranges("0-0,4-8,20-21,43-45"))
OUTPUT
% python3 test.py
0 4 5 6 7 8 20 21 43 44 45
%

How to apply a dict in python to a string as opposed to a single letter

I am trying to output the alphabetical values of a user entered string, I have created a dict and this process works, but only with one letter.
If I try entering more than one letter, it returns a KeyError: (string I entered)
If I try creating a list of the string so it becomes ['e', 'x', 'a', 'm', 'p', 'l', 'e'] and I get a TypeError: unhashable type: 'list'
I cannot use the chr and ord functions (I know how to but they aren't applicable in this situation) and I have tried using the map function once I've turned it to a list but only got strange results.
I've also tried turning the list into a tuple but that produces the same error.
Here is my code:
import string
step = 1
values = dict()
for index, letter in enumerate(string.ascii_lowercase):
values[letter] = index + 1
keyw=input("Enter your keyword for encryption")
keylist=list(keyw)
print(values[keylist])
Alt version without the list:
import string
step=1
values=dict()
for index, letter in enumerate(string.ascii_lowercase):
values[letter] = index + 1
keyw=input("Enter your keyword for encryption")
print(values[keyw])
You need to loop through all the letters and map each one individually:
mapped = [values[letter] for letter in keyw]
print(mapped)
This uses a list comprehension to build the list of integers:
>>> [values[letter] for letter in 'example']
[5, 24, 1, 13, 16, 12, 5]
The map() function would do the same thing, essentially, but returns an iterator; you need to loop over that object to see the results:
>>> for result in map(values.get, 'example'):
... print(result)
5
24
1
13
16
12
5
Note that you can build your values dictionary in one line; enumerate() takes a second argument, the start value (which defaults to 0); using a dict comprehension to reverse the value-key tuple would give you:
values = {letter: index for index, letter in enumerate(string.ascii_lowercase, 1)}
You most certanly can use ord()
inp = input('enter stuff:')
# a list of the ord() value of alphabetic character
# made uppercase and subtracted 64 --> position in the alphabet
alpha_value = [ord(n.upper())-64 for n in inp if n.isalpha()]
print(alpha_value)
Test:
import string
print([ord(n.upper())-64 for n in string.ascii_lowercase if n.isalpha()])
[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]
You can write simple for loop to map alphabet to integer.
try to this.
print[(item, (values[item]))for item in keylist]

Error in int and tuple connection

I get this error:
TypeError: unsupported operand type(s) for +=: 'int' and 'tuple'
Line 37
http://pastebin.com/LhMS9Xhx
filter = [[1,1,1],[1,1,1],[1,1,1]]
activefield = [[1,2,3],[4,5,6],[7,8,9]]
newvalue = 0
newvalue+= filter[iii][jjj]*aktuellesFeld[iii][jjj]
Line 37 is
neuerGrauwert += filter[iii][jjj]*aktuellesFeld[iii][jjj]
aktuellesFeld[iii][jjj] = im.getpixel((...)) is a tuple such as:
In [8]: im.getpixel((125,125))
Out[8]: (11, 11, 11, 255)
Multiplying by a float (like filter[iii][jjj]) concatenates copies of the tuple:
In [9]: 2*im.getpixel((125,125))
Out[9]: (11, 11, 11, 255, 11, 11, 11, 255)
But neuerGrauwert is an int. And you can not add a tuple to an int.
That's very straight forward: you can't add a tuple to an int. aktuellesFeld[iii][jjj] is a tuple, which you multiply with an int (filter[iii][jjj]) resulting in a tuple. You then add that tuple to another int (neuerGrauwert), and that's a TypeError
Your code is very unreadable. Why use variable names such as iii or jjj? Also, it's a bad idea to use filter as a variable name as it is a built-in function.
You try to add a tupel to an int. Look inside your tuple, extract the value you want, and then add it to the int.

Categories