Repository: pyjanitor-devs/pyjanitor

Issue:
Add function: filter_column_isin
Some notes for myself:

```python
@pf.register_dataframe_method
def filter_column_isin(df, column, iterable):
    return df[df[column].isin(iterable)]
```


Discussion:

Resolving patch:
diff --git a/janitor/functions.py b/janitor/functions.py
--- a/janitor/functions.py
+++ b/janitor/functions.py
@@ -3,14 +3,14 @@
 """
 import datetime as dt
 import re
+import warnings
 from functools import partial, reduce
-from typing import List, Union, Dict
+from typing import Dict, Iterable, List, Union
 
 import numpy as np
 import pandas as pd
 import pandas_flavor as pf
 from scipy.stats import mode
-import warnings
 from sklearn.preprocessing import LabelEncoder
 
 from .errors import JanitorError
@@ -1100,6 +1100,53 @@ def _get_day(x):
     return df.loc[_date_filter_conditions(_filter_list), :]
 
 
+@pf.register_dataframe_method
+def filter_column_isin(
+    df: pd.DataFrame, column: str, iterable: Iterable, complement: bool = False
+):
+    """
+    Filters a dataframe based on whether the values of a given column are
+    present inside another iterable.
+
+    Assumes exact matching; fuzzy matching not implemented
+
+    The below example syntax will filter the DataFrame such that we only get
+    rows for which the "names" are exactly "James" and "John".
+
+    .. code-block:: python
+
+        df = (
+            pd.DataFrame(...)
+            .clean_names()
+            .filter_column_isin(column="names", iterable=["James", "John"]
+            )
+        )
+
+    This is the method chaining alternative to:
+
+    .. code-block:: python
+
+        df = df[df['names'].isin(['James', 'John'])]
+
+    :param df: A pandas DataFrame
+    :param column: The column on which to filter.
+    :param iterable: An iterable. Could be a list, tuple, another pandas
+        Series.
+    :param complement: Whether to return the complement of the selection or
+        not.
+    """
+    if len(iterable) == 0:
+        raise ValueError(
+            "`iterable` kwarg must be given an iterable of length 1 or greater"
+        )
+    criteria = df[column].isin(iterable)
+
+    if complement:
+        return df[~criteria]
+    else:
+        return df[criteria]
+
+
 @pf.register_dataframe_method
 def remove_columns(df: pd.DataFrame, columns: List):
     """


Test patch:
diff --git a/janitor/testing_utils/fixtures.py b/janitor/testing_utils/fixtures.py
--- a/janitor/testing_utils/fixtures.py
+++ b/janitor/testing_utils/fixtures.py
@@ -3,6 +3,7 @@
 import numpy as np
 import pandas as pd
 import pytest
+
 from janitor.testing_utils import date_data
 
 TEST_DATA_DIR = (
diff --git a/janitor/testing_utils/strategies.py b/janitor/testing_utils/strategies.py
--- a/janitor/testing_utils/strategies.py
+++ b/janitor/testing_utils/strategies.py
@@ -44,8 +44,26 @@ def test_function(df):
 def categoricaldf_strategy():
     return data_frames(
         columns=[
-            column("class_label", st.sampled_from(["test1", "test2"])),
-            column("numbers", st.sampled_from([1, 2, 3])),
+            column("names", st.sampled_from(names)),
+            column("numbers", st.sampled_from(range(3))),
         ],
         index=range_indexes(min_size=1, max_size=20),
     )
+
+
+names = [
+    "John",
+    "Mark",
+    "Luke",
+    "Matthew",
+    "Peter",
+    "Adam",
+    "Eve",
+    "Mary",
+    "Ruth",
+    "Esther",
+]
+
+
+def names_strategy():
+    return st.lists(elements=st.sampled_from(names))
diff --git a/tests/functions/test_encode_categorical.py b/tests/functions/test_encode_categorical.py
--- a/tests/functions/test_encode_categorical.py
+++ b/tests/functions/test_encode_categorical.py
@@ -11,8 +11,8 @@
 @pytest.mark.functions
 @given(df=categoricaldf_strategy())
 def test_encode_categorical(df):
-    df = df.encode_categorical("class_label")
-    assert df["class_label"].dtypes == "category"
+    df = df.encode_categorical("names")
+    assert df["names"].dtypes == "category"
 
 
 @pytest.mark.functions
diff --git a/tests/functions/test_filter_column_isin.py b/tests/functions/test_filter_column_isin.py
new file mode 100644
--- /dev/null
+++ b/tests/functions/test_filter_column_isin.py
@@ -0,0 +1,16 @@
+import pandas as pd
+import pytest
+from hypothesis import assume, given
+
+from janitor.testing_utils.strategies import (
+    categoricaldf_strategy,
+    names_strategy,
+)
+
+
+@pytest.mark.functions
+@given(df=categoricaldf_strategy(), iterable=names_strategy())
+def test_filter_column_isin(df, iterable):
+    assume(len(iterable) >= 1)
+    df = df.filter_column_isin("names", iterable)
+    assert set(df["names"]).issubset(iterable)
diff --git a/tests/functions/test_filter_date.py b/tests/functions/test_filter_date.py
--- a/tests/functions/test_filter_date.py
+++ b/tests/functions/test_filter_date.py
@@ -1,6 +1,7 @@
 import numpy as np
 import pandas as pd
 import pytest
+
 from janitor.testing_utils.fixtures import date_dataframe