Check if element is list or another object - python

I've got an object which contains an element named "companies".
This element can either be a list of objects or just a single object (not contained within a list).
I would like to run through all companies, but this example fails if the element "companies" is just a single item (not contained within a list):
for company in companies:
I've tried to test before the for-loop, such as:
if type(companies['company']) is list:
# do your thing
but that fails as well.
Can anyone help?

Firstly, that's a really horrible way to structure data, and you should complain to whoever creates it. If an item can be a list, it should always be a list, even if that list just contains one element.
However, the code you have shown should work - although a better way to do it is if isinstance(companies['company'], list). If that's still not working, you will need to show the data, and the exact code that's using it.

You can make a list from a non-list for non-conditional use of "for ... in ...".
companies = list(companies)
for company in companies:
# use "company" in some way

Related

Problems with BeautifulSoup find_all

I need to retrieve a few ids from a site html, it's not a hard work to do if i create some variables to store them there, however i would like to use a list to make it easier to find and work with.
The terminal returns "TypeError: list indices must be integers or slices, not str" when using the following line:
ids = site.find_all('p', class_="frase fr")['id']
I mean, using soup.find_all works fine for me, though if i use the square brackets in the end to specify where it should gather the info it don't work. Here lies the problem, how can i fix it?
The find_all method returns a list of elements, so if you want to get only the IDs for each element you will have to iterate over each one and extract the desired information.
Use this instead:
ids = [p.get('id') for p in site.find_all('p', class_="frase fr")]
This will give you a list of every ID in the tags you find, including None ones.
You can also filter the None's out using:
ids = [p.get('id') for p in site.find_all('p', class_="frase fr") if p.get('id')]

passing fields of an array of collections through functions in python

is there a way of passing a field of an array of collections into a function so that it can still be used to access a element in the collection in python?. i am attempting to search through an array of collections to locate a particular item by comparing it with an identifier. this identifier and field being compared will change as the function is called in different stages of the program. is there a way of passing up the field to the function, to access the required element for comparison?
this is the code that i have tried thus far:
code ...
In your code, M_work is a list. Lists are accessed using an index and this syntax: myList[index]. So that would translate to M_work[place] in your case. Then you say that M_work stores objects which have fields, and you want to access one of these fields by name. To do that, use getattr like this: getattr(M_work[place], field). You can compare the return value to identifier.
Other mistakes in the code you show:
place is misspelled pace at one point.
True is misspelled true at one point.
The body of your loop always returns at the first iteration: there is a return in both the if found == True and else branches. I don't think this is what you want.
You could improve your code by:
noticing that if found == True is equivalent to if found.
finding how you don't actually need the found variable.
looking at Python's for...in loop.

Python delete multiple element(s) in list if in another list

I have two arrays, where if an element exists in an array received from a client then it should delete the matching array in the other array. This works when the client array has just a single element but not when it has more than one.
This is the code:
projects = ['xmas','easter','mayday','newyear','vacation']
for i in self.get_arguments('del[]'):
try:
if i in projects:
print 'PROJECTS', projects
print 'DEL', self.get_arguments('del[]')
projects.remove(i)
except ValueError:
pass
self.get_arguments('del[]'), returns an array from the client side in the format:
[u'xmas , newyear, mayday']
So it reads as one element not 3 elements, as only one unicode present.
How can I get this to delete multiple elements?
EDIT: I've had to make the list into one with several individual elements.
How about filter?
projects = filter(lambda a: a not in self.get_arguments('del[]'), projects)
Could try something uber pythonic like a list comprehension:
new_list = [i for i in projects if i not in array_two]
You'd have to write-over your original projects, which isn't the most elegant, but this should work.
The reason this doesn't work is that remove just removes the first element that matches. You could fix that by just repeatedly calling remove until it doesn't exist anymore—e.g., by changing your if to a while, like this:
while i in projects:
print 'PROJECTS', projects
print 'DEL', self.get_arguments('del[]')
projects.remove(i)
But in general, using remove is a bad idea—especially when you already searched for the element. Now you're just repeating the search so you can remove it. Besides the obvious inefficiency, there are many cases where you're going to end up trying to delete the third instance of i (because that's the one you found) but actually deleting the first instead. It just makes your code harder to reason about. You can improve both the complexity and the efficiency by just iterating over the list once and removing as you go.
But even this is overly complicated—and still inefficient, because every time you delete from a list, you're moving all the other elements of the list. It's almost always simpler to just build a new list from the values you want to keep, using filter or a list comprehension:
arguments = set(self.get_arguments('del[]'))
projects = [project for project in projects if project not in arguments]
Making arguments into a set isn't essential here, but it's conceptually cleaner—you don't care about the order of the arguments, or need to retain any duplicates—and it's more efficient—sets can test membership instantly instead of by comparing to each element.

Python, sets, Comparing two elements in the same set

If I have a python set and I want to find out if one element in the set is part of another element in the same set, how do I do it?
I've tried using indicies but I run into the following:
mySet = {"hello", "lo"}
mySet[1] in mySet[0] #I expect to return true
TypeError: 'set' object does not support indexing
I haven't found the python docs to be particularly helpful in this situation because I don't know how to compare elements within a set.
BTW, this is my first Stackoverflow question ever. I tried to adhere to the best practices. If there is a way I can improve the question, please let me know. Thank you for your help!
Sets don't have order. The index of an element is effectively the element itself. If you do need sets (although I have suspicions another data structure may be suitable) then they are iterable, and you can compare each element with other elements, but this won't be terrific performance wise, eg:
mySet = {"hello", "lo"}
for item in mySet:
for other_item in mySet.difference([item]):
if item in other_item:
print item, other_item
'set' object does not support indexing.
That clearly states that you can not index an element of set as mySet[1].
to access a single element of a set you have to use it like mySet.pop()
It looks like you're not actually trying to compare sets, but rather members of sets. The problem is you can't grab indexed members, because sets are an unordered (and as such unindexed) collection of elements.
You're trying to compare these two elements (strings). What you want is therefore a list or tuple:
>>> myTuple = ('hello', 'lo')
>>> myTuple[1] in myTuple[0]
True
This checks if the string 'lo' is a substring of 'hello'. This appears to be what you're trying to accomplish in your question.

Retrieving a specific set element in Python

Essentially this is what I'm trying to do:
I have a set that I add objects to. These objects have their own equality method, and a set should never have an element equal to another element in the set. However, when attempting to insert an element, if it is equal to another element, I'd like to record a merged version of the two elements. That is, the objects have an "aux" field that is not considered in its equality method. When I'm done adding things, I would like an element's "aux" field to contain a combination of all of the "aux" fields of equal elements I've tried to add.
My thinking was, okay, before adding an element to the set, check to see if it's already in the set. If so, pull it out of the set, combine the two elements, then put it back in. However, the remove method in Python sets doesn't return anything and the pop method returns an arbitrary element.
Can I do what I'm trying to do with sets in Python, or am I barking up the wrong tree (what is the right tree?)
Sounds like you want a defaultdict
from collections import defaultdict
D = defaultdict(list)
D[somekey].append(auxfield)
Edit:
To use your merge function, you can combine the code people have given in the comments
D = {}
for something in yourthings:
if something.key in D:
D[something.key] = something.auxfield
else:
D[something.key] = merge(D[something.key], something.auxfield)

Categories

Resources