Better way for taking multiple inputs with a for loop? - python

I would like to use a for loop to get inputs for many questions I have to receive.
I managed to make some code, but it seems there should be
a better way.
Maybe I can reduce the number of variables I'm using?
## <Desired Result>
## onset : 3mo
## location : earth
## character : red
checks = ['onset','location','character']
l1 = ['onset','location','character']
l2 = ['onset','location','character']
for i in range(len(checks)):
l2[i] = input(checks[i])
for i in range(len(checks)):
print(l1[i]+" : "+l2[i])

A few observations on your code:
Note that you never actually change l1 so basically it is unnecessary and wherever you use l1 replace with checks.
It is not necessary to define l2 this way as you are overriding all its values anyway, so you could just define l2 = [] and then use append in your loop:
for i in range(len(checks)):
l2.append(input(checks[i]))
Both your loops have exactly the same range, so you could combine them to 1:
for i in range(len(checks)):
l2[i] = input(checks[i])
print(l1[i]+" : "+l2[i])
Now, using list-comprehension and the join method of strings, you could actually reduce this code to 3 lines (and get rid of l1):
checks = ['onset', 'location', 'character']
l2 = [input(x) for x in checks]
print("\n".join(checks[i]+" : "+l2[i] for i in range(len(checks))))
Or more neatly using zip:
print("\n".join(check + " : " + ans for check, ans in zip(checks, l2)))
Lastly, to reduce even one more line (and get rid of l2):
checks = ['onset', 'location', 'character']
print("\n".join(check + " : " + input(check) for check in checks))
We could also avoid using join and use the chance to further reduce to one line (getting rid of checks) using print's extra arguments and list-unpacking:
print(*(check + " : " + input(check) for check in ['onset', 'location', 'character']), sep='\n')

What you are trying to achieve for is done using List comprehensions.
In your case you can do that in a single line.
l2 = [input(x) for x in checks]

You should not initialize the list of desired length and take input for each element. You can use append method to that.
The following code will help you:
checks = ['onset','location','character']
arr = []
for i in checks:
arr.append(input(i + ' : '))
If you want to reduce the number of lines, you can try the following:
arr = [ input(i + ' : ') for i in ['onset','location','character']]

For a truly 1-line solution to your for-loops, you could do your list comprehension like this:
l2 = [(n, print(l1[i]+" : "+n))[0] for i, n in enumerate([input(x + ": ") for x in checks])]
Ouput:
onseta
locationb
characterc
onset : a
location : b
character : c
EDIT
As others mentioned, this is not best practice, so use something like this:
checks = ['onset','location','character']
l2 = [input(f"Check {n}:\n > ") for n in checks]
print(*(f"{j}: {l2[i]}\n" for i, j in enumerate(checks)), sep="")
Output:
Check onset:
> ok
Check location:
> ok
Check character:
> ok
onset: ok
location: ok
character: ok

Related

Split numbers in multiple ranges

Given the following problem,
Input
lis = ['0-10,000, 10,001-11,000, 11,001-12,000']
Output:
['0-10,000','10,001-11,000', '11,001-12,000']
Create a function such that, it should avoid if there's a single range in the list but split the ranges if there are multiple ranges in the list.
Can anybody help me with this problem, I can't even think of any method.
First build a string from the list of elements, then split the string with the specified ", ".
lis = ['0-10,000, 10,001-11,000, 11,001-12,000']
print(''.join(lis).split(", "))
I have tried this :
lis = ['0-10,000, 10,001-11,000, 11,001-12,000','0-10,001, 10,001-11,000, 11,001-12,000','0-10,011, 10,001-11,000, 11,001-12,000']
def data_clean(x):
v = []
for i in range(len(x)):
v.append(x[i].split(", "))
return v
Here it is how the output is :
[['0-10,000', '10,001-11,000', '11,001-12,000'],
['0-10,001', '10,001-11,000', '11,001-12,000'],
['0-10,011', '10,001-11,000', '11,001-12,000']]

specific characters printing with Python

given a string as shown below,
"[xyx],[abc].[cfd],[abc].[dgr],[abc]"
how to print it like shown below ?
1.[xyz]
2.[cfd]
3.[dgr]
The original string will always maintain the above-mentioned format.
I did not realize you had periods and commas... that adds a bit of trickery. You have to split on the periods too
I would use something like this...
list_to_parse = "[xyx],[abc].[cfd],[abc].[dgr],[abc]"
count = 0
for i in list_to_parse.split('.'):
for j in i.split(','):
string = str(count + 1) + "." + j
if string:
count += 1
print(string)
string = None
Another option is split on the left bracket, and then just re-add it with enumerate - then strip commas and periods - this method is also probably a tiny bit faster, as it's not a loop inside a loop
list_to_parse = "[xyx],[abc].[cfd],[abc].[dgr],[abc]"
for index, i in enumerate(list.split('[')):
if i:
print(str(index) + ".[" + i.rstrip(',.'))
also strip is really "what characters to remove" not a specific pattern. so you can add any characters you want removed from the right, and it will work through the list until it hits a character it can't remove. there is also lstrip() and strip()
string manipulation can always get tricky, so pay attention. as this will output a blank first object, so index zero isn't printed etc... always practice and learn your needs :D
You can use split() function:
a = "[xyx],[abc].[cfd],[abc].[dgr],[abc]"
desired_strings = [i.split(',')[0] for i in a.split('.')]
for i,string in enumerate(desired_strings):
print(f"{i+1}.{string}")
This is just a fun way to solve it:
lst = "[xyx],[abc].[cfd],[abc].[dgr],[abc]"
count = 1
var = 1
for char in range(0, len(lst), 6):
if var % 2:
print(f"{count}.{lst[char:char + 5]}")
count += 1
var += 1
output:
1.[xyx]
2.[cfd]
3.[dgr]
explanation : "[" appears in these indexes: 0, 6, 12, etc. var is for skipping the next pair. count is the counting variable.
Here we can squeeze the above code using list comprehension and slicing instead of those flag variables. It's now more Pythonic:
lst = "[xyx],[abc].[cfd],[abc].[dgr],[abc]"
lst = [lst[i:i+5] for i in range(0, len(lst), 6)][::2]
res = (f"{i}.{item}" for i, item in enumerate(lst, 1))
print("\n".join(res))
You can use RegEx:
import regex as re
pattern=r"(\[[a-zA-Z]*\])\,\[[a-zA-Z]*\]\.?"
results=re.findall(pattern, '[xyx],[abc].[cfd],[abc].[dgr],[abc]')
print(results)
Using re.findall:
import re
s = "[xyx],[abc].[cfd],[abc].[dgr],[abc]"
print('\n'.join(f'{i+1}.{x}' for i,x in
enumerate(re.findall(r'(\[[^]]+\])(?=,)', s))))
Output:
1.[xyx]
2.[cfd]
3.[dgr]

Multiple if/else conditions to check last characters in a list of strings

I have this list
num_list=["mille", "duemila", "tremila", "quattromila", "cinquemila", "seimila", "settemila", "ottomila", "novemila", "diecimila", "milione", "miliardo", "milioni",'miliardi','mila']
I would like to build the following list
output=['millesimo', 'duemillesimo','tremillesimo','quattromillesimo','cinquemillesimo','seimillesimo','settemillesimo', 'ottomillesimo', 'novemillesimo', 'diecimillesimo', 'milionesimo', 'miliardesimo', 'milionesimo','miliardesimo']
This should be built by following the conditions below, after removing the last character from each string:
if the word is 'mila' do nothing;
if the word ends with 'l' then add 'lesimo';
else (if the last two characters of the string, after removing the last character, are 'll' or the string is "milion", "miliard"), then add 'esimo';
I started to do as follows:
numeri_card_esimo = [x[:-1] + 'lesimo' if x[:-2] == 'll' else x[:-1] + 'esimo' for x in numeri_card_esimo]
and the output is not so close to that one I would like:
['millesimo',
'duemilesimo', # it should be duemillesimo
'tremilesimo', # same as above
'quattromilesimo', # same as above
'cinquemilesimo', # same as above
'seimilesimo', # same as above
'settemilesimo', # same as above
'ottomilesimo', # same as above
'novemilesimo', # same as above
'diecimilesimo', # same as above
'milionesimo',
'miliardesimo',
'milionesimo',
'milesimo'] # it should be excluded
but it does not work because of wrong use of if/else conditions. How should I write these conditions?
In my opinion, the logic you are trying to apply is a bit long to be used in a list comprehension. It is better to move it into a function for the sake of readability.
def convert(num):
num = num[:-1]
if num[-2:]=='ll' or num=='milion' or num=='miliard':
num = num + 'esimo'
elif word[-1]=='l':
num = num + 'lesimo'
return num
num_list=["mille", "duemila", "tremila", "quattromila", "cinquemila", "seimila", "settemila", "ottomila", "novemila", "diecimila", "milione", "miliardo", "milioni",'miliardi','mila']
# Remove mila occurrences
num_list = [num for num in num_list if num!='mila']
output = [convert(num) for num in num_list]
print(output)

More on dynamic programming

Two weeks ago I posted THIS question here about dynamic programming. User Andrea Corbellini answered precisely what I wanted, but I wanted to take the problem one more step further.
This is my function
def Opt(n):
if len(n) == 1:
return 0
else:
return sum(n) + min(Opt(n[:i]) + Opt(n[i:])
for i in range(1, len(n)))
Let's say you would call
Opt( [ 1,2,3,4,5 ] )
The previous question solved the problem of computing the optimal value. Now,
instead of the computing the optimum value 33 for the above example, I want to print the way we got to the most optimal solution (path to the optimal solution). So, I want to print the indices where the list got cut/divided to get to the optimal solution in the form of a list. So, the answer to the above example would be :
[ 3,2,1,4 ] ( Cut the pole/list at third marker/index, then after second index, then after first index and lastly at fourth index).
That is the answer should be in the form of a list. The first element of the list will be the index where the first cut/division of the list should happen in the optimal path. The second element will be the second cut/division of the list and so on.
There can also be a different solution:
[ 3,4,2,1 ]
They both would still lead you to the correct output. So, it doesn't matter which one you printed. But, I have no idea how to trace and print the optimal path taken by the Dynamic Programming solution.
By the way, I figured out a non-recursive solution to that problem that was solved in my previous question. But, I still can't figure out to print the path for the optimal solution. Here is the non-recursive code for the previous question, it might be helpful to solve the current problem.
def Opt(numbers):
prefix = [0]
for i in range(1,len(numbers)+1):
prefix.append(prefix[i-1]+numbers[i-1])
results = [[]]
for i in range(0,len(numbers)):
results[0].append(0)
for i in range(1,len(numbers)):
results.append([])
for j in range(0,len(numbers)):
results[i].append([])
for i in range(2,len(numbers)+1): # for all lenghts (of by 1)
for j in range(0,len(numbers)-i+1): # for all beginning
results[i-1][j] = results[0][j]+results[i-2][j+1]+prefix[j+i]-prefix[j]
for k in range(1,i-1): # for all splits
if results[k][j]+results[i-2-k][j+k+1]+prefix[j+i]-prefix[j] < results[i-1][j]:
results[i-1][j] = results[k][j]+results[i-2-k][j+k+1]+prefix[j+i]-prefix[j]
return results[len(numbers)-1][0]
Here is one way of printing the selected :
I used the recursive solution using memoization provided by #Andrea Corbellini in your previous question. This is shown below:
cache = {}
def Opt(n):
# tuple objects are hashable and can be put in the cache.
n = tuple(n)
if n in cache:
return cache[n]
if len(n) == 1:
result = 0
else:
result = sum(n) + min(Opt(n[:i]) + Opt(n[i:])
for i in range(1, len(n)))
cache[n] = result
return result
Now, we have the cache values for all the tuples including the selected ones.
Using this, we can print the selected tuples as shown below:
selectedList = []
def printSelected (n, low):
if len(n) == 1:
# No need to print because it's
# already printed at previous recursion level.
return
minVal = math.Inf
minTupleLeft = ()
minTupleRight = ()
splitI = 0
for i in range(1, len(n)):
tuple1ToI = tuple (n[:i])
tupleiToN = tuple (n[i:])
if (cache[tuple1ToI] + cache[tupleiToN]) < minVal:
minVal = cache[tuple1ToI] + cache[tupleiToN]
minTupleLeft = tuple1ToI
minTupleRight = tupleiToN
splitI = low + i
print minTupleLeft, minTupleRight, minVal
print splitI # OP just wants the split index 'i'.
selectedList.append(splitI) # or add to the list as requested by OP
printSelected (list(minTupleLeft), low)
printSelected (list(minTupleRight), splitI)
You call the above method like shown below:
printSelected (n, 0)

How to NOT repeat a random.choice when printing a piece of text in python

I have three lists in text files and I am trying to generate a four-word message randomly, choosing from the prefix and suprafix lists for the first three words and the `suffix' file for the fourth word.
However, I want to prevent it from picking a word that was already chosen by the random.choice function.
import random
a= random.random
prefix = open('prefix.txt','r').readlines()
suprafix = open('suprafix.txt','r').readlines()
suffix = open('suffix.txt','r').readlines()
print (random.choice(prefix + suprafix), random.choice(prefix + suprafix), random.choice(prefix + suprafix), random.choice(suffix))
As you can see it chooses randomly from those two lists for three words.
random.sample(pop, k) selected k items from pop without replacement. Hence:
prefix1, prefix2, prefix3 = random.sample(prefix, 3)
suprafix1, suprafix2, suprafix3 = random.sample(suprafix, 3)
suffix = random.choice(suffix)
print (prefix1 + suprafix1, prefix2 + suprafix2, prefix3 + suprafix3, suffix))
Thankyou xnx that helped me sort out the problem by using the random.sample first then printing either of them afterwards, i might have done it the long way round but this is how i did it >
import random
a= random.random
prefix = open('prefix.txt','r').readlines()
suprafix = open('suprafix.txt','r').readlines()
suffix = open('suffix.txt','r').readlines()
prefix1, prefix2, prefix3 = random.sample(prefix, 3)
suprafix1, suprafix2, suprafix3 = random.sample(suprafix, 3)
suffix = random.choice(suffix)
one = prefix1, suprafix1
two = prefix2, suprafix2
three = prefix3, suprafix3
print (random.choice(one), random.choice(two), random.choice(three), suffix)

Categories

Resources