I have a list of dicts for instance:
data = [
{ 'id': 1 },
{ 'id': 2 },
{ 'id': 3 },
{ 'id': 4 },
{ 'id': 5 },
]
remove_ids = [3,4]
So I'd like to apply remove_ids to list and end up with only:
list = [
{ 'id': 1 },
{ 'id': 2 },
{ 'id': 5 },
]
I was thinking something along the lines of:
data.remove([item (if item['id'] in remove_ids) for k, item in data])
Obviously this doesn't work, but I'm interested to know whether I was even close. I was also interested to see if this is even possibly in a single line.
data = [d for d in data if d['id'] not in remove_ids]
new_data=[x for x in data if x['id'] not in remove_ids]
You could use filter.
remove_ids = (3, 4)
filtered_data = filter(lambda item: item['id'] not in remove_ids, data)
If data is large or you do this very frequently, you might also get benefit out of itertools.
from itertools import ifilterfalse
remove_ids = (3, 4)
filtered_data = tuple(ifilterfalse(lambda item: item['id'] in remove_ids, data))
Related
ldict1 = [{"id":1, "name":"apple", "colour": "", "type": ""},
{"id":2, "name":"orange", "colour": "", "type":""}]
ldict2 = [{"id":1, "colour":"red", "type":"fruit"},
{"id":2, "colour":"orange", "type":"fruit"}]
Above is an example of the 2 types of list of dictionaries I want to merge. The id is the same for both. The length of both is long. I could only think of nested for loops but that could take time. What could be the quickest way to merge the same.
Expected
ldict = [{"id":1, "name":"apple", "colour": "red", "type": "fruit"},
{"id":2, "name":"orange", "colour": "orange", "type":"fruit"}]
Note that the two lists always have the same order of id. Also, I want to add the missing details of ldict1 from ldict2. Those keys are always empty in ldict1 which need to be filled by ldict2.
You could try with:
out = [{**i, **j} for i,j in zip(ldict1, ldict2)]
or if you have Python>=3.9:
out = [i | j for i,j in zip(ldict1, ldict2)]
Output:
[{'id': 1, 'name': 'apple', 'colour': 'red', 'type': 'fruit'},
{'id': 2, 'name': 'orange', 'colour': 'orange', 'type': 'fruit'}]
Note that this works only if the ids match each pair of i-j. Also in the event that a key has values in both i and j, only the value from j is kept.
Also, (probably wouldn't be that different from a double loop but) if the ids don't match, we could use pandas module and use it's fillna method:
import pandas as pd
out = pd.DataFrame(ldict1).replace('', float('nan')).fillna(pd.DataFrame(ldict2)).to_dict('records')
While the other answer meets the OP's need, here's one way to merge two dicts if we don't know which dict has to be updated:
# test data
ldict1 = [{"id":1, "name":"apple", "colour": "", "type": "fruit"},
{"id":2, "name":"orange", "colour": "", "type":""}]
ldict2 = [{"id":1, "colour":"red", "type":""}, # type is missing here
{"id":2, "colour":"orange", "type":"fruit"}]
[{k: i.get(k) or j.get(k) for k in {*i, *j}} for i, j in zip(ldict1, ldict2)]
Output:
[{'type': 'fruit', 'colour': 'red', 'id': 1, 'name': 'apple'},
{'type': 'fruit', 'colour': 'orange', 'id': 2, 'name': 'orange'}]
These are my inputs, pretty-printed for better readability
input1 = [{
"ID": "1",
"SequenceNum": 1
},
{
"ID": "2",
"SequenceNum": 2
},
{
"ID": "3",
"SequenceNum": 3
},
{
"ID": "4",
"SequenceNum": 4
}]
input2 = ['4', '1']
The values contained in input2 are basically the values of the 'ID' key seen in input1
The output will be a list of dictionaries where input1[index]['ID'] == input2[index_element].
Expected output -> [{"ID": "4","SequenceNum": 4},{"ID": "1","SequenceNum": 1}]
I have solved this using the following lines of code:
match_list = []
for idx,val in enumerate(input1):
match_list.append(val['ID'])
return_list = []
for idx,val in enumerate(input2):
if val in match_list:
get_idx = match_list.index(val)
return_list.append(input1[get_idx])
While it works it doesn't feel like the most optimal nor the cleanest way to write code. I apologize for the basic question, I am not a very experienced programmer.
IIUC, you could do:
s = set(input2)
res = [d for d in input1 if d["ID"] in s]
print(res)
Output
[{'ID': '1', 'SequenceNum': 1}, {'ID': '4', 'SequenceNum': 4}]
This has an expected linear complexity.
If the order with respect to input2 needs to be kept, you could do:
lookup = {d["ID"]: d for d in input1}
res = [lookup[i] for i in input2 if i in lookup]
print(res)
This also has an expected linear complexity.
I have the following list of dictionaries:
[{'id': 360004373520, 'value': something1}, {'id': 360004411159, 'value': something2}, {'id': 360004373540, 'value': something}]
I would like to get the value where id = xxxxxxxxxxxx.
Which would be the fastest way?
One possible solution is to use next() built-in method:
lst = [
{"id": 360004373520, "value": "something1"},
{"id": 360004411159, "value": "something2"},
{"id": 360004373540, "value": "something"},
]
to_search = 360004411159
value = next(d["value"] for d in lst if d["id"] == to_search)
print(value)
Prints:
something2
Or: If you search multiple times, it's worth considering transforming the list to dictionary:
to_search = 360004411159
dct = {d["id"]: d["value"] for d in lst}
print(dct[to_search])
This is one possible solution:
for key in lst:
if key['id']=='xxxxxx':
#do something
I have a Python script that adds to a list:
column = defaultdict(list)
[...]
for line in out.splitlines():
column[i + 1].append({"row": str(line)})
[...]
f = open(save_dir + 'table_data.json', "w+")
f.write(json.dumps(column))
f.close()
This will ultimately generate a JSON file, with a string like below:
{ "1":[
{
"row":"Product/Descriptian"
}
],
"2":[
{
"row":"Qty/unit"
},
{
"row":"Text"
}
],
"3":[
{
"row":""
}
]}
As you can see, array["2"] have two values. I am trying to make all arrays the same length. So array["1"] and array["3"] will ultimately also have two values.
So in order to do this, I figure I have to find the longest array first:
longest_array = (max(map(len, column.values())))
This should return 2. Now I want to append an empty {"row":""} to the other arrays, to make it the same length:
final = ([v + ["{'row'}: ''"] * (longest_array - len(v)) for v in column.values()])
Which outputs below JSON string:
[
[
{
"row":"Product/Descriptian"
},
{
"row":""
}
],
[
{
"row":"Qty/unit"
},
{
"row":"Text"
}
],
[
{
"row":""
},
{
"row":""
}
]
]
This seems to work partially. However, I spot two errors in the newly created JSON string:
It seems to add another array around the first array. The JSON string now starts with [ [ {
It removes the "parent" arrays "1", "2" and "3"
The culprit is in line:
final = ([v + ["{'row'}: ''"] * (longest_array - len(v)) for v in column.values()])
which:
It's a list comprehension (instead of dict comprehension): by iterating on column.values(), you lose all the keys, and all the lists corresponding to values have been "packed" in an outer (master) list
Not sure what you try to achieve by the double quotes (") in ["{'row'}: ''"]: that's a list with one string element
To solve your problem, turn the above line into:
final = {k: v + [{'row': ''}] * (longest_array - len(v)) for k, v in column.items()}
and final will become the expected dictionary:
>>> column
defaultdict(<class 'list'>, {'1': [{'row': 'Product/Descriptian'}], '2': [{'row': 'Qty/unit'}, {'row': 'Text'}], '3': [{'row': ''}]})
>>>
>>> longest_array_len = max((len(v) for v in column.values()))
>>> longest_array_len
2
>>> final = {k: v + [{'row': ''}] * (longest_array_len - len(v)) for k, v in column.items()}
>>>
>>> final
{'1': [{'row': 'Product/Descriptian'}, {'row': ''}], '2': [{'row': 'Qty/unit'}, {'row': 'Text'}], '3': [{'row': ''}, {'row': ''}]}
Given this nested dictionary, how could I print all the "phone" values using a for loop?
people = {
'Alice': {
'phone': '2341',
'addr': '87 Eastlake Court'
},
'Beth': {
'phone': '9102',
'addr': '563 Hartford Drive'
},
'Randy': {
'phone': '4563',
'addr': '93 SW 43rd'
}
for d in people.values():
print d['phone']
Loop over the values and then use get() method, if you want to handle the missing keys, or a simple indexing to access the nested values. Also, for the sake of optimization you can do the whole process in a list comprehension :
>>> [val.get('phone') for val in people.values()]
['4563', '9102', '2341']
Using a list comprehension
>>> [people[i]['phone'] for i in people]
['9102', '2341', '4563']
Or if you'd like to use a for loop.
l = []
for person in people:
l.append(people[person]['phone'])
>>> l
['9102', '2341', '4563']