1
- from typing import TYPE_CHECKING , List , Tuple
1
+ from collections import namedtuple
2
+ from typing import TYPE_CHECKING , Iterator , List , Tuple
2
3
3
4
import numpy as np
4
5
9
10
from pandas .core .internals .managers import BlockManager # noqa:F401
10
11
11
12
12
- def operate_blockwise (
13
- left : "BlockManager" , right : "BlockManager" , array_op
14
- ) -> "BlockManager" :
13
+ BlockPairInfo = namedtuple (
14
+ "BlockPairInfo" , ["lvals" , "rvals" , "locs" , "left_ea" , "right_ea" , "rblk" ],
15
+ )
16
+
17
+
18
+ def _iter_block_pairs (
19
+ left : "BlockManager" , right : "BlockManager"
20
+ ) -> Iterator [BlockPairInfo ]:
15
21
# At this point we have already checked the parent DataFrames for
16
22
# assert rframe._indexed_same(lframe)
17
23
18
- res_blks : List ["Block" ] = []
19
24
for n , blk in enumerate (left .blocks ):
20
25
locs = blk .mgr_locs
21
26
blk_vals = blk .values
@@ -34,21 +39,32 @@ def operate_blockwise(
34
39
right_ea = not isinstance (rblk .values , np .ndarray )
35
40
36
41
lvals , rvals = _get_same_shape_values (blk , rblk , left_ea , right_ea )
42
+ info = BlockPairInfo (lvals , rvals , locs , left_ea , right_ea , rblk )
43
+ yield info
37
44
38
- res_values = array_op (lvals , rvals )
39
- if left_ea and not right_ea and hasattr (res_values , "reshape" ):
40
- res_values = res_values .reshape (1 , - 1 )
41
- nbs = rblk ._split_op_result (res_values )
42
45
43
- # Assertions are disabled for performance, but should hold:
44
- # if right_ea or left_ea:
45
- # assert len(nbs) == 1
46
- # else:
47
- # assert res_values.shape == lvals.shape, (res_values.shape, lvals.shape)
46
+ def operate_blockwise (
47
+ left : "BlockManager" , right : "BlockManager" , array_op
48
+ ) -> "BlockManager" :
49
+ # At this point we have already checked the parent DataFrames for
50
+ # assert rframe._indexed_same(lframe)
51
+
52
+ res_blks : List ["Block" ] = []
53
+ for lvals , rvals , locs , left_ea , right_ea , rblk in _iter_block_pairs (left , right ):
54
+ res_values = array_op (lvals , rvals )
55
+ if left_ea and not right_ea and hasattr (res_values , "reshape" ):
56
+ res_values = res_values .reshape (1 , - 1 )
57
+ nbs = rblk ._split_op_result (res_values )
58
+
59
+ # Assertions are disabled for performance, but should hold:
60
+ # if right_ea or left_ea:
61
+ # assert len(nbs) == 1
62
+ # else:
63
+ # assert res_values.shape == lvals.shape, (res_values.shape, lvals.shape)
48
64
49
- _reset_block_mgr_locs (nbs , locs )
65
+ _reset_block_mgr_locs (nbs , locs )
50
66
51
- res_blks .extend (nbs )
67
+ res_blks .extend (nbs )
52
68
53
69
# Assertions are disabled for performance, but should hold:
54
70
# slocs = {y for nb in res_blks for y in nb.mgr_locs.as_array}
@@ -85,7 +101,7 @@ def _get_same_shape_values(
85
101
# Require that the indexing into lvals be slice-like
86
102
assert rblk .mgr_locs .is_slice_like , rblk .mgr_locs
87
103
88
- # TODO(EA2D): with 2D EAs pnly this first clause would be needed
104
+ # TODO(EA2D): with 2D EAs only this first clause would be needed
89
105
if not (left_ea or right_ea ):
90
106
lvals = lvals [rblk .mgr_locs .indexer , :]
91
107
assert lvals .shape == rvals .shape , (lvals .shape , rvals .shape )
@@ -102,3 +118,14 @@ def _get_same_shape_values(
102
118
rvals = rvals [0 , :]
103
119
104
120
return lvals , rvals
121
+
122
+
123
+ def blockwise_all (left : "BlockManager" , right : "BlockManager" , op ) -> bool :
124
+ """
125
+ Blockwise `all` reduction.
126
+ """
127
+ for info in _iter_block_pairs (left , right ):
128
+ res = op (info .lvals , info .rvals )
129
+ if not res :
130
+ return False
131
+ return True
0 commit comments