diff --git a/.travis.yml b/.travis.yml
index 64cf253c88cbe2c4ff997e8e88167dd34560d3c6..0835bafe4270352d50fb95854b55292f6de8bb67 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -9,7 +9,6 @@ python:
 cache: pip
 install:
   - pip install -r requirements.txt
-  - pip install pyyaml toml
   - pip install --force-reinstall "coverage>=4.0,<4.4" codeclimate-test-reporter # for codeclimate-test-reporter
 script:
   - bash tests/test_posix/test_hang_until_sig.sh
diff --git a/CHANGELOG.md b/CHANGELOG.md
index ff642575c0149c8fdced8fe6091c3e75981c8cb8..49fd0d32b5255bddcf33ab42a40308b8239588bf 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,6 +1,6 @@
 # v2.2.17
 
-* _TBA_
+* added [choose](satella/coding/sequences/choose.py)
 
 # v2.2.16
 
diff --git a/docs/coding/sequences.rst b/docs/coding/sequences.rst
new file mode 100644
index 0000000000000000000000000000000000000000..b08ecbf6cb883274dd009ef6edb65a0db8480aa4
--- /dev/null
+++ b/docs/coding/sequences.rst
@@ -0,0 +1,6 @@
+choose
+======
+
+To return the single element that returns true on given callable, use the following function:
+
+.. autofunction:: satella.coding.sequences.choose
diff --git a/docs/index.rst b/docs/index.rst
index 3168e26af403c6b7a8dcd1591cf786b1d8f47ecf..222e5ca42b0d12af7966471596e3324269c5c618 100644
--- a/docs/index.rst
+++ b/docs/index.rst
@@ -2,6 +2,10 @@
 Welcome to satella's documentation!
 ===================================
 
+Visit the project's page at GitHub_!
+
+.. _GitHub: https://github.com/piotrmaslanka/satella
+
 .. toctree::
            :maxdepth: 2
            :caption: Contents
@@ -11,6 +15,7 @@ Welcome to satella's documentation!
            coding/functions
            coding/structures
            coding/concurrent
+           coding/sequences
            instrumentation/traceback
            instrumentation/metrics
            exception_handling
diff --git a/requirements.txt b/requirements.txt
index a4d92cc08db6a0d8bfedbbbd620d1fb11f84677b..d36e77a2cf5accf12f8f22e842bfb5d8f2be0291 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -1 +1,3 @@
 psutil
+pyyaml
+toml
diff --git a/satella/__init__.py b/satella/__init__.py
index 2b8a694a5795cc5c6dd4fbfbc56a330590fb3a30..342df280d318f2925ee80147d8078c3a87a40af1 100644
--- a/satella/__init__.py
+++ b/satella/__init__.py
@@ -1,2 +1,2 @@
 # coding=UTF-8
-__version__ = '2.2.17a1'
+__version__ = '2.2.17'
diff --git a/satella/coding/sequences/__init__.py b/satella/coding/sequences/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..7dfca4cc8ccd57b8c01f2f2dca4a21191ca71e56
--- /dev/null
+++ b/satella/coding/sequences/__init__.py
@@ -0,0 +1,4 @@
+from .choose import choose
+
+
+__all__ = ['choose']
diff --git a/satella/coding/sequences/choose.py b/satella/coding/sequences/choose.py
new file mode 100644
index 0000000000000000000000000000000000000000..f323506cea1aa2bd1caab0dd52221bc810f1fafe
--- /dev/null
+++ b/satella/coding/sequences/choose.py
@@ -0,0 +1,30 @@
+import typing as tp
+
+T = tp.TypeVar('T')
+
+__all__ = ['choose']
+
+
+def choose(filter_fun: tp.Callable[[T], bool], iterable: tp.Iterable[T]) -> T:
+    """
+    Return a single value that exists in given iterable
+
+    :param filter_fun: function that returns bool on the single value
+    :param iterable: iterable to examine
+    :return: single element in the iterable that matches given input
+    :raises ValueError: on multiple elements matching, or none at all
+    """
+    elem_candidate = None
+    found = False
+    for elem in iterable:
+        if filter_fun(elem):
+            if found:
+                raise ValueError(
+                    'Multiple values (%s, %s) seen' % (repr(elem_candidate), repr(elem)))
+            elem_candidate = elem
+            found = True
+
+    if not found:
+        raise ValueError('No elements matching given filter seen')
+
+    return elem_candidate
diff --git a/tests/test_coding/test_sequences.py b/tests/test_coding/test_sequences.py
new file mode 100644
index 0000000000000000000000000000000000000000..307b756bc6258d627222e6b3f0db4fbfcfbee0cc
--- /dev/null
+++ b/tests/test_coding/test_sequences.py
@@ -0,0 +1,14 @@
+import logging
+import typing as tp
+import unittest
+
+from satella.coding.sequences import choose
+
+logger = logging.getLogger(__name__)
+
+
+class TestSequences(unittest.TestCase):
+    def test_choose(self):
+        self.assertEqual(choose(lambda x: x == 2, [1, 2, 3, 4, 5]), 2)
+        self.assertRaises(ValueError, lambda: choose(lambda x: x % 2 == 0, [1, 2, 3, 4, 5]))
+        self.assertRaises(ValueError, lambda: choose(lambda x: x == 0, [1, 2, 3, 4, 5]))