Skip to content

Commit 5d134ec

Browse files
TomAugspurgerjreback
authored andcommitted
ENH: ExtensionArray.repeat (#24349)
1 parent ff69f45 commit 5d134ec

File tree

3 files changed

+62
-1
lines changed

3 files changed

+62
-1
lines changed

doc/source/whatsnew/v0.24.0.rst

+2-1
Original file line numberDiff line numberDiff line change
@@ -987,7 +987,8 @@ update the ``ExtensionDtype._metadata`` tuple to match the signature of your
987987

988988
**Other changes**
989989

990-
- ``ExtensionArray`` has gained the abstract methods ``.dropna()`` (:issue:`21185`)
990+
- :meth:`~pandas.api.types.ExtensionArray.dropna` has been added (:issue:`21185`)
991+
- :meth:`~pandas.api.types.ExtensionArray.repeat` has been added (:issue:`24349`)
991992
- ``ExtensionDtype`` has gained the ability to instantiate from string dtypes, e.g. ``decimal`` would instantiate a registered ``DecimalDtype``; furthermore
992993
the ``ExtensionDtype`` has gained the method ``construct_array_type`` (:issue:`21185`)
993994
- An ``ExtensionArray`` with a boolean dtype now works correctly as a boolean indexer. :meth:`pandas.api.types.is_bool_dtype` now properly considers them boolean (:issue:`22326`)

pandas/core/arrays/base.py

+29
Original file line numberDiff line numberDiff line change
@@ -580,6 +580,35 @@ def factorize(self, na_sentinel=-1):
580580
uniques = self._from_factorized(uniques, self)
581581
return labels, uniques
582582

583+
def repeat(self, repeats, axis=None):
584+
"""
585+
Repeat elements of an array.
586+
587+
.. versionadded:: 0.24.0
588+
589+
Parameters
590+
----------
591+
repeats : int
592+
This should be a non-negative integer. Repeating 0 times
593+
will return an empty array.
594+
595+
Returns
596+
-------
597+
repeated_array : ExtensionArray
598+
Same type as the input, with elements repeated `repeats` times.
599+
600+
See Also
601+
--------
602+
numpy.repeat : Similar method for :class:`numpy.ndarray`.
603+
ExtensionArray.take : Take arbitrary positions.
604+
"""
605+
if axis is not None:
606+
raise ValueError("'axis' must be None.")
607+
if repeats < 0:
608+
raise ValueError("negative repeats are not allowed.")
609+
ind = np.arange(len(self)).repeat(repeats)
610+
return self.take(ind)
611+
583612
# ------------------------------------------------------------------------
584613
# Indexing methods
585614
# ------------------------------------------------------------------------

pandas/tests/extension/base/methods.py

+31
Original file line numberDiff line numberDiff line change
@@ -264,3 +264,34 @@ def test_where_series(self, data, na_value, as_frame):
264264
if as_frame:
265265
expected = expected.to_frame(name='a')
266266
self.assert_equal(result, expected)
267+
268+
@pytest.mark.parametrize("as_series", [True, False])
269+
@pytest.mark.parametrize("repeats", [0, 1, 2])
270+
def test_repeat(self, data, repeats, as_series):
271+
a, b, c = data[:3]
272+
arr = type(data)._from_sequence([a, b, c], dtype=data.dtype)
273+
274+
if as_series:
275+
arr = pd.Series(arr)
276+
277+
result = arr.repeat(repeats)
278+
279+
if repeats == 0:
280+
expected = []
281+
elif repeats == 1:
282+
expected = [a, b, c]
283+
else:
284+
expected = [a, a, b, b, c, c]
285+
expected = type(data)._from_sequence(expected, dtype=data.dtype)
286+
if as_series:
287+
index = pd.Series(np.arange(len(arr))).repeat(repeats).index
288+
expected = pd.Series(expected, index=index)
289+
self.assert_equal(result, expected)
290+
291+
def test_repeat_raises(self, data):
292+
with pytest.raises(ValueError, match="'axis'"):
293+
data.repeat(2, axis=1)
294+
295+
with pytest.raises(ValueError,
296+
match="negative"):
297+
data.repeat(-1)

0 commit comments

Comments
 (0)