@@ -53,78 +53,93 @@ class NO_FILL_VALUE(misc_tools.NonInstantiable):
5353 '''
5454
5555
56- def partitions (sequence , partition_size = None , n_partitions = None ,
57- allow_remainder = True , fill_value = NO_FILL_VALUE ):
58- '''
59- Partition `sequence` into equal partitions of size `partition_size`, or
60- determine size automatically given the number of partitions as
61- `n_partitions`.
62-
63- If the sequence can't be divided into precisely equal partitions, the last
64- partition will contain less members than all the other partitions.
65-
66- Example:
67-
68- >>> partitions([0, 1, 2, 3, 4], 2)
69- [[0, 1], [2, 3], [4]]
70-
71- (You need to give *either* a `partition_size` *or* an `n_partitions`
72- argument, not both.)
73-
74- Specify `allow_remainder=False` to enforce that the all the partition sizes
75- be equal; if there's a remainder while `allow_remainder=False`, an
76- exception will be raised.
77-
78- If you want the remainder partition to be of equal size with the other
79- partitions, you can specify `fill_value` as the padding for the last
80- partition. A specified value for `fill_value` implies
81- `allow_remainder=True` and will cause an exception to be raised if
82- specified with `allow_remainder=False`.
83-
84- Example:
85-
86- >>> partitions([0, 1, 2, 3, 4], 3, fill_value=None)
87- [[0, 1, 2], [3, 4, None]]
88-
89- '''
90-
91- sequence_length = len (sequence )
92-
93- ### Validating input: #####################################################
94- # #
95- if (partition_size is None ) == (n_partitions is None ):
96- raise Exception ('You must specify *either* `partition_size` *or* '
97- '`n_paritions`.' )
98-
99- if fill_value is not NO_FILL_VALUE and not allow_remainder :
100- raise ValueError ('`fill_value` cannot be specified if '
101- '`allow_remainder` is `False`.' )
102-
103- remainder_length = sequence_length % (partition_size if partition_size
104- is not None else n_partitions )
105-
106- if not allow_remainder and remainder_length > 0 :
107- raise Exception ("You set `allow_remainder=False`, but there's a "
108- "reminder of %s left." % remainder_length )
109- # #
110- ### Finished validating input. ############################################
111-
112- if partition_size is None :
113- partition_size = math_tools .ceil_div (sequence_length , n_partitions )
114- if n_partitions is None :
115- n_partitions = math_tools .ceil_div (sequence_length , partition_size )
116-
117- enlarged_length = partition_size * n_partitions
118-
119- blocks = [sequence [i : i + partition_size ] for i in
120- range (0 , enlarged_length , partition_size )]
121-
122- if fill_value is not NO_FILL_VALUE and blocks :
123- filler = itertools .repeat (fill_value ,
124- enlarged_length - sequence_length )
125- blocks [- 1 ].extend (filler )
126-
127- return blocks
56+ def partitions (sequence , partition_size = None , n_partitions = None ,
57+ allow_remainder = True , larger_on_remainder = False ,
58+ fill_value = NO_FILL_VALUE ):
59+ '''
60+ Partition `sequence` into equal partitions of size `partition_size`, or
61+ determine size automatically given the number of partitions as
62+ `n_partitions`.
63+
64+ If the sequence can't be divided into precisely equal partitions, the last
65+ partition will contain less members than all the other partitions.
66+
67+ Example:
68+
69+ >>> partitions([0, 1, 2, 3, 4], 2)
70+ [[0, 1], [2, 3], [4]]
71+
72+ (You need to give *either* a `partition_size` *or* an `n_partitions`
73+ argument, not both.)
74+
75+ Specify `allow_remainder=False` to enforce that the all the partition sizes
76+ be equal; if there's a remainder while `allow_remainder=False`, an
77+ exception will be raised.
78+
79+ By default, if there's a remainder, the last partition will be smaller than
80+ the others. (e.g. a sequence of 7 items, when partitioned into pairs, will
81+ have 3 pairs and then a partition with only 1 element.) Specify
82+ `larger_on_remainder=True` to make the last partition, in case there is
83+ one, be a bigger partition. (e.g. a sequence of a 7 items divided into
84+ pairs would result in 2 pairs and one triplet.)
85+
86+ If you want the remainder partition to be of equal size with the other
87+ partitions, you can specify `fill_value` as the padding for the last
88+ partition. A specified value for `fill_value` implies
89+ `allow_remainder=True` and will cause an exception to be raised if
90+ specified with `allow_remainder=False`.
91+
92+ Example:
93+
94+ >>> partitions([0, 1, 2, 3, 4], 3, fill_value='meow')
95+ [[0, 1, 2], [3, 4, 'meow']]
96+
97+ '''
98+
99+ sequence_length = len (sequence )
100+
101+ ### Validating input: #####################################################
102+ # #
103+ if (partition_size is None ) + (n_partitions is None ) != 1 :
104+ raise Exception ('You must specify *either* `partition_size` *or* '
105+ '`n_paritions`.' )
106+
107+ remainder_length = sequence_length % (partition_size if partition_size
108+ is not None else n_partitions )
109+
110+ if not allow_remainder and remainder_length > 0 :
111+ raise Exception ("You set `allow_remainder=False`, but there's a "
112+ "reminder of %s left." % remainder_length )
113+ # #
114+ ### Finished validating input. ############################################
115+
116+ if partition_size is None :
117+ if larger_on_remainder :
118+ partition_size = sequence_length // n_partitions # (Floor div)
119+ else :
120+ partition_size = math_tools .ceil_div (sequence_length , n_partitions )
121+ if n_partitions is None :
122+ n_partitions = math_tools .ceil_div (sequence_length , partition_size )
123+
124+ enlarged_length = partition_size * n_partitions
125+
126+ blocks = [sequence [i : i + partition_size ] for i in
127+ range (0 , enlarged_length , partition_size )]
128+
129+ if enlarged_length > sequence_length : # We have a remainder
130+ assert blocks
131+ if larger_on_remainder :
132+ if len (blocks ) >= 2 :
133+ small_block_to_append_back = blocks [- 1 ]
134+ del blocks [- 1 ]
135+ blocks [- 1 ] += small_block_to_append_back
136+ elif fill_value != NO_FILL_VALUE : # (We use elif because fill is never
137+ # done if `larger_on_remainder=True`.)
138+ filler = itertools .repeat (fill_value ,
139+ enlarged_length - sequence_length )
140+ blocks [- 1 ].extend (filler )
141+
142+ return blocks
128143
129144
130145def is_immutable_sequence (thing ):
0 commit comments