replacing string integer in list, python - python

I wanted to replace string with an integer so I first tried this
timeupseats=[0,480,480,0]
for n in range(0,4):
if timeupseats[n]==0:
timeupseats[n]='CLOSED'
for n in range(0,4):
if timeupseats[n]=='CLOSED':
timeupseats[n]==0
Because the first code didn't work, I tried this code for the second time and it worked
timeupseats=[0,480,480,0]
for n in range(0,4): #print closed when there is no ticket left
if timeupseats[n]==0:
timeupseats[n]='CLOSED'
timeupseats = [0 if i=='CLOSED' else i for i in timeupseats]
What's the difference between the first code and the second code?
Why did only the second code work?

In your first set of code you have this error on the last line :
timeupseats[n]==0
You want to set it to 0 (=) not check for equality (==)

There are many ways to to this. The in my opinion the most robust one would be to first define the values you want to replace, then apply that on each element of the list with ‘map’:
# make some data
ls = list(range(10))
# define values to replace
mapping = {0: 'CLOSED'}
# do replacement
ls = list(map(lambda x: mapping.get(x, x), ls))
print(ls)
There is also the more explicit, but more difficult to maintain way:
ls = list(range(10))
for i, x in enumerate(ls):
if x == 0:
ls[i] = 'CLOSED'
print(ls)

Related

How to handle operating on items in a list without perfectly even len()?

I'm trying to operate on every 5 items in a list, but can't figure out how to handle the remaining items if they don't divide evenly into 5. Right now I'm using modulo, but I can't shake the feeling it's not quite the right answer. Here's an example...
list = ["ValA","ValB","ValC","ValD","ValE","ValF","ValG","ValH","ValI","ValJ","ValK","ValL","ValM","ValN",]
newlist = []
i = 0
for o in list:
i += 1
newlist.append(o)
if i % 5 == 0:
for obj in newlist:
function_for(obj)
newlist.clear()
This code will execute function_for() twice, but not a third time to handle the remaining 4 values. If I add an 'else' statement it runs on every execution.
What's the correct way to handle a situation like this?
This way is pretty easy, if you don't mind modifying the list:
mylist = ["ValA","ValB","ValC","ValD","ValE","ValF","ValG","ValH","ValI","ValJ","ValK","ValL","ValM","ValN",]
while mylist:
function_for( mylist[:5] )
mylist = mylist[5:]
You can also check if the index is equal to the length of the list. (Additionally, it is more idiomatic to use enumerate instead of a counter variable here.)
lst = ["ValA","ValB","ValC","ValD","ValE","ValF","ValG","ValH","ValI","ValJ","ValK","ValL","ValM","ValN",]
newlist = []
for i, o in enumerate(lst, 1):
newlist.append(o)
if i % 5 == 0 or i == len(lst):
print(newlist)
newlist.clear()

Removing the smaller value from a list using function min() [duplicate]

This question already has answers here:
Remove Max and Min values from python list of integers
(3 answers)
Closed 1 year ago.
In short, this is the plan: I want to remove the smallest value from a Python list. My approach to that was creating a new list trimmed , which is basically a copy of the original one but with a condition like:
add it to trimmed only if the value is not equal to min(). Like this:
lis=[]
trimmed =[]
n = int(input("Enter number of elements : "))
for i in range(0, n):
elements = int(input("Type a number: "))
lis.append(elements) # adding the elements
# "trimmed" appends a new copy of "lis" removing the smaller value
trimmed = [x for i,x in enumerate(lis) if i != min(lis)]
print(trimmed)
The problem is, it sometimes seems to build trimmed by removing a value in a specific index rather than removing the actual smaller one. E.g. I have just inputted 5 ,2 ,6 and 9. It should ramv removed number two. Instead, it prints out [5, 2, 9]
It's because your if i != min(lis) checks the minimum value against the index variable i instead of the value itself x. enumerate gives back (index, val) pairs i.e, (i, x) here. It happened that min(lis) was 2, so whenever i hits 2, that value will be trimmed, hence you saw 6 disappearing (which was at 2nd index). Fix is to compare against x:
trimmed = [x for i,x in enumerate(lis) if x != min(lis)]
should do.
But better yet, let us compute the minimum only once (above computes many times):
minimum = min(lis)
trimmed = [x for i,x in enumerate(lis) if x != minimum]
and further, you don't seem to need i at all:
minimum = min(lis)
trimmed = [x for x in list if x != minimum]
The index doesn't have anything to do with the minimum value. No need to enumerate.
minval = min(lis)
trimmed = [x for x in lis if x != minval]

If the input number is in the list add its index to a new one

I want to check if the input number is in the list, and if so - add its index in the original list to the new one. If it's not in the list - I want to add a -1.
I tried using the for loop and adding it like that, but it is kind of bad on the speed of the program.
n = int(input())
k = [int(x) for x in input().split()]
z = []
m = int(input())
for i in range(m):
a = int(input())
if a in k: z.append(k.index(a))
else: z.append(-1)
The input should look like this :
3
2 1 3
1
8
3
And the output should be :
1
-1
2
How can I do what I'm trying to do more efficiently/quickly
There are many approaches to this problem. This is typical when you're first starting in programming as, the simpler the problem, the more options you have. Choosing which option depends what you have and what you want.
In this case we're expecting user input of this form:
3
2 1 3
1
8
3
One approach is to generate a dict to use for lookups instead of using list operations. Lookup in dict will give you better performance overall. You can use enumerate to give me both the index i and the value x from the list from user input. Then use int(x) as the key and associate it to the index.
The key should always be the data you have, and the value should always be the data you want. (We have a value, we want the index)
n = int(input())
k = {}
for i, x in enumerate(input().split()):
k[int(x)] = i
z = []
for i in range(n):
a = int(input())
if a in k:
z.append(k[a])
else:
z.append(-1)
print(z)
k looks like:
{2: 0, 1: 1, 3: 2}
This way you can call k[3] and it will give you 2 in O(1) or constant time.
(See. Python: List vs Dict for look up table)
There is a structure known as defaultdict which allows you to specify behaviour when a key is not present in the dictionary. This is particularly helpful in this case, as we can just request from the defaultdict and it will return the desired value either way.
from collections import defaultdict
n = int(input())
k = defaultdict(lambda: -1)
for i, x in enumerate(input().split()):
k[int(x)] = i
z = []
for i in range(n):
a = int(input())
z.append(k[a])
print(z)
While this does not speed up your program, it does make your second for loop easier to read. It also makes it easier to move into the comprehension in the next section.
(See. How does collections.defaultdict work?
With these things in place, we can use, yes, list comprehension, to very minimally speed up the construction of z and k. (See. Are list-comprehensions and functional functions faster than “for loops”?
from collections import defaultdict
n = int(input())
k = defaultdict(lambda: -1)
for i, x in enumerate(input().split()):
k[int(x)] = i
z = [k[int(input())] for i in range(n)]
print(z)
All code snippets print z as a list:
[1, -1, 2]
See Printing list elements on separated lines in Python if you'd like different print outs.
Note: The index function will find the index of the first occurrence of the value in a list. Because of the way the dict is built, the index of the last occurrence will be stored in k. If you need to mimic index exactly you should ensure that a later index does not overwrite a previous one.
for i, x in enumerate(input().split()):
x = int(x)
if x not in k:
k[x] = i
Adapt this solution for your problem.
def test(list1,value):
try:
return list1.index(value)
except ValueError as e:
print(e)
return -1
list1=[2, 1, 3]
in1 = [1,8,3]
res= [test(list1,i) for i in in1]
print(res)
output
8 is not in list
[1, -1, 2]

problem with nested while loops in Python

I have 2 lists of names, names_1 and names_2, they are both of the same length (1000), no list has duplicate names, each list contains 1000 unique names, but some names appear in both lists, I want to isolate the names that appear in both lists in a third list dup_names and remove them from the original lists, I tried the following code but it didn't work:
dup_names=[]
m=len(names_1)
i=0
k=0
COMPARED=[]
while i<m:
while k<m:
COMPARED.append((i,k))
if names_1[i]==names_2[k]:
dup_names.append(names_1[i])
names_1[i:i+1]=[]
names_2[k:k+1]=[]
m=m-1
k=0
else:
k=k+1
i=i+1
for i_k_pair in COMPARED:
print(i_k_pair)
print('len(COMPARED) =',len(COMPARED))
print('len(dup_names) =',len(dup_names))
print('len(names_1) =',len(names_1))
print('len(names_1) =',len(names_2))
I created the "COMPARED" list to check what (i,k) values got compared to each other, the output was:
(0,0)
(0,1)
.
.
.
(0,999)
len(COMPARED) = 1000
len(dup_names) = 0
len(names_1) = 1000
len(names_2) = 1000
from the i_k_pairs that got printed, I see that it only compaired the 1st name in names_1 (i=0) to all names in names_2, since len(dup_names) = 0, len(names_1) = 1000 and len(names_2) = 1000, I expext that len(COMPARED) = 1000000 but it looks like the is a problem with the outed loop, can anyone please explain what's wrong to me?!?!
I know that I can do the job with the following code:
dup_names=[]
for i in range(len(names_1)):
for k in range(len(names_2)):
if names_1[i]==names_2[k]:
dup_names.append(names_1[i])
new_names_1=[]
new_names_2=[]
for n in range(len(names_1)):
s1=0
s2=0
for m in range(len(dup_names)):
if names_1[n]==dup_names[m]:
s1=1
if names_2[n]==dup_names[m]:
s2=1
if s1==0:
new_names_1.append(names_1[n])
if s2==0:
new_names_2.append(names_2[n])
names_1=new_names_1
names_2=new_names_2
del new_names_1,new_names_2
I tried this code and it worked just fine, but what's really puzzling me is:
what's wrong with the first code???
why the outer while loop didn't work?!
is there a problem with nested while loops in Python?
This is comparing the two lists for duplicates and never compares anything already compared in names_1. I think there might be a well optimized one for this. If you wanna compare the two lists len(names_1) times len(names_2) better avoid removing elements from names_1 and names_2. The reason your code didn't work is, your code was not resetting i=0 to start the names_1 from the beginning after the second while loop.
dup_names=[]
names_1=["a","b","c","d","e"]
names_2=["f","g","h","a","d"]
m=len(names_1)
n=len(names_2)
i=0
k=0
COMPARED=[]
while i<m:
matched_any = False
while k<n:
COMPARED.append((i,k))
if names_1[i]==names_2[k]:
dup_names.append(names_1[i])
names_1[i:i+1]=[]
names_2[k:k+1]=[]
matched_any = True
break
else:
k=k+1
i=0
k=0
if not matched_any:
names_1[i:i+1]=[]
m=len(names_1)
n=len(names_2)
for i_k_pair in COMPARED:
print(i_k_pair)
print('len(COMPARED) =',len(COMPARED))
print('len(dup_names) =',len(dup_names))
print('len(names_1) =',len(names_1))
print('len(names_1) =',len(names_2))
Use Pythonic approach and set for solving your problem.
x = ["C++", "C", "Python"]
y = ["Java", "C"]
z = set(x).intersection(set(y))
x = [elt for elt in x if elt not in z]
y = [elt for elt in y if elt not in z]

Display only 1 element when it's a repetition

I would like print a result without duplicate with my multiplication
Here an example :
5*3*2=30
2*3*5=30
5*2*3=30
3*2*5=30
.....
All these element are from my list that I browse and you can see it's always =30
So I would like display only the first element (5*3*2) and not others because they are the same.
To be more accurate, here an example what I have :
list = ['5*3*2','5*2*3','2*3*5','2*5*3']
for i in list:
if eval(i) == eval(i)+1 ??? (I dont know how to say the next element)
print(eval(i))
Thanks for reading
Something like this with not in will help you.
#python 3.5.2
list = ['5*3*2','5*2*3','6*9','2*3*5','2*5*3','8*3','9*6']
elm = []
for i in list:
elm_value = eval(i)
if elm_value not in elm:
elm.append(elm_value)
print(elm)
DEMO: https://rextester.com/QKV22875
The comparison:
eval(i) == eval(i)+1
Will compare if the the number i is equal to i + 1, which will always return False. I'm sure you mean to use i as an index and simply wanted to compare if the current element is equal to the next element in the list. However, doing this doesn't really keep track of duplicates, since you have to consider everything else in the list.
Its also not a good idea to use list as a variable name, since it shadows the builtin function list. Plenty of other suitable names you can use.
One way is to use a set to keep track of what items you have seen, and only print items that you have seen for the first time:
lst = ["5*3*2","5*2*3","2*3*5","2*5*3"]
seen = set()
for exp in lst:
calc = eval(exp)
if calc not in seen:
print(calc)
seen.add(calc)
If you are always dealing with simple multiplying expressions with the * operator(no brackets), you could also use functools.reduce and operator.mul instead to multiply the numbers instead of eval here. This will first split the numbers by *, map each number string to an integer, then multiply every element with each other.
from operator import mul
from functools import reduce
lst = ["5*3*2","5*2*3","2*3*5","2*5*3"]
seen = set()
for exp in lst:
numbers = map(int, exp.split("*"))
calc = reduce(mul, numbers)
if calc not in seen:
print(calc)
seen.add(calc)
Output:
30
With the following list:
l = ['5*3*2','5*2*3','2*3*5','2*5*3', '2*2']
(Note that list is already something in python so I wouldn't recommend using that as a variable name)
I would first create a list of unique values:
unique_vals = set(map(eval, list))
set([4, 30])
Then for each unique values get the first match in l:
[next(x for x in l if eval(x) == i) for i in unique_vals]
I get:
['2*2', '5*3*2']
Is that what you want?

Categories