ENH: Add Index.filter() method
- [ ] closes #xxxx (Replace xxxx with the GitHub issue number)
  - New feature - no issue
- [x] [Tests added and passed](https://pandas.pydata.org/pandas-docs/dev/development/contributing_codebase.html#writing-tests) if fixing a bug or adding a new feature
  - `pandas\pandas\tests\indexes\test_base.py:TestIndex.test_filter_string()`
  - `pandas\pandas\tests\indexes\test_base.py:TestIndex.test_filter_int()`
- [x] All [code checks passed](https://pandas.pydata.org/pandas-docs/dev/development/contributing_codebase.html#pre-commit).
- [x] Added [type annotations](https://pandas.pydata.org/pandas-docs/dev/development/contributing_codebase.html#type-hints) to new arguments/methods/functions.
- [x] Added an entry in the latest `doc/source/whatsnew/v2.0.0.rst` file if fixing a bug or adding a new feature.

This is similar to `DataFrame.filter()`, except it returns an `Index` object, and avoids any under-the-hood things that might be happening with `DataFrame.filter()` in terms of views/copies of the `DataFrame`.   Some examples where this would be useful (and helpful when doing type checking).

- Instead of `df.columns = [x for x in otherdf.columns if "at" in x]`, you can do `df.columns = otherdf.columns.filter(like="at")`
- Instead of `df.drop(columns=[x for x in df.columns if x.startswith("b")]`, you can do `df.drop(columns=df.columns.filter(regex=r"b.*")`
- Instead of `df.set_index([x for x in df.columns if x.endswith("z")])`, you can do `df.set_index(df.columns.filter(r".*z$"))`


-1 here this is a confusing name (well it's an ok name except filter for dataframe does this) > I might be missing something, but can't you do this mostly with the string accesors as well?

Yes, but it's a bit awkward, because the string accessors return boolean arrays.

Comparison using example `idx = pd.Index(["cat", "dog", "bat", "bird"], dtype=object)`

| Accessors |  With this PR |
| ---- | ---- |
| `idx[idx.isin(["cat", "dog"])]` | `idx.filter(["cat", "dog"])` |
| `idx[idx.str.contains("at")]`  | `idx.filter(like="at")` |
| `idx[idx.str.match(r"b.*")]`  | `idx.filter(match=r"b.*")` |

I also think this PR will be more performant, because you are making just one pass through the index.
 > -1 here this is a confusing name (well it's an ok name except filter for dataframe does this)

Yes, but filter for `DataFrame` returns the entire `DataFrame`, and the goal here is to return a filtered `Index` .  Open to using a different name.

 Looks like this PR has gone stale and might need some discussion on an issue first before moving forward. Going to close for now, but we can reopen when ready to move forward