Multi-level defaultdict with variable depth?
You can do it without even defining a class:
from collections import defaultdict
nested_dict = lambda: defaultdict(nested_dict)
nest = nested_dict()
nest[0][1][2][3][4][5] = 6
Nested defaultdict of defaultdict
For an arbitrary number of levels:
def rec_dd():
return defaultdict(rec_dd)
>>> x = rec_dd()
>>> x['a']['b']['c']['d']
defaultdict(<function rec_dd at 0x7f0dcef81500>, {})
>>> print json.dumps(x)
{"a": {"b": {"c": {"d": {}}}}}
Of course you could also do this with a lambda, but I find lambdas to be less readable. In any case it would look like this:
rec_dd = lambda: defaultdict(rec_dd)
Multiple levels of 'collection.defaultdict' in Python
Use:
from collections import defaultdict
d = defaultdict(lambda: defaultdict(int))
This will create a new defaultdict(int)
whenever a new key is accessed in d
.
Nested defaultdicts
The issue here is that defaultdict
accepts a callable, which is used as a factory to generate the value when a key is missing. Once you understand that, the behaviour is clear:
x = defaultdict(dict)
x # it's a default dict
x['a'] # it's just a dict()
x['a']['b'] = 'c' # it's just setting the 'b' item in the dict x['a']
x['a']['b']['z'] # oops, error, because x['a']['b'] is not a dict!
If you only require a finite level of nesting, using a plain old dict
with tuple
keys is usually a much easier data structure to work with. That will work fine for both the 2-d and 3-d examples shown in your question.
If you require arbitrary levels of nesting, however, you can consider the recursive defaultdict
example shown here.
How can I set the position of my datagrid scrollbar in my winforms app?
You don't actually interact directly with the scrollbar, rather you set the FirstDisplayedScrollingRowIndex
. So before it reloads, capture that index, once it's reloaded, reset it to that index.
EDIT: Good point in the comment. If you're using a DataGridView
then this will work. If you're using the old DataGrid
then the easiest way to do that is to inherit from it. See here: Linkage
The DataGrid has a protected GridVScrolled method that can be used to scroll the grid to a specific row. To use it, derive a new grid from the DataGrid and add a ScrollToRow method.
C# code
public void ScrollToRow(int theRow)
{
//
// Expose the protected GridVScrolled method allowing you
// to programmatically scroll the grid to a particular row.
//
if (DataSource != null)
{
GridVScrolled(this, new ScrollEventArgs(ScrollEventType.LargeIncrement, theRow));
}
}
Modify multi-level dictionaries
I was playing around with the idea of using multiple indexes, and a defaultdict
. And this came out:
from collections import defaultdict
class LayeredDict(defaultdict):
def __getitem__(self, key):
if isinstance(key, (tuple, list)):
if len(key) == 1:
return self[key[0]]
return self[key[0]][key[1:]]
return super(LayeredDict, self).__getitem__(key)
def __setitem__(self, key, value):
if isinstance(key, (tuple, list)):
if len(key) == 1:
self[key[0]] = value
else:
self[key[0]][key[1:]] = value
else:
super(LayeredDict, self).__setitem__(key, value)
def __init__(self, *args, **kwargs):
super(LayeredDict, self).__init__(*args, **kwargs)
self.default_factory = type(self) # override default
I haven't fully tested it, but it should allow you to create any level of nested dictionaries, and index them with a tuple.
>>> x = LayeredDict()
>>> x['abc'] = 'blah'
>>> x['abc']
'blah'
>>> x[0, 8, 2] = 1.2345
>>> x[0, 8, 1] = 8.9
>>> x[0, 8, 'xyz'] = 10.1
>>> x[0, 8].keys()
[1, 2, 'xyz']
>>> x['abc', 1] = 5
*** TypeError: 'str' object does not support item assignment
Unfortunately expansion notation (or whatever it's called) isn't supported, but
you can just pass a list or tuple in as an index.
>>> keylist = (0, 8, 2)
>>> x[*keylist]
*** SyntaxError: invalid syntax (<stdin>, line 1)
>>> x[keylist]
1.2345
Also, the isinstance(key, (tuple, list))
condition means a tuple can't be used as a key.
How to update values in nested dictionary if keys are in a list?
Predefined dictionary structure: functools.reduce
You can define a function using functools.reduce
to apply getitem
repeatedly and then set a supplied value:
from functools import reduce
from operator import getitem
def set_nested_item(dataDict, mapList, val):
"""Set item in nested dictionary"""
reduce(getitem, mapList[:-1], dataDict)[mapList[-1]] = val
return dataDict
key_lst = ["key1", "key2", "key3"]
value = "my_value"
d = {"key1": {"key2": {"key3": "some_value"}}}
d = set_nested_item(d, key_lst, value)
print(d)
# {'key1': {'key2': {'key3': 'my_value'}}}
Note operator.getitem
is used to access dict.__getitem__
, or its more commonly used syntactic sugar dict[]
. In this instance, functools.reduce
calls getitem
recursively on dataDict
, successively using each value in mapList[:-1]
as an argument. With [:-1]
, we intentionally leave out the last value, so we can use __setitem__
via dict[key] = value
for the final key.
Arbitrary dictionary nesting: collections.defaultdict
If you wish to add items at arbitrary branches not yet been defined, you can construct a defaultdict
. For this, you can first defaultify
your regular dictionary input, then use set_nested_item
as before:
from collections import defaultdict
def dd_rec():
return defaultdict(dd_rec)
def defaultify(d):
if not isinstance(d, dict):
return d
return defaultdict(dd_rec, {k: defaultify(v) for k, v in d.items()})
dd = defaultify(d)
key_lst = ["key1", "key2", "key5", "key6"]
value = "my_value2"
dd = set_nested_item(dd, key_lst, value)
print(dd)
# defaultdict(<function __main__.<lambda>>,
# {'key1': defaultdict(<function __main__.<lambda>>,
# {'key2': defaultdict(<function __main__.<lambda>>,
# {'key3': 'my_value',
# 'key5': defaultdict(<function __main__.<lambda>>,
# {'key6': 'my_value2'})})})})
Related Topics
Dynamically Add Field to a Form
Using Backslash in Python (Not to Escape)
How to Append One String to Another in Python
How to Manually Install a Pypi Module Without Pip/Easy_Install
Seaborn Is Not Plotting Within Defined Subplots
How to Remove Nan Values from a Numpy Array
Working with Big Data in Python and Numpy, Not Enough Ram, How to Save Partial Results on Disc
Filtering a List of Strings Based on Contents
How to Reduce a Jpeg Size to a 'Desired Size'
How to Udp Multicast in Python
Convert Utf-8 with Bom to Utf-8 with No Bom in Python
Python Class Instance Variables and Class Variables
Get the Key Corresponding to the Minimum Value Within a Dictionary
How to Find the Number of Arguments of a Python Function
Python' Is Not Recognized as an Internal or External Command