Can anyone help me figure the list comprehension way of producing following output -
Let given list be -
results = [
{"id": 1, "name": "input"},
{"name": "status", "desc": "Status"},
{"name": "entity", "fields": [
{"id": 101, "name": "value"},
{"id": 102, "name": "address"}]
}
]
And I am looking for output in the form of list.
The code to get the output is:
output = []
for eachDict in results:
if "fields" in eachDict:
for field in eachDict["fields"]:
output.append(eachDict["name"]+"."+field["name"])
else:
output.append(eachDict["name"])
Thus the output using above code is -
['input', 'status', 'entity.value', 'entity.address']
Is it possible to get similar output using if else nested for loops in list Comprehension?
I am having trouble trying to get access to that inner for loop in if condition of list Comprehension
My attempt -
output = [eachDict["name"]+"."+field["name"] for field in eachDict["fields"] if "fields" in eachDict else eachDict["name"] for eachDict in results]
One way to transform your code into workable code would be to make the inner loop produce lists, and then flatten the result afterward.
sum(([d['name'] + '.' + f['name'] for f in d['fields']]
if d.get('fields') else [d['name']] for d in results), [])
A list comprehension has a fixed number of (nested) loops. So must have two loops here, one over the top-level dictionaries, and one over the fields. The trick is to produce one iteration in the nested loop if there are no fields:
[d['name'] + fieldname
for d in results
for fieldname in (
('.' + sub['name'] for sub in d['fields']) if 'fields' in d else
('',))
]
The for fieldname loop loops either over the names of the fields sub-directories (with '.' prefixed), or over a tuple with just a single empty string in it.
Note that this isn't actually all that readable. I'd delegate producing the fieldname loop to a helper generator function to improve that:
def fieldnames(d):
if 'fields' in d:
for sub in d['fields']:
yield '.' + sub['name']
else:
yield ''
[d['name'] + fieldname for d in results for fieldname in fieldnames(d)]
Demo:
>>> def fieldnames(d):
... if 'fields' in d:
... for sub in d['fields']:
... yield '.' + sub['name']
... else:
... yield ''
...
>>> [d['name'] + fieldname for d in results for fieldname in fieldnames(d)]
['input', 'status', 'entity.value', 'entity.address']
Related
I have the following problem. I want to compare two lists with dictionaries and find matches.
Schema List A:
[
{
authorID: string,
articleID: string
}
]
Schema List B:
[
{
authorID: string,
firstName: string,
lastName: string
}
]
The length of the list A is 1653 and the list B is 1344 long.
This is my code with which I tried to compare the lists and resave the matches.
def unitedListArticleAuthor(listA, listB):
new_list = []
for article in listA:
for author in listB:
if article["authorID"] == author["authorID"]:
new_list.append({
"articleID": article["articleID"],
"authorID": article["authorID"],
"firstName": author["firstName"],
"lastName": author["lastName"],
})
Now the length of the new list is 1667. That means somewhere a mistake must have happened, because the list A is the biggest and only has to be matched with the list B. Only the author ID's should be matched to add the name of the author to each article.
What is my mistake?
As Sayse said, it is likely that there are multiple instances of the same authorID.
You seem really sure that this is not the case, but try adding a break statement like this:
def unitedListArticleAuthor(listA, listB):
new_list = []
for article in listA:
for author in listB:
if article["authorID"] == author["authorID"]:
new_list.append({
"articleID": article["articleID"],
"authorID": article["authorID"],
"firstName": author["firstName"],
"lastName": author["lastName"],
})
break
I'm looking for code to do same thing as the function below, but in fewer lines if possible. Just out of curiosity.
def matchingStrings(strings, queries):
results = []
for i in range(len(queries)):
temp_list = queries[i]
results.append(strings.count(temp_list))
return results
This function is taking a list of strings and a list of queries. Searching for counts of queries in strings list. Creating a new list from that numbers.
Input:
strings = ["aaa", "abc", "zzz", "xyz", "asd", "aaa"]
queries = ["aa", "aaa", "xyz"]
Output:
[0, 2, 1]
It's easy to write this in one line if you already know how to. Here I show how to arrive at the result by transforming the existing code:
The pattern
for i in range(len(some_list)):
value = some_list[i]
# ...
is equivalent to
for value in some_list:
# ...
The pattern
results = []
for X in Y:
results.append(f(X))
is equivalent to
results = [f(X) for X in Y]
This is known as a list comprehension.
So when applying the first transformation, your code becomes
def matchingStrings(strings, queries):
results = []
for temp_list in queries:
results.append(strings.count(temp_list))
return results
and when applying the second transformation (f being strings.count), it becomes
def matchingStrings(strings, queries):
return [strings.count(temp_list) for temp_list in queries]
Remark: temp_list is a bad name, as queries contains strings, not lists. A better name would be simply query.
Since you're looking for the counts of exact matches (and not substring matches) you can use a Counter object to get the counts for every value in the strings list, then use a list comprehension to get the count for each query.
from collections import Counter
def matchingStrings(strings, queries):
str_counts = Counter(strings)
return [str_counts[q] for q in queries]
s = ["aaa", "abc", "zzz", "xyz", "asd", "aaa"]
q = ["aa", "aaa", "xyz"]
print(matchingStrings(s, q))
For large lists of queries and strings, this will be faster than calling count inside the loop (or list comprehension).
You could use list comprehension:
def matchingStrings(strings, queries):
return [strings.count(item) for item in queries]
strings = ["aaa", "abc", "zzz", "xyz", "asd", "aaa"]
queries = ["aa", "aaa", "xyz"]
print(matchingStrings(strings, queries))
Output:
[0, 2, 1]
I have the following list and am wanting to convert it into a dictionary where the 4 digit value at the start of each item becomes the id.
['3574,A+,2021-03-24', '3575,O+,2021-04-03', '3576,AB-,2021-04-09', '3580,AB+,2021-04-27', '3589,A+,2021-05-08', '3590,B-,2021-05-11']
I have tried many different methods but it doesn't seem to work.
You can use str.split, map and dictionary comprehension
# data holds the list you have provided
{splitted[0]:splitted[1:] for splitted in map(lambda item:item.split(','), data)}
OUTPUT:
Out[35]:
{'3574': ['A+', '2021-03-24'],
'3575': ['O+', '2021-04-03'],
'3576': ['AB-', '2021-04-09'],
'3580': ['AB+', '2021-04-27'],
'3589': ['A+', '2021-05-08'],
'3590': ['B-', '2021-05-11']}
You can use dictionary comprehension with str.split:
lst = [
"3574,A+,2021-03-24",
"3575,O+,2021-04-03",
"3576,AB-,2021-04-09",
"3580,AB+,2021-04-27",
"3589,A+,2021-05-08",
"3590,B-,2021-05-11",
]
out = {int(v.split(",")[0]): v.split(",")[1:] for v in lst}
print(out)
Prints:
{
3574: ["A+", "2021-03-24"],
3575: ["O+", "2021-04-03"],
3576: ["AB-", "2021-04-09"],
3580: ["AB+", "2021-04-27"],
3589: ["A+", "2021-05-08"],
3590: ["B-", "2021-05-11"],
}
Here is the code to do what I believe you asked for. I have also added comments in the code for a bit more clarification.
my_list = ['3574,A+,2021-03-24',
'3575,O+,2021-04-03',
'3576,AB-,2021-04-09',
'3580,AB+,2021-04-27',
'3589,A+,2021-05-08',
'3590,B-,2021-05-11']#your list
my_dict = {}#The dictionary you want to put the list into
print("Your list:", my_list, "\n")
for item in my_list:#cycles through every item in your list
ID, value = item.split(",", 1)#Splits the item in your list only once (when it sees the first comma)
print(ID + ": " + value)
my_dict[ID] = value#Add the ID and value to your dictionary
print("\n" + "Your desired dictionary:", my_dict)
Which outputs this:
Your list: ['3574,A+,2021-03-24', '3575,O+,2021-04-03', '3576,AB-,2021-04-09', '3580,AB+,2021-04-27', '3589,A+,2021-05-08', '3590,B-,2021-05-11']
3574: A+,2021-03-24
3575: O+,2021-04-03
3576: AB-,2021-04-09
3580: AB+,2021-04-27
3589: A+,2021-05-08
3590: B-,2021-05-11
Your desired dictionary: {'3574': 'A+,2021-03-24', '3575': 'O+,2021-04-03', '3576': 'AB-,2021-04-09', '3580': 'AB+,2021-04-27', '3589': 'A+,2021-05-08', '3590': 'B-,2021-05-11'}
Enjoy!
TRY:
result = dict(i.split(',', 1) for i in lst)
OUTPUT:
{'3574': 'A+,2021-03-24',
'3575': 'O+,2021-04-03',
'3576': 'AB-,2021-04-09',
'3580': 'AB+,2021-04-27',
'3589': 'A+,2021-05-08',
'3590': 'B-,2021-05-11'}
I have a dictionary that contains strings as keys and lists as values.
I'd like to remove all list elements that contain the strings "food", "staging", "msatl" and "azeus". I have the below code already, but am having a hard time applying the logic I have in filterIP to the rest of the strings I have.
def filterIP(fullList):
regexIP = re.compile(r'\d{1,3}.\d{1,3}.\d{1,3}.\d{1,3}$')
return filter(lambda i: not regexIP.search(i), fullList)
groups = {key : [domain.replace('fake.com', 'env.fake.com')
for domain in filterIP(list(set(items)))]
for (key, items) in groups.iteritems() }
for key, value in groups.iteritems():
value.sort()
meta = { "_meta" : { "hostvars" : hostvars } }
groups.update(meta)
print(self.json_format_dict(groups, pretty=True))
Example of current output
"role_thumper": [
"thumper-msatl1-prod-1.env.fake.com",
"thumper-msatl1-prod-2.env.fake.com",
"thumper-rwva1-prod-1.env.fake.com",
"thumper-rwva1-prod-2.env.fake.com",
"thumper-rwva1-prod-3.env.fake.com",
"thumper-rwva1-prod-4.env.fake.com",
"thumper-rwva1-prod-5.env.fake.com",
"thumper-rwva1-prod-6.env.fake.com",
"thumper-staging-1.env.fake.com"
],
"role_thumper_mongo": [
"thumper-mongo-staging-1.env.fake.com",
"thumper-mongo-staging-2.env.fake.com",
"thumpermongo-rwva1-staging-1.env.fake.com",
"thumpermongo-rwva1-staging-2.env.fake.com"
],
"role_thumper_mongo_arb": [
"thumper-mongo-arb-staging-1.env.fake.com",
"thumpermongo-arb-rwva1-staging-1.env.fake.com"
],
A list comprehension is what you're after
x= ["a", "b", "aa", "aba"]
x_filtered = [i for i in x if "a" not in i]
print(x_filtered)
>>> ['b']
This is just shorthand for a for loop.
x_filtered = []
for i in x:
if "a" not in i:
x_filtered.append(i)
A simple way to accomplish your task would be to iterate over each lists in the dictionary. Create new lists based upon your criteria, and assign the new lists to the same keys but in a new dictionary. Here is how that would look like in code:
def filter_words(groups, words):
d = {}
for key, domains in groups.iteritems():
new_domains = []
for domain in domains:
if not any(word in domain for word in words):
new_domains.append(domain)
d[key] = new_domains
return d
And you would call it like so:
groups = filter_words(groups, {"food", "staging", "msatl" and "azeus"})
The "meat" of the code above is the second for loop:
for domain in domains:
if not any(word in domain for word in words):
new_domains.append(domain)
This code goes over each string in the current key's list, and filters out all invalid strings according to a list of invalid words.
If I understand you correctly, this might help.
Set up an exclude list:
exclude= ["food", "staging", "msatl", "azeus"]
Test list ( I couldn't really find instances in your examples)
test= ["food", "staging", "msatl", "azeus", "a", "bstaging"]
Run list comprehension (the name of iterators don't matter, you can pick more appropriate ones)
result= [i for i in test if not any([e for e in exclude if e in i])]
result
['a']
The answer above by #Julian gives a good explanation of what list comprehensions do. This uses two of them, the any part is True if there is any match in the exclude list.
Hope this helps.
I have a movietimes={}
It a dict I make by this code:
for i in Showtime.objects.filter(movie_id=movieid,theater_id=theaterid,datetime__range=(today,tomorrow))):
if i.mvtype not in movietimes:
movietimes[i.mvtype] = []
if not i.movietime > today :
movietimes[i.mvtype].append(i.movietime.strftime('%Y-%m-%dT%H:%M:%S.%fZ'))
if not movietimes : #this have bug
for i in Showtime.objects.filter(movie_id=movieid,datetime__range=(yesterday,today)):
if i.mvtype not in movietimes:
movietimes[i.mvtype] = []
movietimes[i.mvtype].append(i.movietime.strftime('%Y-%m-%dT%H:%M:%S.%fZ'))
return movietimes
result like this:
"Times": {
"ONE: [
"2014-12-24T10:40:00.000000Z",
"2014-12-24T12:45:00.000000Z",
"2014-12-25T14:50:00.000000Z"
]
}
I want to ask how can't I judge that if the [] in the 'ONE' part is null ??
I can't use if not movietimes={}: ,because there is u'ONE': [] in the dict
I have to judge the first list in the dict is empty . And there are many types u'ONE',u'TWO',u'Three'
they are catch by i.mvtype
{u'ONE': []}
{u'TWO': []}
{u'Three': []}
Please help me ,Thank you
if not movietimes["Times"]["ONE"]:
# you have empty list
That is presuming by first you mean the key ONE as dicts are not ordered
If you want to see if there is any empty list and your dict is like below:
movietimes = {"Times":{"ONE":[2],"TWO":[]}}
for val in movietimes["Times"].itervalues():
if not any(x for x in val):
# you have empty list