How to remove elements from python class list - python-3.x

I am learning python oops. I am trying to remove an object (trying to remove all the student with mid = 1)from a class list.
for example -
stdents = [[[1], 'y', 'r'], [[2, 3], 'y', 'w'], [[1], 'z', 'r']]
I want to remove all id which contains 1.
here is my code -
class StudentTable:
def _init_(self, idList, name, state):
self.idList = []
self.name = name
self.state = state
stdents = []
student = StudentTable([1], 'y', 'r')
stdents.append(student)
student = StudentTable([2, 3], 'y', 'w')
stdents.append(student)
student = StudentTable([1], 'z', 'r')
stdents.append(student)
print(stdents[0].name)
print(stdents[1].name)
print(stdents[2].name)
mid = 1
for i in range(len(stdents)):
if mid in stdents[i].idList:
# del stdents[i]
stdents.remove(mid)
print(stdents)
But it's not removing.
Even I tried del but not working.
Can anyone please help me to resolve this issue?
Thanks in advance,
Khush

actually there is a simple mistake in line 3.
it should be self.idList = idList instead of self.idList = []
class StudentTable:
def __init__(self, idList, name, state):
self.idList = idList
self.name = name
self.state = state
stdents = []
student1 = StudentTable([1], 'a', 'r')
stdents.append(student1)
student2 = StudentTable([3], 'b', 'w')
stdents.append(student2)
student3 = StudentTable([1], 'c', 'r')
stdents.append(student3)
#print(stdents[0].name)
#print(stdents[1].name)
#print(stdents[2].name)
mid = 1
for i in (stdents):
#print(i.idList,i)
if mid in i.idList:
stdents.remove(i)
print(stdents)

Related

How to make a nested list in python

Suppose I have a 2 lists in my python script:
my_list = ['hat', 'bat']
other_list = ['A', 'B', 'C']
I want to iterate through other_list and create a nested list for 'bat's that adds '_' + other_list item to a the 'bat' and puts it in a nested list:
for item in other_list:
for thing in my_list:
if thing == 'bat':
print(thing + '_' + item)
My desired outcome would be new_list = ['hat',['bat_A', 'bat_B', 'bat_C']]
How would I achieve this?
I tried the below, but it produces this: ['hat', 'hat', 'hat', ['bat_A', 'bat_B', 'bat_C']]
new_list = []
extra = []
for item in other_list:
for thing in my_list:
if thing == 'bat':
extra.append(thing + '_' + item)
else:
new_list.append(thing)
new_list.append(extra)
Try this:
>>> my_list = ['hat', 'bat']
>>> other_list = ['A', 'B', 'C']
>>> new_list=[my_list[0], [f'{my_list[1]}_{e}' for e in other_list]]
>>> new_list
['hat', ['bat_A', 'bat_B', 'bat_C']]
If your question (which is a little unclear) is just about reacting to 'bat' with a different reaction, you can do this:
my_list = ['hat', 'bat','cat']
other_list = ['A', 'B', 'C']
new_list=[]
for e in my_list:
if e=='bat':
new_list.append([f'{e}_{x}' for x in other_list])
else:
new_list.append(e)
>>> new_list
['hat', ['bat_A', 'bat_B', 'bat_C'], 'cat']
Which can be reduced to:
>>> [[f'{e}_{x}' for x in other_list] if e=='bat' else e for e in my_list]
['hat', ['bat_A', 'bat_B', 'bat_C'], 'cat']
I think will work
my_list = ['hat', 'bat']
other = ['A', 'B' , 'C']
new_list = []
extra = []
for item in my_list:
if item == 'bat':
for char in other:
extra.append(item + '_' + char)
else:
new_list.append(item)
new_list.append(extra)
print(new_list)
OK, this is just my answer, but it seems to work. I think is clunky though, and I'm hoping for a better answer
my_list = ['hat', 'bat']
other_list = ['A', 'B', 'C']
new_list = []
extra = []
for item in other_list:
for thing in my_list:
if thing == 'bat':
extra.append(thing + '_' + item)
else:
if thing not in new_list:
new_list.append(thing)
new_list.append(extra)

Compare single element in two lists of lists and output the lists that do not match

I have 2 csv files. I am reading each of them into 2 separate list of lists.
Example: Each csv has 3 columns ['Device', 'User', 'Email']
Edit: I need to keep each list of 3 elements ONLY if element[0] does not match in both lists
list1 = [['hostname-a', 'john', 'john#domain.com'],
['hostname-b', 'joe', 'joe#domain.com'],
['hostname-c', 'jane', 'jane#domain.com'],
['hostname-d', 'bob', 'bob#domain.com']]
list2 = [['hostname-a', 'sally', 'sally#domain.com'],
['hostname-b', 'harry', 'harry#domain.com']]
Targeted Output:
missing_devices = [['hostname-c', 'jane', 'jane#domain.com'],
['hostname-d', 'bob', 'bob#domain.com']]
import csv, re
def start():
file1 = "C:/path/to/file/file1.csv"
file2 = "C:/path/to/file/file2.csv"
list1 = list_1(file1)
list2 = list_2(file2)
## This is where I seem to be hung up. This list comprehension isn't working, but hope it shows what I am trying to accomplish
diff_list = [x for x[0] in list2 if x[0] not in list1]
filename = "devices_missing_from_list_2.csv"
output_csv(diff_list, filename)
def list_1(file1):
with open(file1, "r") as file1:
devices = csv.DictReader(file1, delimiter=',')
list1 = []
for x in devices:
host = x["Device"]
user = x["User"]
email = x["Email"]
host = host.lower()
list1.append([host, user, email])
return list1
def list_2(file2):
with open(file2, "r") as file2:
devices = csv.DictReader(file2, delimiter=',')
list2 = []
for x in devices:
host = x["Device"]
user = x["User"]
email = x["Email"]
host = host.lower()
list2.append([host, user, email])
return list2
def output_csv(diff_list, filename):
with open(filename, 'w', encoding='utf-8', newline='') as outfile:
header = ['Device', 'User', 'Email']
writer = csv.writer(outfile)
writer.writerow(header)
for row in server_list:
writer.writerow([row[0], row[1], row[2]])
if __name__ == "__main__":
start()
list1 = [['hostname-a', 'john', 'john#domain.com'],
['hostname-b', 'joe', 'joe#domain.com'],
['hostname-c', 'jane', 'jane#domain.com'],
['hostname-d', 'bob', 'bob#domain.com']]
list2 = [['hostname-a', 'sally', 'sally#domain.com'],
['hostname-b', 'harry', 'harry#domain.com']]
missing_devices = [['hostname-c', 'jane', 'jane#domain.com'],
['hostname-d', 'bob', 'bob#domain.com']]
first_set_1 = {i[0] for i in list1}
first_set_2 = {i[0] for i in list2}
diff_set = first_set_1.difference(first_set_2)
print(diff_set)
final_list = [i for i in list1 if i[0] in diff_set]
print(final_list)
"""
{'hostname-d', 'hostname-c'}
[['hostname-c', 'jane', 'jane#domain.com'], ['hostname-d', 'bob', 'bob#domain.com']]
"""

The problem of using {}.fromkey(['k1','k2'],[]) and {'k1':[],'k2':[]}

list1 = [99,55]
dict1 = {'k1':[],'k2':[]}
for num in list1:
if num > 77:
dict1['k1'].append(num)
else:
dict1['k2'].append(num)
print(dict1)
{'k1':[99],'k2':[55]}
But when I replaced dict1 = {'k1':[],'k2':[]} to {}.fromkeys(['k1','k2'],[]) , the result became {'k1': [99, 55], 'k2': [99, 55]}
why this happens? I really have no idea.
This happens because you are passing the same list object to both keys. This is the same situation as when you create an alias for a variable:
a = []
b = a
a.append(55)
b.append(99)
print(b)
prints [55, 99] because it is the same list instance.
If you want to make it more concise from a list of keys to initialize with empty list, you can do this:
dict1 = {k: [] for k in ('k1', 'k2')}
This will create a new list instance for every key.
Alternatively, you can use defaultdict
from collections import defaultdict
list1 = [99,55]
dict1 = defaultdict(list)
for num in list1:
if num > 77:
dict1['k1'].append(num)
else:
dict1['k2'].append(num)
print(dict1)
Also works.
The fromKeys() can also be supplied with a mutable object as the default value.
if we append value in the original list, the append takes place in all the values of keys.
example:
list1 = ['a', 'b', 'c', 'd']
list2 = ['SALIO']
dict1 = dict.fromkeys(list1, list2)
print(dict1)
output:
{'a': ['SALIO'], 'b': ['SALIO'], 'c': ['SALIO'], 'd': ['SALIO']}
then you can use this:
list1 = ['k1', 'k2']
dict1 = {'k1':[],'k2':[]}
list2 =[99,55]
for num in list2:
if num > 77:
a = ['k1']
dict1 = dict.fromkeys(a, [num])
else:
b = ['k2']
dict2 = dict.fromkeys(b,[num] )
res = {**dict1, **dict2}
print(res)
output:
{'k1': [99], 'k2': [55]}
You can also use the python code to merge dict code:
this function:
def Merge(dict1, dict2):
return(dict2.update(dict1))
then:
print(Merge(dict1, dict2)) #This return None
print(dict2) # changes made in dict2

Getting index of duplicate letters in a string

from graphics import *
import random
def hangman(word):
returnStuff = {'again':0, '1st':1}
alphabet = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z']
win = GraphWin("Hangman", 800, 550)
win.setBackground("yellow")
titleText = Text(Point(400,50), 'HANGMAN')
titleText.setSize(24)
titleText.setStyle('bold')
titleText.draw(win)
#Building the hangman base
base = Line(Point(120,350),Point(230,350))
base.draw(win)
stand = Line(Point(175,350),Point(175,150))
stand.draw(win)
stand2 = Line(Point(175,150),Point(250,150))
stand2.draw(win)
stand3 = Line(Point(250,150),Point(250,180))
stand3.draw(win)
#drawing the empty lines for the word
x1 = 150
x2 = 180
l = 0
print(word)
while l< len(word):
wordLine = Line(Point(x1, 420),Point(x2,420))
wordLine.draw(win)
l+=1
x1+=40
x2+=40
guessCounter = 0
textCheck = 0
invalidText = Text(Point(600,100), 'You did not enter a valid letter.')
invalidText.setTextColor('red')
indexes = []
while guessCounter < 6:
#text entry box
textEntry = Entry(Point(600,180),10)
textEntry.draw(win)
guessText = Text(Point(600,150), 'Guess a letter:')
guessText.draw(win)
#user has to click this box to confirm the letter
enterBox = Rectangle(Point(580,200), Point(620,220))
enterBox.setFill('white')
enterBox.draw(win)
clickText = Text(Point(600,210), 'Enter')
clickText.draw(win)
click = win.getMouse()
x = click.getX()
y = click.getY()
if 580 < x < 620 and 200 < y < 220:
guess = textEntry.getText().lower().strip()
if guess not in alphabet:
if textCheck == 0:
invalidText.draw(win)
textCheck = 1
else:
if textCheck == 1:
invalidText.undraw()
textCheck = 0
for letter in word:
if letter == guess:
indexes.append(word.index(guess))
print(indexes)
win.getMouse()
win.close()
return returnStuff
#list with various words pertaining to nanotechnology
words = ['nanotechnology', 'science', 'nanometre' , 'strength', 'chemistry',
'small', 'molecule', 'light' , 'weight', 'technology', 'materials',
'property', 'physics', 'engineering', 'matter', 'waterloo', 'nanobot',
'reaction', 'structure', 'cells']
#picks a random word from the list
word = random.choice(words)
#this variable ensures it opens the game the first time
initialCall = 1
#stores the returnValue for the first call
returnValue = hangman(word)
#sets the initialCall to 0 after first call
if returnValue['1st']==1:
initialCall=0
#Calls the game function again if user wishes
while initialCall == 1 or returnStuff['again'] == 1:
returnValue = hangman(word)
I am making Hangman in Python graphics. I apologize for the huge block of code, it all works fine, I just thought it must be useful. The part of the code that I'm concerned about is this:
else:
if textCheck == 1:
invalidText.undraw()
textCheck = 0
for letter in word:
if letter == guess:
indexes.append(word.index(guess))
print(indexes)
This block of code will be executed when the user's letter guess is in the alphabet, I then run through each letter in the chosen word, and if at any point a letter in the word is the same as the guess letter, I store the index of that letter in a empty list so I can use that to tell the computer where to draw the letters on the empty lines.
It works fine, with the exception of when there is a duplicate letter in the word. For example, engineering has 3 es. Unfortunately, .index() only records the index for when the letter appears the first time, and it disregards the other letters. What is the work around for this so I can get the indexes of all 3 es in that word, instead of 3 indexes of just the first e. For testing purposes, I have printed the chosen word and the index list on the console so I can see what's going on and so I don't actually have to guess a letter.
you can do something like this
def indexes(word,letter):
for i,x in enumerate(word):
if x == letter:
yield i
test
>>> list( indexes("engineering","e") )
[0, 5, 6]
>>>
this function is a generator, that is a lazy function that only give result when asked for then, to get a individual result you use next, the functions is execute until the first yield then return the result and stop its execution and remember where it was, until another call to next is executed in witch point resume execution from the previous point until the next yield, if the is no more raise StopIteration, for example:
>>> word="engineering"
>>> index_e = indexes(word,"e")
>>> next(index_e)
0
>>> print(word)
engineering
>>> next(index_e)
5
>>> next(index_e)
6
>>> next(index_e)
Traceback (most recent call last):
File "<pyshell#13>", line 1, in <module>
next(index_e)
StopIteration
>>>
to update a list with the result of this function, you can use the extend method
>>> my_list=list()
>>> index_e = indexes(word,"e")
>>> my_list.extend( index_e )
>>> my_list
[0, 5, 6]
>>>
generator are used in cases where their result is only a intermediary step to something else because they use a minimum amount of memory, but in this case maybe you want the whole thing so use it as the first example or remake the function to return a list in the first place like this
def indexes(word,letter):
result = list()
for i,x in enumerate(word):
if x == letter:
result.append(i)
return result
sorry if I confuse you with the yield thing.

Inserting list into another list using loops only:

I'm using the current version of python. I need to return a copy of list1 with list2 inserted at the position indicated by index i.e if the index value is 2, list2 is inserted into list 1 at position 2. I can only use for/while loops, the range function & the list_name.append (value) methods and the lists cannot be sliced. So if list1 list1 = boom list2 = red and the index value = 2, how do I return a new list = boredom? I have this so far:
list1 = ['b','o','o','m']
list2 = ['r','e','d']
index = 2
new_list = []
if index > len(list1):
new_list = list1 + list2
print (new_list)
if index <= 0:
new_list = list2 + list1
print (new_list)
An alternative approach to Padriac's - using three for loops:
list1 = ['b','o','o','m']
list2 = ['r','e','d']
n = 2
new_list = []
for i in range(n): # append list1 until insert point
new_list.append(list1[i])
for i in list2: # append all of list2
new_list.append(i)
for i in range(n, len(list1)): # append the remainder of list1
new_list.append(list1[i])
Once you hit the index, use an inner loop to append each element from list2:
for ind, ele in enumerate(list1):
# we are at the index'th element in list1 so start adding all
# elements from list2
if ind == index:
for ele2 in list2:
new_list.append(ele2)
# make sure to always append list1 elements too
new_list.append(ele)
print(new_list)
['b', 'o', 'r', 'e', 'd', 'o', 'm']
If you must use range just replace enumerate with range:
new_list = []
for ind in range(len(list1)):
if ind == index:
for ele2 in list2:
new_list.append(ele2)
new_list.append(list1[ind])
print(new_list)
['b', 'o', 'r', 'e', 'd', 'o', 'm']
Or without ifs using extend and remove if allowed:
new_list = []
for i in range(index):
new_list.append(list1[i])
list1.remove(list1[i])
new_list.extend(list2)
new_list.extend(list1)
Appending as soon as we hit the index means the elements will be inserted from the correct index, the elements from list1 must always be appended after your if check.
Check out this small snippet of code I've written.
Check the while condition that is used. I hope it will answer your question.
email = ("rishavmani.bhurtel#gmail.com")
email_split = list(email)
email_len = len(email)
email_uname_len = email_len - 10
email_uname = []
a = 0
while (a < email_uname_len):
email_uname[a:email_uname_len] = email_split[a:email_uname_len]
a = a + 1
uname = ''.join(email_uname)
uname = uname.replace(".", " ")
print("Possible User's Name can be = %s " %(uname))

Resources