I'm trying to create combination of dictionary based on some condition
below is the main dictionary:
payload = {
"type": ["sedan","suv"],
"name": ["car1","car2"],
"color": ["black","white","green"],
"version": ["mid","top"],
"model": ["2","5","13"],
}
below are the conditions:
color = {
"car1": ["black","green"],
"car2":["white"]
}
model = {
"mid":["5"],
"top":["13","5"]
}
For payload["name"] = "car1" the colors can be only be "black" or "green" even if the payload["color"] has more than these color.
for payload["name"] = "car2", it can have only be "white" color.
Same goes for model also, for mid version it can only have model as "5" and for top version it can have only "13" and "5".
below is the expected output:
[
{'type': 'sedan', 'name': 'car1', 'color': 'black', 'version': 'mid', 'model': '5'},
{'type': 'sedan', 'name': 'car1', 'color': 'black', 'version': 'top', 'model': '5'},
{'type': 'sedan', 'name': 'car1', 'color': 'black', 'version': 'top', 'model': '13'},
{'type': 'sedan', 'name': 'car1', 'color': 'green', 'version': 'mid', 'model': '5'},
{'type': 'sedan', 'name': 'car1', 'color': 'green', 'version': 'top', 'model': '5'},
{'type': 'sedan', 'name': 'car1', 'color': 'green', 'version': 'top', 'model': '13'},
{'type': 'suv', 'name': 'car1', 'color': 'black', 'version': 'top', 'model': '5'},
{'type': 'suv', 'name': 'car1', 'color': 'black', 'version': 'top', 'model': '13'},
{'type': 'suv', 'name': 'car1', 'color': 'black', 'version': 'mid', 'model': '5'},
{'type': 'suv', 'name': 'car1', 'color': 'green', 'version': 'top', 'model': '5'},
{'type': 'suv', 'name': 'car1', 'color': 'green', 'version': 'top', 'model': '13'},
{'type': 'suv', 'name': 'car1', 'color': 'green', 'version': 'mid', 'model': '5'},
{'type': 'sedan', 'name': 'car2', 'color': 'white', 'version': 'mid', 'model': '5'},
{'type': 'sedan', 'name': 'car2', 'color': 'white', 'version': 'top', 'model': '5'},
{'type': 'sedan', 'name': 'car2', 'color': 'white', 'version': 'top', 'model': '13'},
{'type': 'suv', 'name': 'car2', 'color': 'white', 'version': 'mid', 'model': '5'},
{'type': 'suv', 'name': 'car2', 'color': 'white', 'version': 'top', 'model': '5'},
{'type': 'suv', 'name': 'car2', 'color': 'white', 'version': 'top', 'model': '13'}
]
Below is my code..it brings out all the combinations, how can i add the condition check to this. Can someone help?
import itertools
payload = {
"type": ["sedan","suv"],
"name": ["car1","car2"],
"color": ["black","white","green"],
"version": ["mid","top"],
"model": ["2","5","13"],
}
color = {
"car1": ["black","green"],
"car2":["white"]
}
model = {
"mid":["5"],
"top":["13","5"]
}
output = [dict(zip(payload.keys(), a)) for a in itertools.product(*payload.values())]
print(output)
You can try to create a dataframe with the outputs and the filter it for each condition like below
import itertools
import pandas as pd
payload = {
"type": ["sedan","suv"],
"name": ["car1","car2"],
"color": ["black","white","green"],
"version": ["mid","top"],
"model": ["2","5","13"],
}
color = {
"car1": ["black","green"],
"car2":["white"]
}
model = {
"mid":["5"],
"top":["13","5"]
}
output = [dict(zip(payload.keys(), a)) for a in itertools.product(*payload.values())]
print(output)
df = pd.DataFrame(output)
# filter for car1 color
df = df.loc[~((df.name == 'car1') & ~(df.color.isin(color['car1']))),:]
# filter for car2 color
df = df.loc[~((df.name == 'car2') & ~(df.color.isin(color['car2']))),:]
#filter for mid model
df = df.loc[~((df.version == 'mid') & ~(df.model.isin(model['mid']))),:]
#filter for topmodel
df = df.loc[~((df.version == 'top') & ~(df.model.isin(model['top']))),:]
df
Related
I have a json array on python which I want to filter based on the value of : my_json_array['models']['variants']['condition']['type']
my json array looks like the following :
my_json_array = [
{'id': 1,
'models': [
{'color': {'code': '#626262', 'name': 'Gray'},
'variants': [{'id': 1,
'condition': [{'id': 1,
'type': 'type1',
'value': 14900},
{'id': 2,
'type': 'type2',
'value': 14000}]]
]
}]
I'm looking for a method to remove condition items with type = type2. The output should look like this :
my_json_array = [{
'id': 1,
'models': [
{'color': {'code': '#626262', 'name': 'Gray'},
'variants': [{'id': 1,
'condition': [{'id': 1,
'type': 'type1',
'value': 14900}]]
]
}]
Do you mean this?
my_json_array = [
{
'id': 1,
'models': [
{
'color': {'code': '#626262', 'name': 'Gray'},
'variants': [
{
'id': 1,
'condition': [
{
'id': 1,
'type': 'type1',
'value': 14900
},
{
'id': 2,
'type': 'type2',
'value': 14000
}
]
}
]
}
]
}
]
for mydict in my_json_array:
for model in mydict['models']:
for variant in model['variants']:
for condition in variant['condition']:
if condition['type']=="type2":
variant['condition'].remove(condition)
print(my_json_array) # [{'id': 1, 'models': [{'color': {'code': '#626262', 'name': 'Gray'}, 'variants': [{'id': 1, 'condition': [{'id': 1, 'type': 'type1', 'value': 14900}]}]}]}]
I tried to parse the following code using python-solidity-parser (https://github.com/ConsenSys/python-solidity-parser)
pragma solidity ^0.4.13;
contract someContract {
mapping(address => uint) balances;
function deposit() payable {
balances[msg.sender] += msg.value;
}
function withdrawOkayish(uint amount) {
if(balances[msg.sender] >= amount) {
balances[msg.sender] -= amount; if(!msg.sender.send(amount)) { throw; }
}
}
function withdrawBad2(uint amount) {
if(balances[msg.sender] >= amount) {
balances[msg.sender] -= amount;
if(!msg.sender.call.gas(2500000).value(amount)()) { throw; }
}
}
}
It produces the following output
{'children': [{'name': 'solidity',
'type': 'PragmaDirective',
'value': '^0.4.13'},
{'baseContracts': [],
'kind': 'contract',
'name': 'someContract',
'subNodes': [{'initialValue': None,
'type': 'StateVariableDeclaration',
'variables': [{'expression': None,
'isDeclaredConst': False,
'isIndexed': False,
'isStateVar': True,
'name': 'balances',
'type': 'VariableDeclaration',
'typeName': {'keyType': {'name': 'address',
'type': 'ElementaryTypeName'},
'type': 'Mapping',
'valueType': {'name': 'uint',
'type': 'ElementaryTypeName'}},
'visibility': 'default'}]},
{'body': {'statements': [{'expression': {'left': {'base': {'name': 'balances',
'type': 'Identifier'},
'index': {'expression': {'name': 'msg',
'type': 'Identifier'},
'memberName': 'sender',
'type': 'MemberAccess'},
'type': 'IndexAccess'},
'operator': '+=',
'right': {'expression': {'name': 'msg',
'type': 'Identifier'},
'memberName': 'value',
'type': 'MemberAccess'},
'type': 'BinaryOperation'},
'type': 'ExpressionStatement'}],
'type': 'Block'},
'isConstructor': False,
'modifiers': [],
'name': 'deposit',
'parameters': {'parameters': [],
'type': 'ParameterList'},
'returnParameters': [],
'stateMutability': 'payable',
'type': 'FunctionDefinition',
'visibility': 'default'},
{'body': {'statements': [{'FalseBody': None,
'TrueBody': {'statements': [{'expression': {'left': {'base': {'name': 'balances',
'type': 'Identifier'},
'index': {'expression': {'name': 'msg',
'type': 'Identifier'},
'memberName': 'sender',
'type': 'MemberAccess'},
'type': 'IndexAccess'},
'operator': '-=',
'right': {'name': 'amount',
'type': 'Identifier'},
'type': 'BinaryOperation'},
'type': 'ExpressionStatement'},
{'FalseBody': None,
'TrueBody': {'statements': [';'],
'type': 'Block'},
'condition': {'isPrefix': True,
'operator': '!',
'subExpression': {'arguments': [{'name': 'amount',
'type': 'Identifier'}],
'expression': {'expression': {'expression': {'name': 'msg',
'type': 'Identifier'},
'memberName': 'sender',
'type': 'MemberAccess'},
'memberName': 'send',
'type': 'MemberAccess'},
'names': [],
'type': 'FunctionCall'},
'type': 'UnaryOperation'},
'type': 'IfStatement'}],
'type': 'Block'},
'condition': {'left': {'base': {'name': 'balances',
'type': 'Identifier'},
'index': {'expression': {'name': 'msg',
'type': 'Identifier'},
'memberName': 'sender',
'type': 'MemberAccess'},
'type': 'IndexAccess'},
'operator': '>=',
'right': {'name': 'amount',
'type': 'Identifier'},
'type': 'BinaryOperation'},
'type': 'IfStatement'}],
'type': 'Block'},
'isConstructor': False,
'modifiers': [],
'name': 'withdrawOkayish',
'parameters': {'parameters': [{'isIndexed': False,
'isStateVar': False,
'name': 'amount',
'storageLocation': None,
'type': 'Parameter',
'typeName': {'name': 'uint',
'type': 'ElementaryTypeName'}}],
'type': 'ParameterList'},
'returnParameters': [],
'stateMutability': None,
'type': 'FunctionDefinition',
'visibility': 'default'},
{'body': {'statements': [{'FalseBody': None,
'TrueBody': {'statements': [{'expression': {'left': {'base': {'name': 'balances',
'type': 'Identifier'},
'index': {'expression': {'name': 'msg',
'type': 'Identifier'},
'memberName': 'sender',
'type': 'MemberAccess'},
'type': 'IndexAccess'},
'operator': '-=',
'right': {'name': 'amount',
'type': 'Identifier'},
'type': 'BinaryOperation'},
'type': 'ExpressionStatement'},
{'FalseBody': None,
'TrueBody': {'statements': [';'],
'type': 'Block'},
'condition': {'isPrefix': True,
'operator': '!',
'subExpression': {'arguments': [],
'expression': {'arguments': [{'name': 'amount',
'type': 'Identifier'}],
'expression': {'expression': {'arguments': [{'number': '2500000',
'subdenomination': None,
'type': 'NumberLiteral'}],
'expression': {'expression': {'expression': {'expression': {'name': 'msg',
'type': 'Identifier'},
'memberName': 'sender',
'type': 'MemberAccess'},
'memberName': 'call',
'type': 'MemberAccess'},
'memberName': 'gas',
'type': 'MemberAccess'},
'names': [],
'type': 'FunctionCall'},
'memberName': 'value',
'type': 'MemberAccess'},
'names': [],
'type': 'FunctionCall'},
'names': [],
'type': 'FunctionCall'},
'type': 'UnaryOperation'},
'type': 'IfStatement'}],
'type': 'Block'},
'condition': {'left': {'base': {'name': 'balances',
'type': 'Identifier'},
'index': {'expression': {'name': 'msg',
'type': 'Identifier'},
'memberName': 'sender',
'type': 'MemberAccess'},
'type': 'IndexAccess'},
'operator': '>=',
'right': {'name': 'amount',
'type': 'Identifier'},
'type': 'BinaryOperation'},
'type': 'IfStatement'}],
'type': 'Block'},
'isConstructor': False,
'modifiers': [],
'name': 'withdrawBad2',
'parameters': {'parameters': [{'isIndexed': False,
'isStateVar': False,
'name': 'amount',
'storageLocation': None,
'type': 'Parameter',
'typeName': {'name': 'uint',
'type': 'ElementaryTypeName'}}],
'type': 'ParameterList'},
'returnParameters': [],
'stateMutability': None,
'type': 'FunctionDefinition',
'visibility': 'default'}],
'type': 'ContractDefinition'}],
'type': 'SourceUnit'}
I have found that it does not handle the throw keyword. Both if case block contains only ';'.
I am not able to find a way to resolve this issue. Is there any way to resolve this issue.
Created issue here: https://github.com/ConsenSys/python-solidity-parser/issues/11
(Still... not a Python programmer)
This took quite a bit of hacking around on my part just to pick up modifications. (For example, on my system, scripts/antlr4.sh (BTW, docs say script/antlr4, so... off to a great start.) doesn't execute properly)
That said, in the solidity_antlr4 directory is a parser.py source file.
It is missing a visitThrowStatement method.
I added:
def visitThrowStatement(self,ctx):
return Node(ctx=ctx,
type='ThrowStatement')
amongst the other visits* defs.
After moving my code to the site-packages (told ya... not a Python program, and definitely hacking around here, so not the right way to accomplish effecting this change I'm sure)
My output from running python3 -m solidity_parser parse ./samples/so_example.sol > testParse.txt (where ./samples/so_example.sol is your sample input) is:
{'children': [{'name': 'solidity',
'type': 'PragmaDirective',
'value': '^0.4.13'},
{'baseContracts': [],
'kind': 'contract',
'name': 'someContract',
'subNodes': [{'initialValue': None,
'type': 'StateVariableDeclaration',
'variables': [{'expression': None,
'isDeclaredConst': False,
'isIndexed': False,
'isStateVar': True,
'name': 'balances',
'type': 'VariableDeclaration',
'typeName': {'keyType': {'name': 'address',
'type': 'ElementaryTypeName'},
'type': 'Mapping',
'valueType': {'name': 'uint',
'type': 'ElementaryTypeName'}},
'visibility': 'default'}]},
{'body': {'statements': [{'expression': {'left': {'base': {'name': 'balances',
'type': 'Identifier'},
'index': {'expression': {'name': 'msg',
'type': 'Identifier'},
'memberName': 'sender',
'type': 'MemberAccess'},
'type': 'IndexAccess'},
'operator': '+=',
'right': {'expression': {'name': 'msg',
'type': 'Identifier'},
'memberName': 'value',
'type': 'MemberAccess'},
'type': 'BinaryOperation'},
'type': 'ExpressionStatement'}],
'type': 'Block'},
'isConstructor': False,
'modifiers': [],
'name': 'deposit',
'parameters': {'parameters': [],
'type': 'ParameterList'},
'returnParameters': [],
'stateMutability': 'payable',
'type': 'FunctionDefinition',
'visibility': 'default'},
{'body': {'statements': [{'FalseBody': None,
'TrueBody': {'statements': [{'expression': {'left': {'base': {'name': 'balances',
'type': 'Identifier'},
'index': {'expression': {'name': 'msg',
'type': 'Identifier'},
'memberName': 'sender',
'type': 'MemberAccess'},
'type': 'IndexAccess'},
'operator': '-=',
'right': {'name': 'amount',
'type': 'Identifier'},
'type': 'BinaryOperation'},
'type': 'ExpressionStatement'},
{'FalseBody': None,
'TrueBody': {'statements': [{'type': 'ThrowStatement'}],
'type': 'Block'},
'condition': {'isPrefix': True,
'operator': '!',
'subExpression': {'arguments': [{'name': 'amount',
'type': 'Identifier'}],
'expression': {'expression': {'expression': {'name': 'msg',
'type': 'Identifier'},
'memberName': 'sender',
'type': 'MemberAccess'},
'memberName': 'send',
'type': 'MemberAccess'},
'names': [],
'type': 'FunctionCall'},
'type': 'UnaryOperation'},
'type': 'IfStatement'}],
'type': 'Block'},
'condition': {'left': {'base': {'name': 'balances',
'type': 'Identifier'},
'index': {'expression': {'name': 'msg',
'type': 'Identifier'},
'memberName': 'sender',
'type': 'MemberAccess'},
'type': 'IndexAccess'},
'operator': '>=',
'right': {'name': 'amount',
'type': 'Identifier'},
'type': 'BinaryOperation'},
'type': 'IfStatement'}],
'type': 'Block'},
'isConstructor': False,
'modifiers': [],
'name': 'withdrawOkayish',
'parameters': {'parameters': [{'isIndexed': False,
'isStateVar': False,
'name': 'amount',
'storageLocation': None,
'type': 'Parameter',
'typeName': {'name': 'uint',
'type': 'ElementaryTypeName'}}],
'type': 'ParameterList'},
'returnParameters': [],
'stateMutability': None,
'type': 'FunctionDefinition',
'visibility': 'default'},
{'body': {'statements': [{'FalseBody': None,
'TrueBody': {'statements': [{'expression': {'left': {'base': {'name': 'balances',
'type': 'Identifier'},
'index': {'expression': {'name': 'msg',
'type': 'Identifier'},
'memberName': 'sender',
'type': 'MemberAccess'},
'type': 'IndexAccess'},
'operator': '-=',
'right': {'name': 'amount',
'type': 'Identifier'},
'type': 'BinaryOperation'},
'type': 'ExpressionStatement'},
{'FalseBody': None,
'TrueBody': {'statements': [{'type': 'ThrowStatement'}],
'type': 'Block'},
'condition': {'isPrefix': True,
'operator': '!',
'subExpression': {'arguments': [],
'expression': {'arguments': [{'name': 'amount',
'type': 'Identifier'}],
'expression': {'expression': {'arguments': [{'number': '2500000',
'subdenomination': None,
'type': 'NumberLiteral'}],
'expression': {'expression': {'expression': {'expression': {'name': 'msg',
'type': 'Identifier'},
'memberName': 'sender',
'type': 'MemberAccess'},
'memberName': 'call',
'type': 'MemberAccess'},
'memberName': 'gas',
'type': 'MemberAccess'},
'names': [],
'type': 'FunctionCall'},
'memberName': 'value',
'type': 'MemberAccess'},
'names': [],
'type': 'FunctionCall'},
'names': [],
'type': 'FunctionCall'},
'type': 'UnaryOperation'},
'type': 'IfStatement'}],
'type': 'Block'},
'condition': {'left': {'base': {'name': 'balances',
'type': 'Identifier'},
'index': {'expression': {'name': 'msg',
'type': 'Identifier'},
'memberName': 'sender',
'type': 'MemberAccess'},
'type': 'IndexAccess'},
'operator': '>=',
'right': {'name': 'amount',
'type': 'Identifier'},
'type': 'BinaryOperation'},
'type': 'IfStatement'}],
'type': 'Block'},
'isConstructor': False,
'modifiers': [],
'name': 'withdrawBad2',
'parameters': {'parameters': [{'isIndexed': False,
'isStateVar': False,
'name': 'amount',
'storageLocation': None,
'type': 'Parameter',
'typeName': {'name': 'uint',
'type': 'ElementaryTypeName'}}],
'type': 'ParameterList'},
'returnParameters': [],
'stateMutability': None,
'type': 'FunctionDefinition',
'visibility': 'default'}],
'type': 'ContractDefinition'}],
'type': 'SourceUnit'}
relevant excerpt example:
'TrueBody': {'statements': [{'type': 'ThrowStatement'}],
'type': 'Block'},
I don't even know if this is the right content, but it does demonstrate that the solution will be to rebuild with a visitThrowStatement implemented.
(It's absence, would make me suspect other visitor methods may also be missing.)
1.I need to get the value for business' name and append it to a list.
2.I need to get the value policies and append to a list after checking parent.
3.if parent is Marketing name has to added to level1.
4.if parent is Advertising name has to added to level2.
5.if some place Business is [] I need to pass None instead of Null List
Also need to check key exists or not for some keys there is a chance of missing policies, business
Sample dictionary is below
searchtest = [{'_index': 'newtest',
'_type': '_doc',
'_id': '100',
'_score': 1.0,
'_source': {'id': '100',
'name': 'A',
'Business': [{'id': '7', 'name': 'Enterprise'},
{'id': '8', 'name': 'Customer'}],
'policies': [{'id': '332',
'name': 'Second division',
'parent': 'Marketing'},
{'id': '3323', 'name': 'First division', 'parent': 'Marketing'}]}},
{'_index': 'newtest',
'_type': '_doc',
'_id': '101',
'_score': 1.0,
'_source': {'id': '101',
'name': 'B',
'Business': [{'id': '7'},
{'id': '8', 'name': 'Customer'}],
'policies': [{'id': '332',
'name': 'Second division',
'parent': 'Marketing'},
{'id': '3323', 'name': 'First division', 'parent': 'Marketing'}]}}]
Expected out
[
{
"id": "100",
"name": "A",
"Business": ["Enterprise", "Customer"],
"level1": ['Second division', 'First division'],
"level2": [ ]
},
{
"id": "101",
"name": "B",
"Business": ["Enterprise", "Customer"],
"level1": ['Second division', 'First division'],
"level2": [ ]
}
]
COde is below
def do_the_thing(lst):
resp = []
parents_mapper = {
'Marketing': 'level1',
'Advertising': 'level2'
}
for el in lst:
d = {
'id': el['_source']['id'],
'name': el['_source']['name'],
'Business': [],
'level1': [],
'level2': []
}
for business in el.get("_source", {}).get("business", {}).get("name", ""):
business_name = business.get('name')
if business_name:
d['Business'].append(business_name)
for policy in el.get('policies', []):
policy_parent = policy.get('parent')
parent_found = parents_mapper.get(policy_parent)
policy_name = policy.get('name')
if parent_found and policy_name:
d[parent_found].append(policy_name)
resp.append(d)
return resp
if __name__ == "__main__":
import pprint
pp = pprint.PrettyPrinter(4)
pp.pprint(do_the_thing(searchtest))
My output
[ {'Business': [], 'id': '100', 'level1': [], 'level2': [], 'name': 'A'},
{'Business': [], 'id': '101', 'level1': [], 'level2': [], 'name': 'B'}]
The problem in my output you can see:
'Business', 'level1' is [] is null list.
Adding one more dictionary for testing
searchtest = [{'_index': 'newtest',
'_type': '_doc',
'_id': '100',
'_score': 1.0,
'_source': {'id': '100',
'name': 'A',
'policies': [{'id': '332',
'name': 'Second division',
'parent': 'Marketing'},
{'id': '3323', 'name': 'First division', 'parent': 'Marketing'}]}},
{'_index': 'newtest',
'_type': '_doc',
'_id': '101',
'_score': 1.0,
'_source': {'id': '101',
'name': 'B',
'Business': [{'id': '9'}, {'id': '10', 'name': 'Customer'}],
'policies': [{'id': '332',
'name': 'Second division',
'parent': 'Marketing'},
{'id': '3323', 'name': 'First division', 'parent': 'Advertising'}]}}]
In the above dictionary you can see that there is no Business in 100 key and for 101 there is no name inside the Business key. So there will be key error will be coming. Need to handle that
You are not collecting data from dict, You have to select particular key to get it's value.
replace this :
for el in lst:
d = {
'id': el['_source']['id'],
'name': el['_source']['name'],
'Business': [],
'level1': [],
'level2': []
}
with this:
for el in data:
d = {
'id' : el['_source']['id'],
'name' : el['_source']['name'],
'Business' : [name['name'] for name in el['_source']['Business']],
'level1' : [name['name'] for name in el['_source']['policies']],
'level2' : []
}
output:
[ { 'Business': ['Enterprise', 'Customer'],
'id': '100',
'level1': ['Second division', 'First division'],
'level2': [],
'name': 'A'},
{ 'Business': ['Enterprise', 'Customer'],
'id': '101',
'level1': ['Second division', 'First division'],
'level2': [],
'name': 'B'}]
I have the following list of dictionaries:
mylist = [{'color': 'red', 'size': 'small', 'pattern': 'striped', 'id': '10'},
{'color': 'red', 'size': 'small', 'pattern': 'spotted', 'id': '11'},
{'color': 'red', 'size': 'large', 'pattern': 'striped', 'id': '12'},
{'color': 'red', 'size': 'small', 'pattern': 'spotted', 'id': '13'},
{'color': 'blue', 'size': 'medium', 'pattern': 'spotted', 'id': '14'}]
I want to remove dictionaries with the lowest values for the id key (leaving only the most recent) that have the same values for both the color and size keys. So in this case I want to end up with:
result = [{'color': 'red', 'size': 'large', 'pattern': 'striped', 'id': '12'},
{'color': 'red', 'size': 'small', 'pattern': 'spotted', 'id': '13'},
{'color': 'blue', 'size': 'medium', 'pattern': 'spotted', 'id': '14'}]
What is the best way to do this in python?
Using sort and groupby
sorted_list = sorted(mylist, key=lambda d: (d['color'], d['size'], int(d['id'])))
result = [list(v)[-1] for k, v in groupby(sorted_list, lambda d: (d['color'], d['size']))]
Result
[{'color': 'blue', 'id': '14', 'pattern': 'spotted', 'size': 'medium'},
{'color': 'red', 'id': '12', 'pattern': 'striped', 'size': 'large'},
{'color': 'red', 'id': '13', 'pattern': 'spotted', 'size': 'small'}]
Explanation
Sort elements so dictionaries with same color and size are consecutive and in ascending order by id
sorted_list = sorted(mylist, key=lambda d: (d['color'], d['size'], int(d['id'])))
Group sorted dictionaries by size and color
for k, v in groupby(sorted_list, lambda d: (d['color'], d['size']))
Dictionaries in each group are in ascending order by id.
Take last element of each group
result = [list(v)[-1] for k, v in groupby(...)]
You could build an intermediate dict with tuples (color, size) as keys and your dicts as values, and update it when you encounter a new (color, size) combination, or an higher id for an existing one.
In the end, the output you want is just the list of its values.
mylist = [{'color': 'red', 'size': 'small', 'pattern': 'striped', 'id': '10'},
{'color': 'red', 'size': 'large', 'pattern': 'striped', 'id': '11'},
{'color': 'red', 'size': 'small', 'pattern': 'spotted', 'id': '12'},
{'color': 'blue', 'size': 'medium', 'pattern': 'spotted', 'id': '13'}]
by_color_and_size = {}
for d in mylist:
key = (d['color'], d['size'])
if (key not in by_color_and_size
or int(d['id']) > int(by_color_and_size[key]['id'])):
by_color_and_size[key] = d
out = list(by_color_and_size.values())
print(out)
# [{'color': 'red', 'size': 'small', 'pattern': 'spotted', 'id': '12'},
# {'color': 'red', 'size': 'large', 'pattern': 'striped', 'id': '11'},
# {'color': 'blue', 'size': 'medium', 'pattern': 'spotted', 'id': '13'}]
I have collated some data on world happiness index reports from 2015 to 2019, which you can access here and download the dataset. I want to make an animation slider of happiness vs some other factor (like economy, health, etc) over the years. Below is my code:
import pandas as pd
from plotly.offline import download_plotlyjs, init_notebook_mode, iplot
from plotly.graph_objs import *
init_notebook_mode()
from chart_studio.grid_objs import Grid, Column
from plotly.tools import FigureFactory as FF
dataset = pd.read_csv('Full dataset.csv')
dataset.drop(['Family', 'Standard Error'], axis=1, inplace=True)
years_from_col = set(dataset['year'])
years_ints = sorted(list(years_from_col))
years = [str(year) for year in years_ints]
# make list of continents
continents = []
for continent in dataset['Continent']:
if continent not in continents:
continents.append(continent)
df = pd.DataFrame()
# make grid
for year in years:
for continent in continents:
dataset_by_year = dataset[dataset['year'] == int(year)]
dataset_by_year_and_cont = dataset_by_year[dataset_by_year['Continent'] == continent]
for col_name in dataset_by_year_and_cont:
# each column name is unique
temp = '{year}+{continent}+{header}_grid'.format(
year=year, continent=continent, header=col_name
)
#if dataset_by_year_and_cont[col_name].size != 0:
df = df.append({'value': list(dataset_by_year_and_cont[col_name]), 'key': temp}, ignore_index=True)
figure = {
'data': [],
'layout': {},
'frames': []
}
figure['layout']['xaxis'] = {'title': 'Economy (GDP per Capita)', 'type': 'log', 'autorange': True}
figure['layout']['yaxis'] = {'title': 'Happiness Score', 'autorange': True}
figure['layout']['hovermode'] = 'closest'
figure['layout']['showlegend'] = True
figure['layout']['sliders'] = {
'args': [
'slider.value', {
'duration': 400,
'ease': 'cubic-in-out'
}
],
'initialValue': '2015',
'plotlycommand': 'animate',
'values': years,
'visible': True
}
figure['layout']['updatemenus'] = [
{
'buttons': [
{
'args': [None, {'frame': {'duration': 500, 'redraw': False},
'fromcurrent': True, 'transition': {'duration': 300, 'easing': 'quadratic-in-out'}}],
'label': 'Play',
'method': 'animate'
},
{
'args': [[None], {'frame': {'duration': 0, 'redraw': False}, 'mode': 'immediate',
'transition': {'duration': 0}}],
'label': 'Pause',
'method': 'animate'
}
],
'direction': 'left',
'pad': {'r': 10, 't': 87},
'showactive': False,
'type': 'buttons',
'x': 0.1,
'xanchor': 'right',
'y': 0,
'yanchor': 'top'
}
]
sliders_dict = {
'active': 0,
'yanchor': 'top',
'xanchor': 'left',
'currentvalue': {
'font': {'size': 20},
'prefix': 'Year:',
'visible': True,
'xanchor': 'right'
},
'transition': {'duration': 300, 'easing': 'cubic-in-out'},
'pad': {'b': 10, 't': 50},
'len': 0.9,
'x': 0.1,
'y': 0,
'steps': []
}
custom_colors = {
'Asia': 'rgb(171, 99, 250)',
'Europe': 'rgb(230, 99, 250)',
'Africa': 'rgb(99, 110, 250)',
'North America': 'rgb(25, 211, 243)',
'South America': 'rgb(25, 163, 243)',
'Oceania': 'rgb(50, 170, 255)'
}
col_name_template = '{year}+{continent}+{header}_grid'
year = 2015
for continent in continents:
data_dict = {
'x': df.loc[df['key']==col_name_template.format(
year=year, continent=continent, header='Economy (GDP per Capita)'
), 'value'].values[0],
'y': df.loc[df['key']==col_name_template.format(
year=year, continent=continent, header='Happiness Score'
), 'value'].values[0],
'mode': 'markers',
'text': df.loc[df['key']==col_name_template.format(
year=year, continent=continent, header='Country'
), 'value'].values[0],
'marker': {
'sizemode': 'area',
'sizeref': 200000,
'size': df.loc[df['key']==col_name_template.format(
year=year, continent=continent, header='Generosity'
), 'value'].values[0],
'color': custom_colors[continent]
},
'name': continent
}
figure['data'].append(data_dict)
for year in years:
frame = {'data': [], 'name': str(year)}
for continent in continents:
data_dict = {
'x': df.loc[df['key']==col_name_template.format(
year=year, continent=continent, header='Economy (GDP per Capita)'
), 'value'].values[0],
'y': df.loc[df['key']==col_name_template.format(
year=year, continent=continent, header='Happiness Score'
), 'value'].values[0],
'mode': 'markers',
'text': df.loc[df['key']==col_name_template.format(
year=year, continent=continent, header='Country'
), 'value'].values[0],
'marker': {
'sizemode': 'area',
'sizeref': 200000,
'size': df.loc[df['key']==col_name_template.format(
year=year, continent=continent, header='Generosity'
), 'value'].values[0],
'color': custom_colors[continent]
},
'name': continent
}
frame['data'].append(data_dict)
figure['frames'].append(frame)
slider_step = {'args': [
[year],
{'frame': {'duration': 300, 'redraw': False},
'mode': 'immediate',
'transition': {'duration': 300}}
],
'label': year,
'method': 'animate'}
sliders_dict['steps'].append(slider_step)
figure['layout']['sliders'] = [sliders_dict]
iplot(figure, config={'scrollzoom': True})
It produces animation of a blank viz, like so:
What went wrong? And how do I fix it?
import pandas as pd
import plotly.graph_objs as go
from plotly.offline import init_notebook_mode, iplot
init_notebook_mode()
dataset = pd.read_csv('https://raw.githubusercontent.com/PrashantSaikia/Happiness-Index/master/Full%20dataset.csv')
years = list(dataset['year'].sort_values().unique())
continents = list(dataset['Continent'].sort_values().unique())
layout = {
'xaxis': {
'title': 'Economy (GDP per Capita)',
'type': 'log',
'autorange': True
},
'yaxis': {
'title': 'Happiness Score',
'autorange': True
},
'hovermode': 'closest',
'showlegend': True,
'updatemenus': [{
'buttons': [
{
'args': [None, {'frame': {'duration': 600, 'redraw': True}, 'fromcurrent': True, 'transition': {'duration': 0}}],
'label': 'Play',
'method': 'animate'
},
{
'args': [[None], {'frame': {'duration': 0, 'redraw': False}, 'mode': 'immediate', 'transition': {'duration': 0}}],
'label': 'Pause',
'method': 'animate'
}
],
'direction': 'left',
'pad': {'r': 10, 't': 87},
'showactive': False,
'type': 'buttons',
'x': 0.1,
'xanchor': 'right',
'y': 0,
'yanchor': 'top'
}],
'sliders': [{
'active': 0,
'yanchor': 'top',
'xanchor': 'left',
'currentvalue': {
'font': {'size': 20},
'prefix': 'Year:',
'visible': True,
'xanchor': 'right'},
'transition': {'duration': 300, 'easing': 'cubic-in-out'},
'pad': {'b': 10, 't': 50},
'len': 0.9,
'x': 0.1,
'y': 0,
'steps': []
}]
}
custom_colors = {
'Asia': 'rgb(171, 99, 250)',
'Europe': 'rgb(230, 99, 250)',
'Africa': 'rgb(99, 110, 250)',
'North America': 'rgb(25, 211, 243)',
'South America': 'rgb(25, 163, 243)',
'Oceania': 'rgb(50, 170, 255)'
}
data = []
year = years[0]
for continent in continents:
df = dataset[(dataset['Continent'] == continent) & (dataset['year'] == year)]
data.append(go.Scatter(x=df['Economy (GDP per Capita)'],
y=df['Happiness Score'],
text=df['Country'],
mode='markers',
marker={
'size': 100 * df['Generosity'],
'color': custom_colors[continent]
},
name=continent))
frames = []
for year in years[1:]:
frame = {'data': [], 'name': str(year)}
for continent in continents:
df = dataset[(dataset['Continent'] == continent) & (dataset['year'] == year)]
frame['data'].append(go.Scatter(x=df['Economy (GDP per Capita)'],
y=df['Happiness Score'],
text=df['Country'],
mode='markers',
marker={
'size': 100 * df['Generosity'],
'color': custom_colors[continent]
},
name=continent))
frames.append(go.Frame(data=frame['data'], name=frame['name']))
slider_step = {
'args': [
[str(year)],
{'frame': {'duration': 600, 'redraw': True},
'mode': 'immediate',
'transition': {'duration': 200}}
],
'label': str(year),
'method': 'animate'
}
layout['sliders'][0]['steps'].append(slider_step)
figure = go.Figure(data=data, layout=layout, frames=frames)
iplot(figure)