# Members Only

> Every digit wants in. Only the odd ones make the cut.

Canonical URL: <https://datadriven.io/problems/members_only>

Domain: Python · Difficulty: easy · Seniority: L3

## Problem

A legacy identity system exports employee IDs as strings of digit characters. Downstream reports keep only the odd digits from each ID, in the order they appear.

## Worked solution and explanation

### What this really is

Under the employee-ID costume this is a value predicate over a sequence: keep the characters whose numeric value is odd, drop the rest, hand back a string in the same order. Nobody fails the loop itself. Candidates trip on the definition of 'odd'. The tempting shortcuts all read like the answer and all lie: slicing every other character selects by POSITION not value, a set silently drops repeated odds, and sorting throws away the original order. Pick any of them and you don't get a close answer, you get a different string, and on an ID that must round-trip exactly, different is broken.

---

### The shortcuts that look right and aren't

**Positional slice**

s[::2] grabs every other character by index. On '2468' it returns '26', but there are no odd digits, so the answer must be ''. Selecting by position answers a different question than selecting by value.

**Value predicate**

Convert each character to an int and keep it only when the value is odd. On '2468' every digit is even, so nothing survives and you correctly return ''.

> **Trick to solving**
>
> The word 'odd' is about the digit's VALUE, not where it sits. Convert each character to an int, test value % 2, and append survivors to a list in the order you meet them. Order and duplicates come free because you never reorder or dedupe, you only skip.

---

### How to get there

#### Step 1: Walk the characters

Scan the input one character at a time. Each character is a digit, so its identity is its value.

#### Step 2: Test the value, not the index

Convert the character to an int and test parity with modulo 2. This is the line that separates 'odd value' from 'odd position': you are asking about the digit itself, not where it sits.

#### Step 3: Rebuild in order

Collect survivors in a list and join once at the end. Order and repeats are free because you never reorder, you just skip the evens.

---

### The solution

**Value-based digit filter**

```python
def filter_odd_digits(s: str) -> str:
    result = []
    for ch in s:
        if int(ch) % 2 != 0:
            result.append(ch)
    return ''.join(result)
```

> **Cost**
>
> **Time:** O(n) over the string length. **Space:** O(k) for the k odd digits kept. A single pass is plenty for the few-thousand-character IDs this sees.

> **Interviewers watch for**
>
> The empty string and the all-even string ('2468') both fall out for free: the loop keeps nothing and join returns ''. A candidate who special-cases these is writing code they don't need.

> **Common pitfall**
>
> Growing the result with `result += ch` inside the loop. Python strings are immutable, so each concatenation copies the whole string so far, quietly turning an O(n) scan into O(n^2). Accumulate in a list and join once.

---

## Common follow-up questions

- What if the input contained non-digit characters? _(Tests adding an `isdigit()` guard before the int conversion.)_
- How would you return the even digits instead? _(Tests flipping the parity condition.)_
- What if you needed both odd and even digits as separate results? _(Tests building two result lists in a single pass.)_

## Related

- [All practice problems](https://datadriven.io/problems)
- [Mock interview mode](https://datadriven.io/interview/members_only)
- [Python Interview Questions](https://datadriven.io/python-interview-questions)
- [Data Engineering Interview Prep Guide](https://datadriven.io/data-engineer-interview-prep)
- [Daily Challenge](https://datadriven.io/daily)

---

Source: DataDriven (https://datadriven.io). DataDriven is the data engineering interview community. Live code execution in SQL, Python, and Spark sandboxes. Every feature is open to every member.