Remove else statement from list comprehensions - python

Why won't it not, not letting me use a else statement? When I run this code it's giving me this error SyntaxError: expected 'else' after 'if' expression, but I simply don't want to return anything after the if statement
x = ["x" if "x" in letter for letter in s]

It looks like what you want to do is to filter the list, rather than to map each value to a different value. The syntax for that is to place an if clause at the end of the list comprehension:
["x" for letter in s if "x" in letter]
At this position in a list comprehension, if has a special meaning: the subsequent expression is used for filtering, so that the comprehension returns only those elements that satisfy the condition (and there can be no else). The condition is evaluated with the original value of the item, but you can still do mapping (as you do, since you're using "x" instead of letter).
In your original attempt, you used if in the mapping expression (which says what you want each result element to be). There, it is interpreted as a conditional expression that must have an else.
By the way, if s is a string, so that letter is a single-character string, you should use letter == "x" instead of "x" in letter. The latter works, but kinda by accident (because Python represents individual characters as strings with length one), and looks confusing because the right hand side of in is usually a "full" string or a collection.

Two main parts of list comprehensions are : condition part and expression part.
Here is the syntax:
[expression for member in iterable if condition]
in condition part, you can not use else. Think of it as a filter. Move it to the end so that it acts like a filter:
x = ["x" for letter in s if "x" in letter]
But in expression part you can have any valid Python expression.
for example a conditional expression as the expression part which is:
a = <on_true> if <condition> else <on_false>
So you need to have the else part in expression part of the list comprehension because the expression part is indeed a conditional expression and the conditional expression need else.

Related

condition within return statement

I am trying to create a function which takes as an argument a string and returns the same string but alternating upper and lower cases letters within the string. I know a longer solution to this, but I came up with the solution below which however is not working, and I am wondering why this does not work.
def myfunc(*args):
return [b.lower() if a%2 else b.upper() for a,b in enumerate(args)]
The above piece of code gives me as output a full uppercase string, for example:
>>> myfunc('Hello')
['HELLO']
Okay, first of all you function is not taking a single string now, but it can take several variables (because of the * you put in front of args), hence when you pass it the argument "Hello", it actually gets a tuple object like ('Hello', ). So in your for loop you actually iterate over that tuple instead of iterating over the characters of the string.
If you want to get a string, just remove the *.
def myfunc(args):
return "".join([b.lower() if a%2 else b.upper() for a,b in enumerate(args)])
Note that you operation returns not a string but a list of characters. The "".join([]) will concatenate the characters inside of your list into a string, separated by "" (i.e nothing)
You need to unpack the args (*args), but then this will return a list, so you need to join the string again too.
return "".join([b.lower() if a%2 else b.upper() for a,b in enumerate(*args)])
As noted in the comments, this only works if there is only one argument, if there isn't you may want to join the strings together, one such way is using chain, and then pass this in to enumerate instead
from itertools import chain
if len(args) > 1:
single_arg = chain.from_iterable(args)
return "".join(b.lower() if a%2 else b.upper() for a,b in enumerate(chain.from_iterable(single_arg)))

Palindrome Coding issue

Writing a program:
Input string from the user
print out whether this string is a palindrome or not
Also, I found a few other codes online but want to work with this code only.m Please let me know the error
i = str(input())
for item in i:
print(item)
if int(i[item]) == int(i[-item]):
print('yes')
else:
print('no')
Use a String slice (The i[::-1] will reverse the string):
i = input()
if i == i[::-1]:
print("Yes")
else:
print("No")
This will take the input from the user and compare it against the same input in reverse.
try this:
word="TOT"
i=word[::-1]
if i==word:
print("palandrom")
Although for item in i: loops through every character in the string, there are several problems with your code line if int(i[item]) == int(i[-item]):. First of all, item is going to be a character from your string. So if the user types "hello", then i[item] first looks for i['h']. Since 'h' is a character and not a number, this makes Python think that i is a dictionary and not a string, and thus tells Python to look for a dictionary named i and return the value where the key is h. That won't work since i is your original string, not a dictionary.
It looks like what you meant to do here is compare i[0] (the first character in the string) to i[-1] (the last character in the string), then i[1] to i[-2], and so on. But even you if looped through the position numbers, i[-item] doesn't mathematically give you what you want.
Yet another issue here is that you're checking each character one at a time and returning "yes" or "no". What you ultimately want though is to output one simple answer: whether your string is a palindrome or not.
Also, there's no need to put str() around input(), since input returns a string anyway, even if the user enters only numerals. By the way, even though you're using i as your string variable, the usual convention in programming is to use i to denote some sort of integer, such as one you're iterating through in a for loop. But that's OK for now.
As some of the other answers have shown, i[::-1] is a quick way to return the reverse of a string itself. So if you're OK with seeing the output return True if the string is a palindrome and False if it isn't, then here's an extremely simple way to do it:
i = input()
print(i == i[::-1])
If the string i is identical to itself reversed, then i == i[::-1] returns True. If not, it returns False. The print statement then prints whichever the answer is.
However, if you really do want to do it the long way, testing character by character in a loop, then here's one way to do it. You could make a function that takes in a string and does the work:
def is_palindrome(mystring):
# The "//2" here divides by 2 and ignores the remainder. So if
# there are an even number of letters, we'll test each pair. If
# It's an odd number, then we don't care about the middle character
# anyway. Compare [0] to [-1], then [1] to [-2], [2] to [-3], and so on.
for position in range(0, len(mystring)//2):
# If we've found a mismatched pair of letters, then we can
# stop looking; we know it's not a palindrome.
if mystring[position] != mystring[(-1 * position) - 1]:
print("This is NOT a palindrome")
return # This breaks you out of the entire function.
# If we've gotten this far, then the word must be a palindrome.
print("This is a palindrome")
# Here's where we run the command to input the string, and run the function
mystring = input("Enter your string: ")
is_palindrome(mystring)

Starred expression in ternary operator python

I wrote a python program to print the ascii value of up to every 3 numbers in a string or "ERROR" if the length is not divisible by three. I was golf the code when I ran into a SyntaxError.
Code:
c=input()
p=len(c)
c=[int(c[i:i+3])for i in range(0,len(c),3)]
print("ERROR"if p%3else*map(chr,c),sep='')#SyntaxError here
But this works:
c=input()
p=len(c)
c=[int(c[i:i+3])for i in range(0,len(c),3)]
print(*map(chr,c),sep='')
Putting a space before the * or after the 3 doesn't work. I could just use ''.join but it's one character longer. My question is why can't I use a starred expression in a ternary operator?
Because the * has to apply to the whole expression that produces the set of arguments, not a part of it, and not conditionally. Internally, CPython uses different bytecodes for calling with unpacking vs. normal calls, so your conditional would require it to change the byte code to call print based on the arguments to print, essentially rewriting what you wrote into pseudocode like:
if p % 3:
call(print, "ERROR", sep='')
else:
call_varargs(print, *map(chr, c), sep='')
which is beyond the compiler's capability.
If you wanted to make this work, you could do the following:
print(*(("ERROR",) if p%3 else map(chr,c)), sep='')
which ensures the whole ternary evaluates to an unpackable sequence and unpacks whatever survives unconditionally, avoiding the confusion.
print(*(["ERROR"] if p%3 else map(chr,c)),sep="!")
keep it outside of the ternary
The * expander transforms a single enumerable variable into individual variables. E.g.
li = [1,2,3]
print(*li)
produces: 1 2 3 instead of [1, 2, 3].
One value vs. multiple values
It appears to remove the brackets and pass a single string to print, but this is only an appearance, it actually replaces the single list variable by 3 variables and is actually equivalent to:
print(li[0], li[1], li[2])
It works because print accepts a variable number of arguments, so in our case it can deal with the single list or with these three integers.
The conditional expression is a one-value operator
However in your code you use the star operator within a conditional expression:
c = '065066067068'
p = len(c)
c = [int(c[i:i+3]) for i in range(0, p, 3)]
print('ERROR' if p%3 else *map(chr, c), sep='!')
print would be able to accept both evaluations of the expression, a single string value ('ERROR') or multiple char values from map.
But the conditional expression prevents returning multiple values according to the condition (p%3). The expression output has to be a single value. So you have no other choice than to return the list from map as an enumerable, and un-nest it only outside of the ternary operator, e.g. in the print statement.
A string is an enumerable, not a scalar value
However this solution now introduces another problem: Un-nesting will also convert the constant string ERROR into single chars, as a string is considered by Python an enumerable of single chars (as you know since you use this property for your input string). When the condition is true, the output would be:
E!R!R!O!R
Therefore the string must be first converted to an enumerable of strings, e.g. a tuple
Final solution
if p%3: s = ('ERROR',)
else: s = map(chr, c)
print(*s, sep='!')
The outputs will be:
A!B!C!D
ERROR

Delete elements of a List, using a condition

Hello I'm learning to program in Python to manipulate data bases and I can't make this simple task. Please someone help me.
I have this list
CIS=['4998200lp','2159140lp','02546or']
I want to get this result:
CIS=['4998200lp','2159140lp','2546or']
I was trying something like:
for x in CIS:
izq= x[:1]
if izq == 0:
CIS=[x.replace(x[:1],'') for x in CIS]
print (CIS)
I just want to delete the first element of every string for the condition izq == 0.
Your description doesn't match your example input/output which also differs from your code.
Based on the example input/output, I suspect what you're trying to do is strip a single leading 0 from any string that starts with 0. And that's not too bad, but you can't do it in a for loop without having an index to assign back to. For that, you can use enumerate:
for i, x in enumerate(CIS):
if x.startswith('0'): # or x[:1] == '0' if you really prefer
CIS[i] = x[1:]
Alternatively, you can use a list comprehension to replace CIS:
CIS = [x[1:] if x.startswith('0') else x for x in CIS]
and to mutate in place (rather than making a new list), use the same comprehension but assign to the full slice, which makes it behave like the spelled out loop in the first example:
CIS[:] = [x[1:] if x.startswith('0') else x for x in CIS]
The difference between examples #1/#3 and example #2 occurs if CIS was passed as an argument to a function, or otherwise is referenced in multiple places. In #1/#3, it's mutating the list in place, so all references will see the updates, in #2, it's reassigning CIS, but leaving the original list unchanged; if other references exist, they won't appear changed.
Note: If the goal is to remove all leading 0s, then use str.lstrip, e.g.:
CIS = [x.lstrip('0') for x in CIS]
with similar adaptations for the other approaches. You don't even need to test for the presence of 0 in that case, as lstrip will return the str unmodified if it doesn't begin with 0.
If you are simply looking to remove the first zero of every string, utilize the startswith method. Also, don't look for an integer 0. Look for a string '0'.
Finally, you can simplify your implementation with doing this all in a comprehension, creating a new list with your new data:
[w[1:] if w.startswith('0') else w for w in CIS]
Outputs:
['4998200lp', '2159140lp', '2546or']
Just try to delete first character of every elements that starts with 0:
CIS=['4998200lp','2159140lp','02546or']
for i,v in enumerate(CIS):
if v.startswith('0'):
CIS[i] = v[1:]
CIS # ['4998200lp', '2159140lp', '2546or']
Actually your loop contained a very close approach to a working solution:
CIS=['4998200lp','2159140lp','02546or']
CIS=[x.replace(x[:1],'') for x in CIS]
but this would strip all first elements. To only replace them if they are '0' (notice that's not the same as the integer: 0) you need to incorporate you if ... else ... into the list-comprehension:
CIS=['4998200lp','2159140lp','02546or']
CIS=[x.replace(x[:1],'',1) if x[:1] == '0' else x for x in CIS ]
The if ... else ... syntax might be a bit strange but just try to read the code aloud: "Insert the replaced x if the first character is a zero or if not insert x, for every x in CIS".
The other answers contain much more sophisticated approaches but I just wanted to add this answer to give you a heads-up that you were on the right track!
But it's generally a bad idea to use a list-comprehension inside a for loop if they iterate over the same iterable. Mostly you just want one of them.

Display the number of lower case letters in a string

This is what I have so far:
count=0
mystring=input("enter")
for ch in mystring:
if mystring.lower():
count+=1
print(count)
I figured out how to make a program that displays the number of lower case letters in a string, but it requires that I list each letter individually: if ch=='a' or ch=='b' or ch=='c', etc. I am trying to figure out how to use a command to do so.
This sounds like homework! Anway, this is a fun way of doing it:
#the operator module contains functions that can be used like
#their operator counter parts. The eq function works like the
#'=' operator; it takes two arguments and test them for equality.
from operator import eq
#I want to give a warning about the input function. In python2
#the equivalent function is called raw_input. python2's input
#function is very different, and in this case would require you
#to add quotes around strings. I mention this in case you have
#been manually adding quotes if you are testing in both 2 and 3.
mystring = input('enter')
#So what this line below does is a little different in python 2 vs 3,
#but comes to the same result in each.
#First, map is a function that takes a function as its first argument,
#and applies that to each element of the rest of the arguments, which
#are all sequences. Since eq is a function of two arguments, you can
#use map to apply it to the corresponding elements in two sequences.
#in python2, map returns a list of the elements. In python3, map
#returns a map object, which uses a 'lazy' evaluation of the function
#you give on the sequence elements. This means that the function isn't
#actually used until each item of the result is needed. The 'sum' function
#takes a sequence of values and adds them up. The results of eq are all
#True or False, which are really just special names for 1 and 0 respectively.
#Adding them up is the same as adding up a sequence of 1s and 0s.
#so, map is using eq to check each element of two strings (i.e. each letter)
#for equality. mystring.lower() is a copy of mystring with all the letters
#lowercase. sum adds up all the Trues to get the answer you want.
sum(map(eq, mystring, mystring.lower()))
or the one-liner:
#What I am doing here is using a generator expression.
#I think reading it is the best way to understand what is happening.
#For every letter in the input string, check if it is lower, and pass
#that result to sum. sum sees this like any other sequence, but this sequence
#is also 'lazy,' each element is generated as you need it, and it isn't
#stored anywhere. The results are just given to sum.
sum(c.islower() for c in input('enter: '))
You have a typo in your code. Instead of:
if my.string.lower():
It should be:
if ch.islower():
If you have any questions ask below. Good luck!
I'm not sure if this will handle UTF or special characters very nicely but should work for at least ASCII in Python3, using the islower() function.
count=0
mystring=input("enter:")
for ch in mystring:
if ch.islower():
count+=1
print(count)
The correct version of your code would be:
count=0
mystring=input("enter")
for ch in mystring:
if ch.islower():
count += 1
print(count)
The method lower converts a string/char to lowercase. Here you want to know if it IS lowercase (you want a boolean), so you need islower.
Tip: With a bit of wizardry you can even write this:
mystring= input("enter")
count = sum(map(lambda x: x.islower(), mystring))
or
count = sum([x.islower() for x in mystring])
(True is automatically converted to 1 and False to 0)
:)
I think you can use following method:
mystring=input("enter:")
[char.lower() for char in mystring].count( True ) )

Categories