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}]
Related
I have a list of object, each object contains a unique ID. The current list is like so:
[{"id": 3}, {"id": 5}, {"id": 8}]
I want to change the indexes a bit - instead of the dictionary with id = 3 to be on index 0, I want the dictionary with id = 3 to be on index 3.
I have tried:
list = []
for item in items:
list[item["id"]] = item
but that gives me indexing error. Then I tried to do the following:
list = []
for item in items:
list.insert(item["id"], item)
which just acts like a regular append (does not insert at specified index).
I have a last ditch attempt to do this on the front end when I am getting the response from the API but that defeats the whole purpose of reducing the amount of looping I do on the client side. The reason being is that the server can knock out these loops in like 50 milliseconds and on the client side it takes up to 300 milliseconds since it runs in the browser.
There is no problem in your code it all happens because your list has zero element
items = [{"id": 3}, {"id": 5}, {"id": 8}]
list_ = []
for item in items:
while item['id'] > len(list_):
list.append(None)
list_.insert(item["id"], item)
print(list_)
OUTPUT:
You can see here your elements are inserted inside the list.
[None, None, None, {'id': 3}, None, {'id': 5}, None, None, {'id': 8}, None]
The above code works perfectly if the dictionary inside the list is in increasing order, But if the dictionary is in random order then first you need to first change the list to increasing order.
items = [{"id": 3}, {"id": 5}, {"id": 8},{'id':2}]
items = (sorted(items,key=lambda e:e['id'])) # sort the list
list_ = []
for item in items:
while item['id'] > len(list_):
list.append(None)
list_.append(item)
print(list)
INPUT/OUTPUT
IN:items = [{"id": 3}, {"id": 5}, {"id": 8},{'id':2}]
OUTPUT FROM FIRST ANSWER:[None, None, {'id': 2}, None, {'id': 3}, None, {'id': 5}, None, None, {'id': 8}]
OUTPUT FROM SECOND ANSWER:[None, None, {'id': 2}, {'id': 3}, None, {'id': 5}, None, None, {'id': 8}]
I think the general solution for this will be
a= [{"id": 3}, {"id": 5}, {"id": 8}]
l = [None for _ in range(max(a,key=lambda x: x["id"])["id"]+1)]
for item in a:
l[item["id"]]= item
print(l)
Also insert and item assignment is creating error because it expects that index to be exist beforehand so in that case you need to initialize your list with empty labels
Create an empty list with needed indexes first like
data = [{"id": 3}, {"id": 5}, {"id": 8}]
mod_list = [None]*max(x.get("id") for x in data)
Now fill the indexes with needed data
[mod_list.insert(x.get("id"),x) for x in data]
You get a list like this
[None, None, None, {'id': 3}, None, {'id': 5}, None, None, {'id': 8}, None, None]
The None indexes can be ignored in processing.
You can't insert into an empty list at index 3. The first element you add to a list will always be at index 0. More general, you can't insert at an index that's higher than the list is long. If you want a quick way to look up items with a specific index, use another dict instead of a list as the container:
>>> lst = [{"id": 3}, {"id": 5}, {"id": 8}]
>>> d = {x["id"]: x for x in lst}
>>> d
{3: {'id': 3}, 5: {'id': 5}, 8: {'id': 8}}
>>> d[3]
{'id': 3}
This way, each element can be looked up in O(1) using its ID as the index. And this will also work if the IDs are very large numbers (when its impractical to create a mostly empty list with that many indices) or even non-numeric, e.g. strings.
You can do below steps;
x = [{"id": 3}, {"id": 5}, {"id": 8}]
x.insert(3, x[0])
del x[0]
I have a python list of dictionaries like this
test_list = [{'id': 0, 'A':True, 'B':123},
{'id':76, 'A':True, 'B':73},
{'id':5, 'A':False, 'B':223},
{'id':5, 'A':False, 'B':223},
{'id':85, 'A':True, 'B':4},
{'id':81, 'A':False, 'B':76},
{'id':76, 'A':True, 'B':73}]
And I want to make this list unique
using simple set(test_list) give you TypeError: unhashable type: 'dict'
My below answer works fine for me, but I am looking for a better and short answer
unique_ids = list(set([x['id'] for x in test_list]))
d = {}
for item in test_list:
d[item['id']] = item
new_d = []
for x in unique_ids:
new_d.append(d[x])
Create a new dictionary with keys as ids and the values as the entire dictionary and access only the values:
new_d = list({v["id"]: v for v in test_list}.values())
>>> new_d
[{'id': 0, 'A': True, 'B': 123},
{'id': 76, 'A': True, 'B': 73},
{'id': 5, 'A': False, 'B': 223},
{'id': 85, 'A': True, 'B': 4},
{'id': 81, 'A': False, 'B': 76}]
~~
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.
My question is similar to that of another question in SO How to remove a json string from list.
The solution to that question did solve a part of my problem but mine is little different.
My lists are:
list1 = [{"ID": 1, "data": "12"},{"ID": 2, "data": "13"}]
list2 = [{"ID": 1, "col": "5"},{"ID": 1, "col": "8"},{"ID": 2,"col": "2"}]
I did the following to modify the final list:
per_id = {}
for info in chain(list1, list2):
per_id.setdefault(info['ID'], {}).update(info)
output = list(per_id.values())
The expected output was:
output = [{"ID": 1,"data": "12", "col": "5"},{"ID": 1,"data": "12", "col": "8"},{"ID": 2,"data": "13","col": "2"}]
But the output i got is:
output = [{"ID": 1,"data": "12", "col": "5"},{"ID": 2,"data": "13","col": "2"}]
Is there a way to rectify this problem.
You get the second version because there is more than one "ID" with the the value of 1. If you use a defaultdict with a list, you can set it to append.
This example is taken directly from the page:
>>> s = [('yellow', 1), ('blue', 2), ('yellow', 3), ('blue', 4), ('red', 1)]
>>> d = defaultdict(list)
>>> for k, v in s:
... d[k].append(v)
...
>>> d.items()
[('blue', [2, 4]), ('red', [1]), ('yellow', [1, 3])]
Try itertools-combinations-
from itertools import chain
from itertools import combinations
list1 = [{"ID": 1, "data": "12"},{"ID": 2, "data": "13"}]
list2 = [{"ID": 1, "col": "5"},{"ID": 1, "col": "8"},{"ID": 2,"col": "2"}]
data = []
for i,j in combinations(chain(list1,list2),2):
if i['ID'] == j['ID']:
d = dict(i.items()+j.items())
if len(d.keys())==3:#Ensure that it has three keys i.e. avoid combination between lsit1 elements or combination between list2 elements themselves.
data.append(d)
print data
Output-
[{'data': '12', 'ID': 1, 'col': '5'}, {'data': '12', 'ID': 1, 'col': '8'}, {'data': '13', 'ID': 2, 'col': '2'}]
The previous answer from Serge Ballesta works if you include a simple check to avoid repeating values (i would comment it, but i don't have enough reputation).
result = [] # start with an empty list
for elt1 in list1:
for elt2 in list2:
if elt1['ID'] == elt2['ID']:
for k in elt2.keys():
if k != "ID":
eltr = elt1.copy() # take a copy to avoid changing original lists
eltr.update(elt2)
result.append(eltr)
result
Output:
[{'data': '12', 'ID': 1, 'col': '5'}, {'data': '12', 'ID': 1, 'col': '8'}, {'data': '13', 'ID': 2, 'col': '2'}]
If you have one list that contains some attributes for an ID and another one that contains other attributes, chaining is probably not the best idea.
Here you could simply iterate separately both lists and update the map of one list with the map of the second one. Code example in python console:
>>> result = [] # start with an empty list
>>> for elt1 in list1:
for elt2 in list2:
if elt1['ID'] == elt2['ID']:
eltr = elt1.copy() # take a copy to avoid changing original lists
eltr.update(elt2)
result.append(eltr)
>>> result
[{'data': '12', 'ID': 1, 'col': '5'}, {'data': '12', 'ID': 1, 'col': '8'}, {'data': '13', 'ID': 2, 'col': '2'}]
as expected...
I've got a list of Tokens which looks something like:
[{
Value: "Blah",
StartOffset: 0,
EndOffset: 4
}, ... ]
What I want to do is get a count of how many times each value occurs in the list of tokens.
In VB.Net I'd do something like...
Tokens = Tokens.
GroupBy(Function(x) x.Value).
Select(Function(g) New With {
.Value = g.Key,
.Count = g.Count})
What's the equivalent in Python?
IIUC, you can use collections.Counter:
>>> from collections import Counter
>>> tokens = [{"Value": "Blah", "SO": 0}, {"Value": "zoom", "SO": 5}, {"Value": "Blah", "SO": 2}, {"Value": "Blah", "SO": 3}]
>>> Counter(tok['Value'] for tok in tokens)
Counter({'Blah': 3, 'zoom': 1})
if you only need a count. If you want them grouped by the value, you could use itertools.groupby and something like:
>>> from itertools import groupby
>>> def keyfn(x):
return x['Value']
...
>>> [(k, list(g)) for k,g in groupby(sorted(tokens, key=keyfn), keyfn)]
[('Blah', [{'SO': 0, 'Value': 'Blah'}, {'SO': 2, 'Value': 'Blah'}, {'SO': 3, 'Value': 'Blah'}]), ('zoom', [{'SO': 5, 'Value': 'zoom'}])]
although it's a little trickier because groupby requires the grouped terms to be contiguous, and so you have to sort by the key first.
Let's assume that is your python list, containing dictionnaries:
my_list = [{'Value': 'Blah',
'StartOffset': 0,
'EndOffset': 4},
{'Value': 'oqwij',
'StartOffset': 13,
'EndOffset': 98},
{'Value': 'Blah',
'StartOffset': 6,
'EndOffset': 18}]
A one liner:
len([i for i in a if i['Value'] == 'Blah']) # returns 2
import collections
# example token list
tokens = [{'Value':'Blah', 'Start':0}, {'Value':'BlahBlah'}]
count=collections.Counter([d['Value'] for d in tokens])
print count
shows
Counter({'BlahBlah': 1, 'Blah': 1})
token = [{
'Value': "Blah",
'StartOffset': 0,
'EndOffset': 4
}, ... ]
value_counter = {}
for t in token:
v = t['Value']
if v not in value_counter:
value_counter[v] = 0
value_counter[v] += 1
print value_counter
Another efficient way is to convert data to Pandas DataFrame and then aggregate them. Like this:
import pandas as pd
df = pd.DataFrame(data)
df.groupby('key')['value'].count()
df.groupby('key')['value'].sum()