Skip to content

Commit

Permalink
fixes #654
Browse files Browse the repository at this point in the history
  • Loading branch information
jph00 committed Dec 9, 2024
1 parent b1df2f6 commit 77fefc4
Show file tree
Hide file tree
Showing 5 changed files with 112 additions and 63 deletions.
1 change: 1 addition & 0 deletions fastcore/_modidx.py
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@
'fastcore.basics._clsmethod': ('basics.html#_clsmethod', 'fastcore/basics.py'),
'fastcore.basics._clsmethod.__get__': ('basics.html#_clsmethod.__get__', 'fastcore/basics.py'),
'fastcore.basics._clsmethod.__init__': ('basics.html#_clsmethod.__init__', 'fastcore/basics.py'),
'fastcore.basics._conv_key': ('basics.html#_conv_key', 'fastcore/basics.py'),
'fastcore.basics._eval_type': ('basics.html#_eval_type', 'fastcore/basics.py'),
'fastcore.basics._get_op': ('basics.html#_get_op', 'fastcore/basics.py'),
'fastcore.basics._ispy3_10': ('basics.html#_ispy3_10', 'fastcore/basics.py'),
Expand Down
12 changes: 8 additions & 4 deletions fastcore/basics.py
Original file line number Diff line number Diff line change
Expand Up @@ -618,12 +618,16 @@ def range_of(x):
return list(range(len(x)))

# %% ../nbs/01_basics.ipynb
def _conv_key(k):
if isinstance(k,int): return itemgetter(k)
elif isinstance(k,str): return attrgetter(k)
elif isinstance(k,tuple): return lambda x: tuple(_conv_key(o)(x) for o in k)
return k

def groupby(x, key, val=noop):
"Like `itertools.groupby` but doesn't need to be sorted, and isn't lazy, plus some extensions"
if isinstance(key,int): key = itemgetter(key)
elif isinstance(key,str): key = attrgetter(key)
if isinstance(val,int): val = itemgetter(val)
elif isinstance(val,str): val = attrgetter(val)
key = _conv_key(key)
val = _conv_key(val)
res = {}
for o in x: res.setdefault(key(o), []).append(val(o))
return res
Expand Down
2 changes: 1 addition & 1 deletion fastcore/foundation.py
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ def __init__(self, items=None, *rest, use_list=False, match=None):
def _xtra(self): return None
def _new(self, items, *args, **kwargs): return type(self)(items, *args, use_list=None, **kwargs)
def __getitem__(self, idx):
if isinstance(idx,int): return self.items[idx]
if isinstance(idx,int) and not hasattr(self.items,'iloc'): return self.items[idx]
return self._get(idx) if is_indexer(idx) else L(self._get(idx), use_list=None)
def copy(self): return self._new(self.items.copy())

Expand Down
58 changes: 47 additions & 11 deletions nbs/01_basics.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -685,7 +685,7 @@
"text/markdown": [
"---\n",
"\n",
"[source](https://github.com/AnswerDotAI/fastcore/blob/master/fastcore/basics.py#L113){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n",
"[source](https://github.com/AnswerDotAI/fastcore/blob/master/fastcore/basics.py#L114){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n",
"\n",
"### get_class\n",
"\n",
Expand All @@ -697,7 +697,7 @@
"text/plain": [
"---\n",
"\n",
"[source](https://github.com/AnswerDotAI/fastcore/blob/master/fastcore/basics.py#L113){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n",
"[source](https://github.com/AnswerDotAI/fastcore/blob/master/fastcore/basics.py#L114){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n",
"\n",
"### get_class\n",
"\n",
Expand Down Expand Up @@ -875,7 +875,7 @@
"text/markdown": [
"---\n",
"\n",
"[source](https://github.com/AnswerDotAI/fastcore/blob/master/fastcore/basics.py#L157){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n",
"[source](https://github.com/AnswerDotAI/fastcore/blob/master/fastcore/basics.py#L158){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n",
"\n",
"#### ignore_exceptions\n",
"\n",
Expand All @@ -886,7 +886,7 @@
"text/plain": [
"---\n",
"\n",
"[source](https://github.com/AnswerDotAI/fastcore/blob/master/fastcore/basics.py#L157){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n",
"[source](https://github.com/AnswerDotAI/fastcore/blob/master/fastcore/basics.py#L158){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n",
"\n",
"#### ignore_exceptions\n",
"\n",
Expand Down Expand Up @@ -2910,7 +2910,7 @@
"text/markdown": [
"---\n",
"\n",
"[source](https://github.com/AnswerDotAI/fastcore/blob/master/fastcore/basics.py#L524){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n",
"[source](https://github.com/AnswerDotAI/fastcore/blob/master/fastcore/basics.py#L525){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n",
"\n",
"#### GetAttr\n",
"\n",
Expand All @@ -2921,7 +2921,7 @@
"text/plain": [
"---\n",
"\n",
"[source](https://github.com/AnswerDotAI/fastcore/blob/master/fastcore/basics.py#L524){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n",
"[source](https://github.com/AnswerDotAI/fastcore/blob/master/fastcore/basics.py#L525){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n",
"\n",
"#### GetAttr\n",
"\n",
Expand Down Expand Up @@ -3601,12 +3601,16 @@
"outputs": [],
"source": [
"#|export\n",
"def _conv_key(k):\n",
" if isinstance(k,int): return itemgetter(k)\n",
" elif isinstance(k,str): return attrgetter(k)\n",
" elif isinstance(k,tuple): return lambda x: tuple(_conv_key(o)(x) for o in k)\n",
" return k\n",
"\n",
"def groupby(x, key, val=noop):\n",
" \"Like `itertools.groupby` but doesn't need to be sorted, and isn't lazy, plus some extensions\"\n",
" if isinstance(key,int): key = itemgetter(key)\n",
" elif isinstance(key,str): key = attrgetter(key)\n",
" if isinstance(val,int): val = itemgetter(val)\n",
" elif isinstance(val,str): val = attrgetter(val)\n",
" key = _conv_key(key)\n",
" val = _conv_key(val)\n",
" res = {}\n",
" for o in x: res.setdefault(key(o), []).append(val(o))\n",
" return res"
Expand All @@ -3625,7 +3629,39 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"Here's an example of how to *invert* a grouping, using an `int` as `key` (which uses `itemgetter`; passing a `str` will use `attrgetter`), and using a `val` function:"
"You can use an `int` as `key` or `val` (which uses `itemgetter`; passing a `str` will use `attrgetter`), eg:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"test_eq(groupby('aa ab bb'.split(), 0), {'a':['aa','ab'], 'b':['bb']})"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"...and you can use a tuple as `key` or `val` (which creates a tuple from the provided keys or vals), eg:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"test_eq(groupby('aaa abc bba'.split(), 0, (1,2)), {'a':[('a','a'),('b','c')], 'b':[('b','a')]})"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Here's an example of how to *invert* a grouping, and using a `val` function:"
]
},
{
Expand Down
Loading

0 comments on commit 77fefc4

Please sign in to comment.