Printing a formatted list [duplicate] - python

This question already has answers here:
Joining words together with a comma, and "and"
(8 answers)
Closed 3 years ago.
name1=input("Give 1st name: ")
name2=input("Give 2nd name: ")
name3=input("Give 3rd name: ")
names = [name1, name2, name3]
names = list(set(names))
names.sort()
print("names in alphabetical order: {}, {} and {}".format(*nimet))
My code gives error: tuple index out of range when 2 names are same.
When inputs are like Ava, Benjamin and Charlie, I want the output to be like:
names in alphabetical order: Ava, Benjamin and Charlie
but when inputs are like Ava, Benjamin, Ava, I want the output to be like:
names in alphabetical order: Ava and Benjamin

the number of arguments of .format() must match the number of {}-s in the string you are formatting.
You can deal with this before the .format():
name1=input("Give 1st name: ")
name2=input("Give 2nd name: ")
name3=input("Give 3rd name: ")
names = [name1, name2, name3]
names = list(set(names))
names.sort()
first_names = ', '.join(names[:-1])
print("names in alphabetical order: {} and {}".format(first_names, names[-1]))

You can use ', '.join to join the names together with commas in between. But you also want "and" between the last two names instead of a comma. One solution is to join the last two names with "and" first, and then join the rest with commas.
def join_names(names):
names = sorted(set(names))
if len(names) > 1:
last, second_last = names.pop(), names.pop()
names.append(second_last + ' and ' + last)
return ', '.join(names)
Examples:
>>> join_names(['Alice', 'Bob', 'Clive'])
'Alice, Bob and Clive'
>>> join_names(['Clive', 'Bob', 'Clive'])
'Bob and Clive'
>>> join_names(['Alice', 'Alice', 'Alice'])
'Alice'
>>> join_names(['John', 'Paul', 'George', 'Ringo'])
'George, John, Paul and Ringo'

You have exactly three placeholders ({}) in your format string and if the names tuple has less than three elements, this will cause an error, as there are not enough values to format the string.
Instead of pluggin in the whole tuple, try this:
print('names in alphabetical order: ' + ', '.join(names))

Set makes elements unique(removes duplicate). The error Tuple index out of range which you are getting is because in your print line you are expecting 3 elements but your tuple has just two because the duplicate element has been removed. So the error says tuple index out of range. So in such scenarios if you want to use set and don't know the number of elements in a tuple, the best bet would be to use joins.
[Edit with code snippet which would work]:
name1=input("Give 1st name: ")
name2=input("Give 2nd name: ")
name3=input("Give 3rd name: ")
names = [name1, name2, name3]
names = list(set(names))
names.sort()
print("names in alphabetical order are:"+ ",".join(str(e) for e in names))

Related

How to remove strings from a list which contain a sub-string?

I have a list of strings that's structured as follows:
['3M', 'Saint Paul, Minnesota', 'A. O. Smith', 'Milwaukee, Wisconsin', 'Abbott Laboratories',...]
I want to remove the strings corresponding to cities, which all contain a comma ,.
So far my code is:
for name in names:
if '</a>' in name:
names.remove(name)
if re.search(', Inc.',name) != None:
name = name.replace(',',"")
names.append(name)
if ',' in name:
names.remove(name)
But I get an error ValueError: list.remove(x): x not in list at names.remove(name).
I can't seem to understand why the 1st block, which drops if the string contains </a> works fine, but the one with commas does not.
Going off my comment about how, in Python, we generally want to "retain things we like" rather than "purge things we don't like". This is preferable because we can avoid changing the size of a list as we're iterating over it, which is never a good idea. We achieve this by filtering the original list based on a predicate (is_desirable in this case). A predicate is a function/callable that accepts a single parameter and returns a boolean. When used in conjunction with filter, we can create an iterator that yields only those items that satisfy the condition of the predicate. We then consume the contents of that iterator to build up a new list:
names = [
'3M',
'Saint Paul, Minnesota',
'A. O. Smith',
'Milwaukee, Wisconsin',
'Abbott Laboratories'
]
def is_desirable(name):
return "</a>" not in name and "," not in name
print(list(filter(is_desirable, names)))
Output:
['3M', 'A. O. Smith', 'Abbott Laboratories']
However, this does not take into account the other operation you're performing: If the current name contains the substring ", Inc.", we still want to retain this name, but with the comma removed.
In this situation, I would define a generator that only yields the items we want to retain. If we come across the substring ", Inc.", we modify the current name and yield it. The generator's contents are then consumed to build up a new list:
def filtered_names(names):
for name in names:
if ", Inc." in name:
name = name.replace(",", "")
if "</a>" in name or "," in name:
continue
yield name
print(list(filtered_names(names)))
This is by no means the only way of doing this. This is my personal preference.
You can use list comprehension to filter out invalid elements (i.e. the ones containing comma).
>>> l = ['3M', 'Saint Paul, Minnesota', 'A. O. Smith', 'Milwaukee, Wisconsin', 'Abbott Laboratories']
>>> result = [e for e in l if "," not in e]
>>> result
['3M', 'A. O. Smith', 'Abbott Laboratories']

Picking phrases containing specific words in python

I have a list with 10 names and a list with many of phrases. I only want to select the phrases containing one of those names.
ArrayNames = [Mark, Alice, Paul]
ArrayPhrases = ["today is sunny", "Paul likes apples", "The cat is alive"]
In the example, is there any way to pick only the second phrase considering the face that contains Paul, given these two arrays?
This is what I tried:
def foo(x,y):
tmp = []
for phrase in x:
if any(y) in phrase:
tmp.append(phrase)
print(tmp)
x is the array of phrases, y is the array of names.
This is the output:
if any(y) in phrase:
TypeError: coercing to Unicode: need string or buffer, bool found
I'm very unsure about the syntax I used concerning the any() construct. Any suggestions?
Your usage of any is incorrect, do the following:
ArrayNames = ['Mark', 'Alice', 'Paul']
ArrayPhrases = ["today is sunny", "Paul likes apples", "The cat is alive"]
result = []
for phrase in ArrayPhrases:
if any(name in phrase for name in ArrayNames):
result.append(phrase)
print(result)
Output
['Paul likes apples']
You are getting a TypeError because any returns a bool and your trying to search for a bool inside a string (if any(y) in phrase:).
Note that any(y) works because it will use the truthy value of each of the strings of y.

Python: How do I continue searching a list for different elements efficiently?

I have many lists of strings I've scraped and parsed and I would like to find certain strings in these lists using regular expressions. Each string I would like is different, but they appear sequentially in the lists. I.e. The first string I'd like will always appear before the second string, the second will appear before the third string, and so on. However, I can't just use an index because the number of elements in between vary between lists.
Ex. say I scraped these strings and stored it in the following lists:
personal_info = ["Name: John Doe", "Wife: Jane Doe", "Children: Jenny Doe", "Children: Johnny Doe", "Location: US", "Accounts: BoA", "Accounts: Chase", "House: Own", "Car: Own", "Other: None"]
personal_info2 = ["Name: James Lee", "Location: CAN", "Accounts: Citibank", "House: Rent", "Car: Own", "Other: None"]
and I would like to grab the elements starting with Name, Location, and House, which may or may not have multiple elements in between. Location will always be after Name and House will always be after Location.
Because I'll be repeating this over many lists, I'd like to search using the first regex, then continue searching using the next regex from where I left off, because I know they appear sequentially. Is there a concise way to do that in Python? Right now I currently have a set of for loops, break when there's a match, and then record the index to pass to the next for loop.
If it must be shown:
idx = 0
for string in string_list:
idx +=1
if re.search('pattern', string) is not None:
string_one = re.search('pattern', string).group(0)
a short code that prints your requested fields:
x=["Name", "Location", "House"]
y=iter(x)
z=y.next()
for a in personal_info:
if a.startswith(z):
print a
try:
z=y.next()
except StopIteration:
break
you can replace the "startswith" with regex, and "print" with any other action.
You could you an index counter too keep track of which condition you are suppose to be checking:
conditions = [("Name", "John Doe"), ("Location", "US")]
condition_index = 0
for index, i in enumerate(personal_info):
j1, j2 = conditions[condition_index]
if j1 in i or j2 in i:
print "List idx", index, i, "Condition", (j1, j2)
condition_index += 1
if condition_index == len(conditions):
break
>>>List idx 0 Name: John Doe Condition ('Name', 'John Doe')
List idx 4 Location: US Condition ('Location', 'US')

Splitting a string of names

I'm trying to write a program that will ask a user to input several names, separated by a semi-colon. The names would be entered as lastname,firstname. The program would then print each name in a firstname lastname format on separate lines. So far, my program is:
def main():
names=input("Please enter your list of names: ")
person=names.split(";")
xname=person.split(",")
This is as far as I got,because there's an error when I try to split on the comma. What am I doing wrong? The output should look like this:
Please enter your list of names: Falcon, Claudio; Ford, Eric; Owen, Megan; Rogers, Josh; St. John, Katherine
You entered:
Claudio Falcon
Eric Ford
Megan Owen
Josh Rogers
Katherine St. John
.split is a string method that returns a list of strings. So it works fine on splitting the original string of names, but you can't call it on the resulting list (list doesn't have a .split method, and that really wouldn't make sense). So you need to call .split on each of the strings in the list. And to be neat, you should clean up any leading or trailing spaces on the names. Like this:
names = "Falcon, Claudio; Ford, Eric; Owen, Megan; Rogers, Josh; St. John, Katherine"
for name in names.split(';'):
last, first = name.split(',')
print(first.strip(), last.strip())
output
Claudio Falcon
Eric Ford
Megan Owen
Josh Rogers
Katherine St. John
.split returns a list, so you are attempting
["Falcon, Claudio", "Ford, Eric" ...].split(',')
Which obviously doesn't work, as split is a string method. Try this:
full_names = []
for name in names.split("; "):
last, first = name.split(', ')
full_names.append(first + " " + last)
To give you
['Claudio Falcon', 'Eric Ford', 'Megan Owen', 'Josh Rogers', 'Katherine St. John']
You are splitting the whole list instead of each string. Change it to this:
def main():
names=input("Please enter your list of names: ")
person=names.split("; ")
xname=[x.split(", ") for x in person]
To print it out, do this:
print("\n".join([" ".join(x[::-1]) for x in xname]))
You can use the following code:
names = raw_input("Please enter your list of names:")
data = names.split(";")
data will return you list so process that list to get first name and last name
f_names=[]
for i in data:
l_name,f_name= i.split(",")
f_names.append(f_name+" "+l_name)
print "you entered \n"+ '\n'.join(p for p in f_names)
So this way you can print desired input

Function to convert a string to a tuple

Here is an example of what data I will have:
472747372 42 Lawyer John Legend Bishop
I want to be able to take a string like that and using a function convert it into a tuple so that it will be split like so:
"472747372" "42" "Lawyer" "John Legend" "Bishop"
NI Number, Age, Job, surname and other names
What about:
>>> string = "472747372 42 Lawyer John Legend Bishop"
>>> string.split()[:3] + [' '.join(string.split()[3:5])] + [string.split()[-1]]
['472747372', '42', 'Lawyer', 'John Legend', 'Bishop']
Or:
>>> string.split(maxsplit=3)[:-1] + string.split(maxsplit=3)[-1].rsplit(maxsplit=1)
['472747372', '42', 'Lawyer', 'John Legend', 'Bishop']
In python, str has a built-in method called split which will split the string into a list, splitting on whatever character you pass it. It's default is to split on whitespace, so you can simply do:
my_string = '472747372 42 Lawyer Hermin Shoop Tator'
tuple(my_string.split())
EDIT: After OP changed the post.
Assuming there will always be an NI Number, Age, Job, and surname, you would have to do:
elems = my_string.split()
tuple(elems[:3] + [' '.join(elems[3:5])] + elems[5:])
This will allow you to support an arbitrary number of "other" names after the surname

Categories