summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRoss Barnowski <rossbar@berkeley.edu>2021-01-27 11:23:12 -0800
committerGitHub <noreply@github.com>2021-01-27 14:23:12 -0500
commitb26480b1c236a581296c86c7c077600631d3babe (patch)
tree893bfbb9b1159538f4c4e89b6b94c639ebe3297c
parentde9c66ff7790ae786c15c8b7bb5a05879fb454c7 (diff)
downloadnetworkx-b26480b1c236a581296c86c7c077600631d3babe.tar.gz
Update documentation and testing of arbitrary_element (#4451)
* Update documentation for arbitrary_element. * Add numpydoc sections to docstring and extensive examples. * Add to reference documentation. * Add tests for arbitrary_element. * Update networkx/utils/misc.py Co-authored-by: Stefan van der Walt <sjvdwalt@gmail.com> Co-authored-by: Stefan van der Walt <sjvdwalt@gmail.com>
-rw-r--r--doc/reference/utils.rst1
-rw-r--r--networkx/utils/misc.py69
-rw-r--r--networkx/utils/tests/test_misc.py28
3 files changed, 84 insertions, 14 deletions
diff --git a/doc/reference/utils.rst b/doc/reference/utils.rst
index 12e39395..636134ee 100644
--- a/doc/reference/utils.rst
+++ b/doc/reference/utils.rst
@@ -11,6 +11,7 @@ Helper Functions
.. autosummary::
:toctree: generated/
+ arbitrary_element
is_string_like
flatten
iterable
diff --git a/networkx/utils/misc.py b/networkx/utils/misc.py
index e4beca5b..6d07bbd7 100644
--- a/networkx/utils/misc.py
+++ b/networkx/utils/misc.py
@@ -232,22 +232,63 @@ def arbitrary_element(iterable):
"""Returns an arbitrary element of `iterable` without removing it.
This is most useful for "peeking" at an arbitrary element of a set,
- but can be used for any list, dictionary, etc., as well::
+ but can be used for any list, dictionary, etc., as well.
- >>> arbitrary_element({3, 2, 1})
+ Parameters
+ ----------
+ iterable : `abc.collections.Iterable` instance
+ Any object that implements ``__iter__``, e.g. set, dict, list, tuple,
+ etc.
+
+ Returns
+ -------
+ The object that results from ``next(iter(iterable))``
+
+ Raises
+ ------
+ ValueError
+ If `iterable` is an iterator (because the current implementation of
+ this function would consume an element from the iterator).
+
+ Examples
+ --------
+ Arbitrary elements from common Iterable objects:
+
+ >>> arbitrary_element([1, 2, 3]) # list
+ 1
+ >>> arbitrary_element((1, 2, 3)) # tuple
+ 1
+ >>> arbitrary_element({1, 2, 3}) # set
+ 1
+ >>> d = {k: v for k, v in zip([1, 2, 3], [3, 2, 1])}
+ >>> arbitrary_element(d) # dict_keys
+ 1
+ >>> arbitrary_element(d.values()) # dict values
+ 3
+
+ `str` is also an Iterable:
+
+ >>> arbitrary_element("hello")
+ 'h'
+
+ :exc:`ValueError` is raised if `iterable` is an iterator:
+
+ >>> iterator = iter([1, 2, 3]) # Iterator, *not* Iterable
+ >>> arbitrary_element(iterator)
+ Traceback (most recent call last):
+ ...
+ ValueError: cannot return an arbitrary item from an iterator
+
+ Notes
+ -----
+ This function does not return a *random* element. If `iterable` is
+ ordered, sequential calls will return the same value::
+
+ >>> l = [1, 2, 3]
+ >>> arbitrary_element(l)
+ 1
+ >>> arbitrary_element(l)
1
- >>> arbitrary_element("hello")
- 'h'
-
- This function raises a :exc:`ValueError` if `iterable` is an
- iterator (because the current implementation of this function would
- consume an element from the iterator)::
-
- >>> iterator = iter([1, 2, 3])
- >>> arbitrary_element(iterator)
- Traceback (most recent call last):
- ...
- ValueError: cannot return an arbitrary item from an iterator
"""
if isinstance(iterable, Iterator):
diff --git a/networkx/utils/tests/test_misc.py b/networkx/utils/tests/test_misc.py
index 4abb7ce6..8f35d74b 100644
--- a/networkx/utils/tests/test_misc.py
+++ b/networkx/utils/tests/test_misc.py
@@ -4,6 +4,7 @@ import pytest
import networkx as nx
import random
from networkx.utils import (
+ arbitrary_element,
create_py_random_state,
create_random_state,
discrete_sequence,
@@ -271,3 +272,30 @@ def test_PythonRandomInterface():
)
assert rng.randint(3, 5) == rs42.randint(3, 6)
assert rng.random() == rs42.random_sample()
+
+
+@pytest.mark.parametrize(
+ ("iterable_type", "expected"),
+ (
+ (list, 1),
+ (tuple, 1),
+ (str, "["),
+ (set, 1),
+ ),
+)
+def test_arbitrary_element(iterable_type, expected):
+ iterable = iterable_type([1, 2, 3])
+ assert arbitrary_element(iterable) == expected
+
+
+@pytest.mark.parametrize(
+ "iterator",
+ (
+ (i for i in range(3)), # generator
+ iter([1, 2, 3]),
+ ),
+)
+def test_arbitrary_element_raises(iterator):
+ """Value error is raised when input is an iterator."""
+ with pytest.raises(ValueError, match="from an iterator"):
+ arbitrary_element(iterator)