Given list1 below, how do I return a new list where the values of 'codes' contain the string 'Two' but does not contain the string 'One'?
# Example, given list1:
list1 = [{'id': 11, 'codes': ['OneSeven', 'TwoThree']}, {'id': 22, 'codes': ['FiveTwoSix', 'Four', 'FourFive']}, {'id': 33, 'codes': ['SixSeven', 'OneSix']}]
# Return list with element where 'id': 22 since the string 'Two' is in codes but 'One' isn't.
list2 = [{'id': 22, 'codes': ['FiveTwoSix', 'Four', 'FourFive']}]
# Example, given list1:
list1 = [{'id': 11, 'codes': ['OneSeven', 'TwoThree']}, {'id': 22, 'codes': ['FiveTwoSix', 'Four', 'FourFive']}, {'id': 33, 'codes': ['SixSeven', 'OneSix']}]
list2 = [
d for d in list1
if any(
'Two' in word
for word in d['codes']
) and all(
'One' not in word
for word in d['codes']
)
]
print(list2)
output:
[{'id': 22, 'codes': ['FiveTwoSix', 'Four', 'FourFive']}]
If you don't like redundant traversing lists, you can variable alternatives.
For python 3.8 or later, you can do this:
# Example, given list1:
list1 = [{'id': 11, 'codes': ['OneSeven', 'TwoThree']}, {'id': 22, 'codes': ['FiveTwoSix', 'Four', 'FourFive']}, {'id': 33, 'codes': ['SixSeven', 'OneSix']}]
list2 = [
d for d in list1
if 'Two' in (text := ' '.join(d['codes'])) and 'One' not in text
]
print(list2)
Of course, using for-statement instead of comprehension, you can do this with 3.7 or earlier version.
list2 = []
for d in list1:
text = ' '.join(d['codes'])
if 'Two' in text and 'One' not in text:
list2.append(d)
Or use function + comprehension:
def check_condition(data: dict) -> bool:
text = ' '.join(data['codes'])
return'Two' in text and 'One' not in text
list2 = [
d for d in list1 if check_condition(d)
]
Last one is quite readable, but someone might dislike declaring function which is used in only one place.
Choose a method fits your situation.
Related
I have a list of strings that I want to use to filter the text inside a nested dictionary. If one of the list items appear in the nested text, I would like to create a new list of dictionaries, with the list item as its parent key&value and the corresponding texts where the list item appears as nested list of dictionaries inside this parent key&value.
The list for filtering:
my_list = ['cat', 'dog', 'horse']
The current list of dictionaries looks something like this:
list_dicts = [{'id':1, 'text': 'This is a cat'}, {'id': 2, 'text': 'The man had a dog'},
{'id': 3, 'text': 'There was a cat'}]
Desired output:
desired_output = [{'name': 'cat', 'matching_texts':[{'id': 1, 'text': 'This is a cat'},
{'id': 3,'There was a cat'}], {'name': 'dog', 'matching_texts':[{'id':2,
'text': 'The man had a dog'}]}]
The best I can do for now is finding when an item of my_list appears in list_dicts. I thought about using setdefault method but I am unsure whether I am going in the right direction.
My code:
dic = {}
for d in list_dicts:
for k,v in d.items():
if k == 'text':
for i in my_list:
if i in v:
dic.setdefault(i,v)
Here's a simple solution using iteration:
main_list = []
for i in my_list:
curr_dic = {"name": i, "matching_texts": []}
for dic in list_dicts:
if i in dic.get("text", ""):
curr_dic["matching_texts"].append(dic)
if curr_dic["matching_texts"]:
main_list.append(curr_dic)
print(main_list)
Here is a simple solution using dict comprehension.
results = []
for animal in my_list:
temp = {"name": animal, "matching_texts": [element for element in list_dicts if animal in element.get("text")]}
if temp.get("matching_texts"): results.append(temp)
print(results)
my solution
my_list = ['cat', 'dog', 'horse']
list_dicts = [{'id':1, 'text': 'This is a cat'}, {'id': 2, 'text': 'The man had a dog'},
{'id': 3, 'text': 'There was a cat'}]
aa=[]
a={'name':'','matching_texts':[]}
for x in my_list:
for y in list_dicts:
if y['text'].find(x)>=0:
a['name']=x
a['matching_texts'].append(y)
if a['name']!='':aa.append(a)
a={'name':'','matching_texts':[]}
print(aa)
Personally, I find the solutions here a bit hard to read. I would write something like:
for current_word in my_list:
matching_entries = [entry for entry in list_dicts if current_word in entry['text']]
if matching_entries:
output.append({'name': current_word, 'matching_texts': matching_entries})
The output is the same:
[
{'name': 'cat', 'matching_texts': [
{'id': 1, 'text': 'This is a cat'},
{'id': 3, 'text': 'There was a cat'}
]},
{'name': 'dog', 'matching_texts': [
{'id': 2, 'text': 'The man had a dog'}
]}
]
I need to make a list of dictionary from two list. keys of the dictionary is are fixed.
list1 = ['a','b','c']
list2 = [1,2,3]
i need to create a list of dictionary like this,
final_list = [{'name':'a','age':1},{'name':'b','age':2},{'name':'c','age':3}]
final_list = [{"name": x, "age": y} for x, y in zip(list1, list2)]
list1 = ['a','b','c']
list2 = [1,2,3]
final_list = []
for i in range(len(list1)):
final_list.append({'name': list1[i], 'age': list2[i]})
final_list = [{'name':x, 'age':y} for (x,y) in zip(list1, list2)]
Out: [{'name': 'a', 'age': 1}, {'name': 'b', 'age': 2}, {'name': 'c', 'age': 3}]
I have a list of keys and a list of value lists.
What I need to do is to convert these two lists to a single list with dictionaries.
I have a key list:
keys = ['id','firstname','lastname']
My value list is like:
values = [[23,'abc','gef'],[24,'aabb','ppqq']]
The expected output is:
data = [{'id':23,'firstname':'abc','lastname':'gef'}, {'id':24,'firstname':'aabb','lastname':'ppqq'}]
I will be working with a large list as 'values' list. Is there any efficient 'pythonic' way to do this?
Try a simple list comprehension:
>>> keys = ['id','firstname','lastname']
>>> values = [[23,'abc','gef'],[24,'aabb','ppqq']]
>>> [dict(zip(keys, value)) for value in values]
[{'id': 23, 'firstname': 'abc', 'lastname': 'gef'}, {'id': 24, 'firstname': 'aabb', 'lastname': 'ppqq'}]
a one-liner would be data = [{k:v for k, v in zip(keys, v)} for v in values] which combines a list comp and dict comp
>>> keys =['id','name1','name2']
>>> values = [[23, 'a','g'],[24,'ab','cc']]
>>> data = [{k:v for k, v in zip(keys, v)} for v in values]
>>> data
[{'id': 23, 'name1': 'a', 'name2': 'g'}, {'id': 24, 'name1': 'ab', 'name2': 'cc'}]
Using list comprehension.
zip() is to map the similar index of multiple containers so that they can be used just using as single entity.
keys = ['id','firstname','lastname']
value = [[23, 'abc', 'gef'], [24, 'aabb', 'ppqq']]
data = [{k:v for k,v in zip(keys,v)} for v in value ]
print(data)
O/P:
[{'id': 23, 'firstname': 'abc', 'lastname': 'gef'}, {'id': 24, 'firstname': 'aabb', 'lastname': 'ppqq'}]
UPDATE: Just to be clear, I'd like to check the key-value of the 'name' and 'last' and add only if these are not already in the list.
I have:
lst = [{'name':'John', 'last':'Smith'.... .... (other key-values)... },
{'name':'Will', 'last':'Smith'... ... (other key-values)... }]
I want to append a a new dict into this list only if it is not the exact same as an existing dictionary.
In other words:
dict1 = {'name':'John', 'last':'Smith'} # ==> wouldn't be appended
but...
dict2 = {'name':'John', 'last':'Brown'} # ==> WOULD be appended
Could someone explain the simplest way to do this, as well as in English, what is happening in the solution. THANKS!
Reference: Python: Check if any list element is a key in a dictionary
Since you asked for a way to only check the two keys, even if the dicts have other keys in them:
name_pairs = set((i['name'], i['last']) for i in lst)
if (d['name'], d['last']) not in name_pairs:
lst.append(d)
You can do it with this list comprehension just append everything to your list and run this:
lst.append(dict1)
lst.append(dict2)
[dict(y) for y in set(tuple(x.items()) for x in lst)]
The output is:
[
{'last': 'Smith', 'name': 'John'},
{'last': 'Brown', 'name': 'John'},
{'last': 'Smith', 'name': 'Will'}
]
With this method you can add extra fields and it will still work.
You could also write a small method to do it and return the list
def update_if_not_exist(lst, val):
if len([d for d in lst if (d['name'], d['last']) == (val['name'], val['last'])]) == 0:
lst.append(val)
return lst
lst = update_if_not_exist(lst, dict1)
lst = update_if_not_exist(lst, dict2)
It works by filtering the original list to matching the name and last keys and seeing if the result is empty.
>>> class Person(dict):
... def __eq__(self, other):
... return (self['first'] == other['first'] and
... self['second'] == other['second'])
... def __hash__(self):
... return hash((self['first'], self['second']))
>>> l = [{'first': 'John', 'second': 'Smith', 'age': 23},
... {'first': 'John', 'second': 'Smith', 'age': 30},
... {'first': 'Ann', 'second': 'Rice', 'age': 31}]
>>> l = set(map(Person, l))
>>> print l
set([{'first': 'Ann', 'second': 'Rice', 'age': 31},
{'first': 'John', 'second': 'Smith', 'age': 23}])
Instance of the Person class can be used as simple dict.
I have two list one with the label and the other data. for example
label = ["first","second"]
list = [[1,2],[11,22]]
I need the result to be a list of dictionary
[ {
"first" : 1,
"second" : 2,
},
{
"first" : 11,
"second" : 22,
}
]
Is there a simple way to do that. Note the label and list might vary, but number of entry remain the same.
>>> label = ["first","second"]
>>> lists = [[1,2],[11,22]]
>>> [dict(zip(label, l)) for l in lists]
[{'second': 2, 'first': 1}, {'second': 22, 'first': 11}]
Try this:
>>> [dict(zip(label, e)) for e in list]
[{'second': 2, 'first': 1}, {'second': 22, 'first': 11}]