Skip to content

Commit 77fefc4

Browse files
committed
fixes #654
1 parent b1df2f6 commit 77fefc4

File tree

5 files changed

+112
-63
lines changed

5 files changed

+112
-63
lines changed

fastcore/_modidx.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,7 @@
9090
'fastcore.basics._clsmethod': ('basics.html#_clsmethod', 'fastcore/basics.py'),
9191
'fastcore.basics._clsmethod.__get__': ('basics.html#_clsmethod.__get__', 'fastcore/basics.py'),
9292
'fastcore.basics._clsmethod.__init__': ('basics.html#_clsmethod.__init__', 'fastcore/basics.py'),
93+
'fastcore.basics._conv_key': ('basics.html#_conv_key', 'fastcore/basics.py'),
9394
'fastcore.basics._eval_type': ('basics.html#_eval_type', 'fastcore/basics.py'),
9495
'fastcore.basics._get_op': ('basics.html#_get_op', 'fastcore/basics.py'),
9596
'fastcore.basics._ispy3_10': ('basics.html#_ispy3_10', 'fastcore/basics.py'),

fastcore/basics.py

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -618,12 +618,16 @@ def range_of(x):
618618
return list(range(len(x)))
619619

620620
# %% ../nbs/01_basics.ipynb
621+
def _conv_key(k):
622+
if isinstance(k,int): return itemgetter(k)
623+
elif isinstance(k,str): return attrgetter(k)
624+
elif isinstance(k,tuple): return lambda x: tuple(_conv_key(o)(x) for o in k)
625+
return k
626+
621627
def groupby(x, key, val=noop):
622628
"Like `itertools.groupby` but doesn't need to be sorted, and isn't lazy, plus some extensions"
623-
if isinstance(key,int): key = itemgetter(key)
624-
elif isinstance(key,str): key = attrgetter(key)
625-
if isinstance(val,int): val = itemgetter(val)
626-
elif isinstance(val,str): val = attrgetter(val)
629+
key = _conv_key(key)
630+
val = _conv_key(val)
627631
res = {}
628632
for o in x: res.setdefault(key(o), []).append(val(o))
629633
return res

fastcore/foundation.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ def __init__(self, items=None, *rest, use_list=False, match=None):
112112
def _xtra(self): return None
113113
def _new(self, items, *args, **kwargs): return type(self)(items, *args, use_list=None, **kwargs)
114114
def __getitem__(self, idx):
115-
if isinstance(idx,int): return self.items[idx]
115+
if isinstance(idx,int) and not hasattr(self.items,'iloc'): return self.items[idx]
116116
return self._get(idx) if is_indexer(idx) else L(self._get(idx), use_list=None)
117117
def copy(self): return self._new(self.items.copy())
118118

nbs/01_basics.ipynb

Lines changed: 47 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -685,7 +685,7 @@
685685
"text/markdown": [
686686
"---\n",
687687
"\n",
688-
"[source](https://github.com/AnswerDotAI/fastcore/blob/master/fastcore/basics.py#L113){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n",
688+
"[source](https://github.com/AnswerDotAI/fastcore/blob/master/fastcore/basics.py#L114){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n",
689689
"\n",
690690
"### get_class\n",
691691
"\n",
@@ -697,7 +697,7 @@
697697
"text/plain": [
698698
"---\n",
699699
"\n",
700-
"[source](https://github.com/AnswerDotAI/fastcore/blob/master/fastcore/basics.py#L113){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n",
700+
"[source](https://github.com/AnswerDotAI/fastcore/blob/master/fastcore/basics.py#L114){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n",
701701
"\n",
702702
"### get_class\n",
703703
"\n",
@@ -875,7 +875,7 @@
875875
"text/markdown": [
876876
"---\n",
877877
"\n",
878-
"[source](https://github.com/AnswerDotAI/fastcore/blob/master/fastcore/basics.py#L157){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n",
878+
"[source](https://github.com/AnswerDotAI/fastcore/blob/master/fastcore/basics.py#L158){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n",
879879
"\n",
880880
"#### ignore_exceptions\n",
881881
"\n",
@@ -886,7 +886,7 @@
886886
"text/plain": [
887887
"---\n",
888888
"\n",
889-
"[source](https://github.com/AnswerDotAI/fastcore/blob/master/fastcore/basics.py#L157){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n",
889+
"[source](https://github.com/AnswerDotAI/fastcore/blob/master/fastcore/basics.py#L158){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n",
890890
"\n",
891891
"#### ignore_exceptions\n",
892892
"\n",
@@ -2910,7 +2910,7 @@
29102910
"text/markdown": [
29112911
"---\n",
29122912
"\n",
2913-
"[source](https://github.com/AnswerDotAI/fastcore/blob/master/fastcore/basics.py#L524){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n",
2913+
"[source](https://github.com/AnswerDotAI/fastcore/blob/master/fastcore/basics.py#L525){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n",
29142914
"\n",
29152915
"#### GetAttr\n",
29162916
"\n",
@@ -2921,7 +2921,7 @@
29212921
"text/plain": [
29222922
"---\n",
29232923
"\n",
2924-
"[source](https://github.com/AnswerDotAI/fastcore/blob/master/fastcore/basics.py#L524){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n",
2924+
"[source](https://github.com/AnswerDotAI/fastcore/blob/master/fastcore/basics.py#L525){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n",
29252925
"\n",
29262926
"#### GetAttr\n",
29272927
"\n",
@@ -3601,12 +3601,16 @@
36013601
"outputs": [],
36023602
"source": [
36033603
"#|export\n",
3604+
"def _conv_key(k):\n",
3605+
" if isinstance(k,int): return itemgetter(k)\n",
3606+
" elif isinstance(k,str): return attrgetter(k)\n",
3607+
" elif isinstance(k,tuple): return lambda x: tuple(_conv_key(o)(x) for o in k)\n",
3608+
" return k\n",
3609+
"\n",
36043610
"def groupby(x, key, val=noop):\n",
36053611
" \"Like `itertools.groupby` but doesn't need to be sorted, and isn't lazy, plus some extensions\"\n",
3606-
" if isinstance(key,int): key = itemgetter(key)\n",
3607-
" elif isinstance(key,str): key = attrgetter(key)\n",
3608-
" if isinstance(val,int): val = itemgetter(val)\n",
3609-
" elif isinstance(val,str): val = attrgetter(val)\n",
3612+
" key = _conv_key(key)\n",
3613+
" val = _conv_key(val)\n",
36103614
" res = {}\n",
36113615
" for o in x: res.setdefault(key(o), []).append(val(o))\n",
36123616
" return res"
@@ -3625,7 +3629,39 @@
36253629
"cell_type": "markdown",
36263630
"metadata": {},
36273631
"source": [
3628-
"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:"
3632+
"You can use an `int` as `key` or `val` (which uses `itemgetter`; passing a `str` will use `attrgetter`), eg:"
3633+
]
3634+
},
3635+
{
3636+
"cell_type": "code",
3637+
"execution_count": null,
3638+
"metadata": {},
3639+
"outputs": [],
3640+
"source": [
3641+
"test_eq(groupby('aa ab bb'.split(), 0), {'a':['aa','ab'], 'b':['bb']})"
3642+
]
3643+
},
3644+
{
3645+
"cell_type": "markdown",
3646+
"metadata": {},
3647+
"source": [
3648+
"...and you can use a tuple as `key` or `val` (which creates a tuple from the provided keys or vals), eg:"
3649+
]
3650+
},
3651+
{
3652+
"cell_type": "code",
3653+
"execution_count": null,
3654+
"metadata": {},
3655+
"outputs": [],
3656+
"source": [
3657+
"test_eq(groupby('aaa abc bba'.split(), 0, (1,2)), {'a':[('a','a'),('b','c')], 'b':[('b','a')]})"
3658+
]
3659+
},
3660+
{
3661+
"cell_type": "markdown",
3662+
"metadata": {},
3663+
"source": [
3664+
"Here's an example of how to *invert* a grouping, and using a `val` function:"
36293665
]
36303666
},
36313667
{

0 commit comments

Comments
 (0)