OOP python - removing class instance from a list - python

I have a list where I save the objects created by a specific class.
I would like to know, cause I can't manage to solve this issue, how do I delete an instance of the class from the list?
This should happen based on knowing one attribute of the object.

Iterate through the list, find the object and its position, then delete it:
for i, o in enumerate(obj_list):
if o.attr == known_value:
del obj_list[i]
break

You could use a list comprehension:
thelist = [item for item in thelist if item.attribute != somevalue]
This will remove all items with item.attribute == somevalue.
If you wish to remove just one such item, then use WolframH's solution.

You could have stored them in a dict and removed them by name
di = {"test" : my_instance()}
del di['test']

Related

How do I index f.items()?

I could run a for loop as such:
for v in f.items():
BUT, it takes too much time. I know I want the second object in f.items(). How to I directly get the second object and save it?
Im not sure what the syntax is: e.g is it f.items(2), f.items()[2]? None of these work so I was wondering what does.
If you want values(your 2nd objects) from f.items() you should use the below: -
for k,v in f.items()
Or if you want the 2nd item from f.items() you should use the below: -
f = {1:'A',2:'B',3:'C'}
for item in enumerate(f.items(),1):
k,v = item
if k == 2:
print(v)
Do still want to extract 2nd value from 2nd item ?
You can create a list and then index.
item = list(f.items())[1]
Lists are created often in python and this operation is relatively inexpensive. If your dictionary is large, you can create an iterator and take its second value.
i = iter(f.items())
next(i)
item = next(i)
But the dict would need to be rather large to make this the better option.

Python Remove Duplicate Dict

I am trying to find a way to remove duplicates from a dict list. I don't have to test the entire object contents because the "name" value in a given object is enough to identify duplication (i.e., duplicate name = duplicate object). My current attempt is this;
newResultArray = []
for i in range(0, len(resultArray)):
for j in range(0, len(resultArray)):
if(i != j):
keyI = resultArray[i]['name']
keyJ = resultArray[j]['name']
if(keyI != keyJ):
newResultArray.append(resultArray[i])
, which is wildly incorrect. Grateful for any suggestions. Thank you.
If name is unique, you should just use a dictionary to store your inner dictionaries, with name being the key. Then you won't even have the issue of duplicates, and you can remove from the list in O(1) time.
Since I don't have access to the code that populates resultArray, I'll simply show how you can convert it into a dictionary in linear time. Although the best option would be to use a dictionary instead of resultArray in the first place, if possible.
new_dictionary = {}
for item in resultArray:
new_dictionary[item['name']] = item
If you must have a list in the end, then you can convert back into a dictionary as such:
new_list = [v for k,v in new_dictionary.items()]
Since "name" provides uniqueness... and assuming "name" is a hashable object, you can build an intermediate dictionary keyed by "name". Any like-named dicts will simply overwrite their predecessor in the dict, giving you a list of unique dictionaries.
tmpDict = {result["name"]:result for result in resultArray}
newArray = list(tmpDict.values())
del tmpDict
You could shrink that down to
newArray = list({result["name"]:result for result in resultArray}.values())
which may be a bit obscure.

Generating dictionary of lists in a loop (3.2.3)

I need to create a dictionary where will be key a string and a value a list. The trick is I need to do it in a loop.
My minimalised code looks like this at the moment:
for elem in xmlTree.iter():
# skipping root element
if elem.tag == xmlTree.getroot().tag:
continue
# this is supposed to be my temporary list
tmpList = []
for child in elem:
tableWColumns[elem.tag] = tmpList.append(child.tag)
print(tableWColumns)
This prints only the list created in the last iteration.
Problem apparently lies in the fact that whenever I change the list, all of its references are changed as well. I Googled that. What I haven't Googled though is the way how can I deal with it when using a loop.
The solution I am supposed to use when I want to keep the list is to copy it to some other list and then I can change the original one without losing data. What I don't know is how do I do it, when I basically need to do this dynamically.
Also I am limited to use of standard libraries only.
The problem is because of that you are creating the tmpList = [] list in each iteration and put it [].So python replace the new with older in each iteration, thus you see the last iteration result in your list.
Instead you can use collections.defaultdict :
from collections import defaultdict
d=defaultdict(list)
for elem in xmlTree.iter():
# skipping root element
if elem.tag == xmlTree.getroot().tag:
continue
# this is supposed to be my temporary list
for child in elem:
d[elem.tag].append(child.tag)
print(tableWColumns)
Or you can use dict.setdefault method :
d={}
for elem in xmlTree.iter():
# skipping root element
if elem.tag == xmlTree.getroot().tag:
continue
# this is supposed to be my temporary list
for child in elem:
d.setdefault(elem.tag,[]).append(child.tag)
print(tableWColumns)
Also note as #abarnert says tmpList.append(child.tag) will return None.so after assignment actually python will assign None to tableWColumns[elem.tag].
The big problem here is that tmpList.append(child.tag) returns None. In fact, almost all mutating methods in Python return None.
To fix that, you can either do the mutation, then insert the value in a separate statement:
for child in elem:
tmpList.append(child.tag)
tableWColumns[elem.tag] = tmpList
… or not try to mutate the list in the first place. For example
tableWColumns[elem.tag] = tmpList + [child.tag for child in elem]
That will get rid of your all-values-are-None problem, but then you've got a new problem. If any tag appears more than once, you're only going to get the children from the last copy of that tag, not from all copies. That's because you build a new list each time, and reassign tableWColumns[elem.tag] to that new list, instead of modifying whatever was there.
To solve that problem, you need to fetch the existing value into tmpList instead of creating a new one:
tmpList = tableWColumns.get(elem.tag, [])
tableWColumns[elem.tag] = tmpList + [child.tag for child in elem]
Or, as Kasra's answer says, you can simplify this by using a defaultdict or the setdefault method.

Python 'NoneType' itterable in list operation

I am writing a function to remove duplication in one list. For specific:
input : a list
output: a list without any duplication
this is my code:
def remove_duplicate(s_list):
for member in s_list:
for other in s_list.remove(member):
if other == member:
s_list.remove(other)
return s_list
After that, I try to run remove_duplicate([1,2,3,4]) and the error is
for other in s_list.remove(member):
TypeError: 'NoneType' object is not iterable
I would suggest to work with two lists instead of changing one list in-place, if possible.
If order is not important, you can use a set:
dup_list = [1,1,2,3,2,5,2]
dupfree_list = list(set(dup_list))
Otherwise, if the order of elements is important, you can note which elements you have already seen:
dupfree_list = []
for e in dup_list:
if e not in dupfree_list:
dupfree_list.append(e)
I think the most Pythonic way is to use a set which removes duplicates:
listwithduplicates = [1,2,3,3]
listwithduplicates = set(listwithduplicates)
The result is:
{2,1,3}
Note that sets are not ordered the way lists are.

Finding values in a list of key/value pairs

I have 2 lists
old_name_list = [a-1234, a-1235, a-1236]
new_name_list = [(a-1235, a-5321), (a-1236, a-6321), (a-1234, a-4321), ... ]
I want to search recursively if the elements in old_name_list exist in new_name_list and returns the associated value with it, for eg. the first element in old_name_list returns a-4321, second element returns a-5321, and so on until old_name_list finishes.
I have tried the following and it doesn't work
for old_name, new_name in zip(old_name_list, new_name_list):
if old_name in new_name[0]:
print new_name[1]
Is the method I am doing wrong or I have to make some minor changes to it? Thank you in advance.
Build a dict() based on your second list, and lookup in that.
old_name_list = ["a-1234", "a-1235", "a-1236"]
new_name_list = [("a-1235", "a-5321"), ("a-1236", "a-6321"), ("a-1234", "a-4321") ]
d = dict(new_name_list)
for n in old_name_list:
print d[n]
You do need to put quotes around strings like "a-1234".
Using a dictionary may be the best way to do this.
old_name_list = ['a-1234', 'a-1235', 'a-1236']
new_name_list = [('a-1235', 'a-5321'), ('a-1236', 'a-6321'), ('a-1234, a-4321')]
mapping = dict(new_name_list)
values = [mapping[item] if item in mapping for item in old_name_list]
print values
Use this:
found_items = [item[1] for item in new_name_list if item[0] in old_name_list]

Categories

Resources