len(s)
Number of characters. Works on any sequence (string, list, dict, set, tuple).
len("hello") # 5Fix these before they cost you minutes.
| You reach for | Doesn't exist / does something else | Use instead |
|---|---|---|
.splice() | Not Python (that's JS arrays) | slicing lst[1:3], .pop(i), del lst[i], lst[1:3] = [...] |
.length / .size | not an attribute | len(x) |
.substring(a, b) | no such method | s[a:b] |
.toString() | no | str(x) |
.indexOf() | no | .index(x) (raises if absent) or .find(x) (returns -1) |
.push() | no | .append(x) |
.map { } / .filter { } | exist but return lazy iterators | comprehensions [f(x) for x in xs if cond] |
s[0] = "a" | strings are immutable — TypeError | rebuild: "a" + s[1:] |
x++ | no such operator | x += 1 |
&& || ! | no | and or not |
null | no | None |
switch | (3.10+ has match, don't bother) | if/elif chain or a dict |
Number of characters. Works on any sequence (string, list, dict, set, tuple).
len("hello") # 5Returns a new string in that case. The standard first move for case-insensitive comparison.
"HeLLo".lower() # "hello"Flip each letter's case / Title Case Each Word / Capitalize only the first char.
"hello world".title() # "Hello World"
"hELLO".swapcase() # "Hello"Removes whitespace from both ends (or just left/right). Pass a string of characters to strip those instead.
" hi ".strip() # "hi"
"xxhixx".strip("x") # "hi"Splits a string into a list. No argument = split on any run of whitespace and drop empties — that's the one you want 90% of the time.
"a b c".split() # ['a', 'b', 'c']
"a,b,c".split(",") # ['a', 'b', 'c']
"a-b-c".split("-", 1) # ['a', 'b-c'] (maxsplit)Glues an iterable of strings into one string. Note it's called on the separator, not the list. Fails if any element isn't a string.
"".join(['e','h','o']) # "eho"
", ".join(['a','b']) # "a, b"
"-".join(str(n) for n in [1,2]) # "1-2"Replaces every occurrence. Add a count to limit it. Deleting = replace with "".
"a-b-c".replace("-", "") # "abc"
"aaa".replace("a", "b", 2) # "bba"Both give the position of the first occurrence. .find() returns -1 if missing; .index() raises ValueError. Use .find() when absence is a normal outcome.
"hello".find("z") # -1
"hello".find("l") # 2Substring / membership test. Reads like English, works on strings, lists, dicts (checks keys), sets.
"ell" in "hello" # True
3 in [1, 2, 3] # TrueCounts non-overlapping occurrences. Fastest way to answer "how many X are in this?" for a single X.
"banana".count("a") # 3Boolean prefix/suffix check. Accepts a tuple to test several at once.
"hello.py".endswith((".py", ".txt")) # TrueTrue if every char in the string is a letter / digit / letter-or-digit / whitespace. Empty string → always False.
"abc".isalpha() # True
"a1".isalpha() # False
"42".isdigit() # True
[c for c in s if c.isalnum()] # the classic cleaning filterTrue if all cased chars are upper/lower. Ignores digits and punctuation.
"HI!".isupper() # TruePads to width n — with zeros on the left, or with any character on the right/left.
"7".zfill(3) # "007"
"7".rjust(3, "*") # "**7"Inline interpolation. Format specs after a colon: :.2f (2 decimals), :03d (zero-pad), :, (thousands).
n = 3.14159
f"pi is {n:.2f}" # "pi is 3.14"
f"{5:03d}" # "005"Character → ASCII code, and back. The engine behind every cipher/shift problem. ord('a')=97, ord('A')=65, ord('0')=48.
ord('a') # 97
chr(97) # 'a'
chr((ord(c) - 97 + 1) % 26 + 97) # shift a lowercase letter by 1, wrappingBulk character-level swap or delete in one pass. Overkill for one replacement, perfect for many.
tbl = str.maketrans("abc", "xyz")
"cab".translate(tbl) # "zxy"
"hello".translate(str.maketrans("", "", "aeiou")) # "hll" (delete vowels)Grabs a sub-sequence. stop is exclusive. Any part is optional. Works on strings, lists, tuples. Never raises for out-of-range bounds — it just clips.
s = "abcdef"
s[1:4] # "bcd"
s[:3] # "abc" (from start)
s[3:] # "def" (to end)
s[-1] # "f" (last char)
s[-2:] # "ef" (last two)
s[:-1] # "abcde" (drop last)
s[::2] # "ace" (every 2nd)
s[::-1] # "fedcba" (REVERSE — memorize this one)The real answer to "JS .splice()". Replace, insert, or delete a chunk in place.
lst = [1,2,3,4]
lst[1:3] = [9] # [1, 9, 4] (replace 2 items with 1)
lst[1:1] = [7, 8] # [1, 7, 8, 9, 4] (insert without removing)
del lst[0:2] # [8, 9, 4] (delete).append adds one item (a list arg becomes a nested list). .extend adds each item of an iterable. + returns a new list.
a = [1,2]
a.append([3,4]) # [1, 2, [3, 4]] <- gotcha
b = [1,2]
b.extend([3,4]) # [1, 2, 3, 4]
[1,2] + [3,4] # [1, 2, 3, 4]Insert at index / remove-and-return by index (default last) / remove first matching value / delete by index or slice.
lst = [1,2,3]
lst.pop() # returns 3 -> lst = [1, 2]
lst.pop(0) # returns 1 -> lst = [2]
lst.remove(2) # lst = [] (by value, raises if absent)sorted() returns a new list and works on anything iterable (including strings → list of chars). .sort() mutates a list in place and returns None. Assigning x = lst.sort() gives you None — classic bug.
sorted("cba") # ['a', 'b', 'c']
sorted([3,1,2], reverse=True) # [3, 2, 1]
"".join(sorted("cba")) # "abc" (the anagram pattern)
lst.sort() # in place, returns NonePass a function that maps each item to the value to sort on. The single most useful sorting idea.
sorted(words, key=len) # by length
sorted(words, key=str.lower) # case-insensitive
sorted(pairs, key=lambda p: p[1]) # by 2nd element of each tuple
sorted(d.items(), key=lambda kv: -kv[1]) # dict by value, descendingIn-place / lazy iterator / new reversed copy. [::-1] is the one-liner for strings and lists both.
[1,2,3][::-1] # [3, 2, 1]
list(reversed([1,2,3])) # [3, 2, 1]First position of a value / how many times it appears.
[1,2,2].index(2) # 1
[1,2,2].count(2) # 2Convert any iterable to a list/tuple. list("abc") explodes a string into characters — the quickest way to get a mutable string.
list("abc") # ['a', 'b', 'c']
tuple([1,2]) # (1, 2)Key→value mapping. Insertion-ordered (3.7+). The default tool for counting, grouping, and lookup tables.
d = {"a": 1}
d["b"] = 2 # add / overwrite
d["a"] # 1 (KeyError if missing)Lookup that returns default (or None) instead of raising KeyError. The heart of the counting idiom.
d.get("z", 0) # 0
counts[c] = counts.get(c, 0) + 1 # count occurrences — memorize thisViews of the keys, values, or (key, value) pairs. .items() is what you loop over when you need both.
for k, v in d.items():
...
list(d.keys()) # ['a', 'b']
sum(d.values()) # 3Get-or-insert / remove-and-return safely / merge another dict in.
groups.setdefault(key, []).append(item) # group-by in one line
d.update({"c": 3})
{**d1, **d2} # merge into a new dictThe "most frequent item" one-liner — the key with the highest value.
max(counts, key=counts.get)Unordered collection of unique items with O(1) membership. Use for dedupe and "have I seen this?" checks. {} alone is an empty dict — use set().
set([1,1,2]) # {1, 2}
list(set(lst)) # dedupe (loses order)
len(set(s)) == len(s) # all characters unique?Intersection, union, difference — one operator each. Great for "common elements" / "in A but not B".
a & b # in both
a | b # in either
a - b # in a, not in b
a ^ b # in exactly one
set("aeiou") & set(word) # which vowels appearPurpose-built counting dict. .most_common(n) returns the top n (item, count) pairs already sorted.
from collections import Counter
c = Counter("hello") # Counter({'l': 2, 'h': 1, 'e': 1, 'o': 1})
c.most_common(1) # [('l', 2)]
c["l"] # 2 (missing keys give 0, not an error)
Counter(a) == Counter(b) # anagram checkA dict that auto-creates a default value for missing keys. Removes the if k not in d boilerplate when grouping.
from collections import defaultdict
g = defaultdict(list)
g["x"].append(1) # no KeyError; {'x': [1]}Cast between types. input() always hands you a string — coerce before math or range(). int("3.5") raises; use int(float("3.5")).
int("42") # 42
int("42") + 1 # 43 ("42" + 1 would TypeError
str(42) + "!" # "42!"
int(3.9) # 3 (truncates toward zero, no rounding)Floor division / remainder / power / both at once. % is the even-odd and wrap-around workhorse.
7 // 2 # 3
7 % 2 # 1
n % 2 == 0 # is even
2 ** 10 # 1024
divmod(7, 2) # (3, 1)Magnitude / rounding / smallest / largest / total. round() uses banker's rounding: round(2.5) is 2, not 3.
abs(-4) # 4
round(3.14159, 2) # 3.14
max([1,5,2]) # 5
max(3, 7) # 7
sum([1,2,3]) # 6
sum(1 for c in s if c in "aeiou") # count with a conditionimport math
math.sqrt(16) # 4.0
math.floor(2.7) # 2
math.ceil(2.1) # 3
math.gcd(12, 18) # 6
math.factorial(5) # 120
math.inf # sentinel for "worse than any real value"Empty things are falsy: "", [], {}, set(), 0, None. Everything else is truthy. if not lst: reads better than if len(lst) == 0:.
if not s: ... # empty string
x = val or "default" # fallback when val is falsyInteger sequence, stop exclusive. range(1, n+1) when you need 1..n inclusive.
for i in range(5): ... # 0,1,2,3,4
for i in range(1, n + 1): ... # 1..n
for i in range(len(s)-1, -1, -1): ... # backwardsDefault to iterating directly. Only reach for range(len(x)) when you truly need the index.
for c in "hello": ...
for item in lst: ...Gives (index, item) pairs when you need both. Beats manual counters.
for i, c in enumerate("abc"):
... # (0,'a'), (1,'b'), (2,'c')
for i, x in enumerate(lst, 1): ... # 1-basedWalks two (or more) sequences in lockstep. Stops at the shorter one.
for x, y in zip([1,2], "ab"): ... # (1,'a'), (2,'b')
dict(zip(keys, values)) # build a dict from two lists
list(zip(*matrix)) # transpose rows <-> columnsExit the loop / skip to next iteration. A loop's else runs only if no break fired — handy for "not found" cases.
for x in lst:
if bad(x): break
else:
print("none were bad")The variable appears on both sides. total = total + i, not total = num + i. Initialize to 0 for sums, 1 for products, "" for strings, [] for lists.
result = 1
for i in range(1, n + 1):
result = result * i # factorial[expr for item in iterable if condition] — map and filter in one line. Reach for this instead of append in a loop.
[x * 2 for x in [1,2,3]] # [2, 4, 6]
[c for c in s if c.isalpha()] # keep letters only
"".join(c for c in s if c.isalnum()) # clean string, one line
[x for x in a if x in b] # common elements[a if cond else b for x in xs] — note the if/else moves before the for when you need both branches.
["even" if n % 2 == 0 else "odd" for n in nums]Same shape, different brackets.
{k: v for k, v in pairs}
{c: s.count(c) for c in set(s)} # frequency map
{x for x in lst if x > 0} # unique positivesRead left to right, outer loop first.
[c for word in words for c in word] # flatten
[[row[i] for row in m] for i in range(len(m[0]))] # transposeTrue if any / all elements are truthy. Pair with a generator for a clean "does it contain..." check.
any(c.isdigit() for c in s) # contains a digit?
all(c.isalpha() for c in s) # letters only?Lazy transform/filter. Comprehensions are usually clearer, but map(int, ...) is genuinely nice.
list(map(int, "1 2 3".split())) # [1, 2, 3]
nums = [int(x) for x in input().split()] # same thing, preferred
sorted(lst, key=lambda x: x[1])Reach for regex only when string methods get ugly. Always use raw strings: r"...".
\d digit \w letter/digit/_ \s whitespace
\D non-digit \W non-word \S non-space
+ 1 or more * 0 or more ? optional
^ start $ end . any char
[abc] any of [^abc] none of [a-z] rangeReturns a list of every match. The go-to for extracting all numbers or words.
re.findall(r"\d+", "a1b22") # ['1', '22']
re.findall(r"[a-zA-Z]+", s) # all wordsReplace every match. The bluntest cleaning tool there is.
re.sub(r"[^a-z0-9]", "", s.lower()) # strip everything but alnum
re.sub(r"\s+", " ", s).strip() # collapse whitespaceFind the first match anywhere / only at the start. Returns a match object (truthy) or None; call .group() for the text.
m = re.search(r"\d+", s)
if m: m.group()Split on a pattern rather than a fixed separator.
re.split(r"[,;]\s*", "a, b;c") # ['a', 'b', 'c']The standard opening move: lowercase, strip, collapse, filter.
s = s.strip().lower()
s = "".join(c for c in s if c.isalnum())
words = s.split()input() gives text. Coerce explicitly.
n = int(input())
nums = [int(x) for x in input().split(",")]set() loses order; dict.fromkeys preserves it.
list(dict.fromkeys([3,1,3,2])) # [3, 1, 2][x for sub in nested for x in sub]groups = {}
for item in items:
groups.setdefault(key(item), []).append(item)from collections import Counter
Counter(items)
# or: counts[x] = counts.get(x, 0) + 1{v: k for k, v in d.items()}list(zip(*matrix)) # list of tuples
[list(r) for r in zip(*matrix)] # list of lists[x for x in lst if x] # drops "", 0, None, []
[x for x in lst if x is not None] # drops only Nonedef to_int(x, default=None):
try:
return int(x)
except (ValueError, TypeError):
return defaultArrays are fixed-type and vectorized: operate on the whole array at once, no loop.
Builds an ndarray from a (possibly nested) list. .shape gives dimensions, .dtype the element type.
a = np.array([1, 2, 3])
m = np.array([[1,2],[3,4]])
m.shape # (2, 2)Range-like array / N evenly spaced values / filled arrays of a given shape.
np.arange(0, 10, 2) # [0 2 4 6 8]
np.linspace(0, 1, 5) # [0. 0.25 0.5 0.75 1.]
np.zeros((2, 3)) # 2x3 of 0.0Arithmetic applies element-wise; scalars stretch across the array automatically.
a * 2 # [2 4 6]
a + a # [2 4 6]
a ** 2 # [1 4 9]
np.sqrt(a)A comparison gives a mask of True/False; index with it to filter.
a[a > 1] # [2 3]
mask = (a > 1) & (a < 3) # use & | ~, NOT and/or/not
a[mask] # [2]Element-wise if/else. With one argument, returns the indices where the condition is True.
np.where(a > 1, "big", "small") # ['small' 'big' 'big']
np.where(a > 1) # (array([1, 2]),)axis=0 collapses down the rows (per column); axis=1 collapses across the columns (per row).
m.sum() # everything
m.sum(axis=0) # column totals
m.mean(axis=1) # row means
a.min(), a.max(), a.std()
a.argmax() # index of the max, not the valueChange shape (use -1 to infer a dimension) / transpose / collapse to 1-D.
np.arange(6).reshape(2, 3)
np.arange(6).reshape(-1, 2) # infer rows
m.T
m.flatten()Sorted distinct values (optionally with counts) / join arrays / NaN mask for cleaning.
np.unique(a, return_counts=True)
np.concatenate([a, a])
a[~np.isnan(a)] # drop NaNsA DataFrame is a table; a Series is one column. Column-first thinking, not row loops.
df = pd.read_csv("f.csv")
df.head() # first 5 rows
df.shape # (rows, cols)
df.info() # dtypes + non-null counts (start here)
df.describe() # numeric summary
df.columns # column names.loc is label-based, .iloc is integer position-based. .loc slices are inclusive of the end label; .iloc isn't.
df["col"] # one column -> Series
df[["a", "b"]] # several -> DataFrame
df.loc[0, "col"] # by label
df.iloc[0] # first row by position
df.iloc[0:3, 1:] # positional blockSame idea as NumPy — build a condition, index with it. Use & | ~ and wrap each condition in parens.
df[df["age"] > 30]
df[(df["age"] > 30) & (df["city"] == "NY")]
df[df["name"].isin(["a", "b"])]
df.query("age > 30 and city == 'NY'") # string formdf.isna().sum() # nulls per column
df.dropna() # drop rows with any NaN
df.dropna(subset=["a"]) # only where column a is null
df.fillna(0)
df["a"].fillna(df["a"].mean())df.duplicated().sum()
df.drop_duplicates()
df.drop_duplicates(subset=["id"], keep="last")errors="coerce" turns unparseable junk into NaN instead of raising — the standard dirty-data move.
df["a"] = df["a"].astype(int)
df["a"] = pd.to_numeric(df["a"], errors="coerce")
df["d"] = pd.to_datetime(df["d"], errors="coerce")Applies string methods down a whole column. Everything from section 1 lives here.
df["name"].str.strip().str.lower()
df["name"].str.contains("smith", case=False)
df["full"].str.split(" ", expand=True) # -> multiple columns
df["s"].str.replace(r"\D", "", regex=True)df.rename(columns={"old": "new"})
df.drop(columns=["a", "b"])
df["total"] = df["x"] + df["y"] # vectorized, no loop
df["flag"] = df["x"].apply(lambda v: v > 0)
df["cat"] = df["code"].map({"A": "apple"}) # Series -> lookup swapdf["city"].value_counts() # frequency table, sorted desc
df["city"].value_counts(normalize=True) # proportions
df["city"].nunique()
df["city"].unique()df.sort_values("age", ascending=False)
df.sort_values(["city", "age"])
df.nlargest(3, "age")Split → apply → combine. .reset_index() turns the group keys back into normal columns.
df.groupby("city")["age"].mean()
df.groupby("city").agg({"age": "mean", "id": "count"})
df.groupby(["city", "job"]).size().reset_index(name="n")merge joins on keys (SQL-style); concat stacks.
pd.merge(a, b, on="id", how="left") # how: inner/left/right/outer
pd.concat([df1, df2], ignore_index=True) # stack rowsdf.pivot_table(index="city", columns="job", values="pay", aggfunc="mean")
df.melt(id_vars="id", var_name="k", value_name="v") # wide -> long
df.reset_index(drop=True)Assigning through a filtered view may silently do nothing. Use .loc for the whole operation.
df[df.a > 1]["b"] = 0 # BAD — may not stick
df.loc[df.a > 1, "b"] = 0 # GOODCtrl-F the word from the prompt.
| Term | What it means | Reach for |
|---|---|---|
| Character / char | a single letter, digit, or symbol | s[i], loop for c in s |
| Substring | a contiguous run of characters | slicing s[i:j], in |
| Subsequence | characters in order, gaps allowed | loop with a pointer |
| Delimiter / separator | the thing you split on | .split(sep) |
| Token | one piece after splitting | .split() |
| Concatenate | join end to end | +, "".join() |
| Alphanumeric | letters + digits only | .isalnum() |
| Alphabetical / lexicographic | dictionary order | sorted() |
| Case-insensitive | ignore upper/lower | .lower() both sides |
| Whitespace | spaces, tabs, newlines | .strip(), .split(), \s |
| Palindrome | reads the same reversed | s == s[::-1] |
| Anagram | same letters, reordered | sorted(a) == sorted(b) or Counter |
| Permutation | a reordering of the elements | sorted(), itertools.permutations |
| Vowels / consonants | aeiou / the rest | c in "aeiou" |
| ASCII code | the integer behind a char | ord() / chr() |
| Encode / cipher / shift | map chars to other chars | ord/chr + % 26 |
| Term | What it means | Reach for |
|---|---|---|
| Element / item | one value in a collection | for x in lst |
| Index | its position (0-based) | lst[i], enumerate |
| Iterable | anything you can loop over | list, str, dict, set, range |
| Mutable | can be changed in place | list, dict, set (not str/tuple) |
| In-place | modify the original, return nothing | .sort(), .append() |
| Nested | a collection inside a collection | [[1,2],[3]], double loop |
| Contiguous | side by side, no gaps | slicing, sliding window |
| Distinct / unique | no repeats | set(), .nunique() |
| Traverse / iterate | visit each element once | for loop |
| Matrix / 2-D array | list of rows | m[row][col] |
| Transpose | flip rows and columns | zip(*m), .T |
| Key–value pair | one dict entry | .items() |
| Frequency / occurrence | how many times it appears | Counter, .count() |
| Cumulative / running total | total so far at each step | accumulator loop |
| Sentinel | a placeholder "impossible" value | None, -1, math.inf |
| Term | What it means | Reach for |
|---|---|---|
| Sum | add them all | sum() |
| Product | multiply them all | accumulator, math.prod() |
| Mean / average | sum ÷ count | sum(x)/len(x), .mean() |
| Median | middle value when sorted | sorted() then middle index |
| Mode | most frequent value | Counter().most_common(1) |
| Absolute value | distance from zero | abs() |
| Floor / ceiling | round down / up | math.floor / math.ceil |
| Truncate | chop the decimals off | int(x) |
| Remainder / modulo | what's left after division | % |
| Even / odd | divisible by 2 or not | n % 2 == 0 |
| Divisor / factor | divides with no remainder | n % d == 0 |
| Multiple | n × some integer | x % n == 0 |
| Prime | divisible only by 1 and itself | trial division to sqrt(n) |
| Factorial (n!) | 1×2×…×n | accumulator or math.factorial |
| Fibonacci | each = sum of previous two | a, b = b, a + b |
| GCD / LCM | greatest common divisor / least common multiple | math.gcd, a*b//gcd |
| Exponent / power | repeated multiplication | ** |
| Ascending / descending | small→large / large→small | sorted(..., reverse=) |
| Consecutive | one after another with no gap | compare x[i+1] - x[i] == 1 |
| Ordered pair / tuple | a fixed small group | (a, b) |
| Swap | exchange two values | a, b = b, a |
| Boolean | True / False | bool, comparisons |
| Cast / coerce / parse | convert type | int(), str(), float() |
| Rounded to n places | round(x, n), f"{x:.2f}" | |
| Inclusive / exclusive | endpoint counted or not | range(1, n+1) for inclusive |
| Term | What it means | Reach for |
|---|---|---|
| Record / observation | one row | df.iloc[i] |
| Field / feature / attribute | one column | df["col"] |
| Schema / dtype | column names and types | df.info() |
| Null / NaN / missing | absent value | .isna(), .fillna() |
| Impute | fill missing values with something | .fillna(mean) |
| Deduplicate | remove repeated rows | .drop_duplicates() |
| Normalize | put on a common scale/format | (x - min)/(max - min), .str.lower() |
| Aggregate | collapse many rows to one number | .groupby().agg() |
| Group by | split into buckets, then aggregate | .groupby() |
| Join / merge | match rows across tables by key | pd.merge(..., on=) |
| Concatenate (tables) | stack them | pd.concat() |
| Filter / subset | keep only matching rows | boolean mask |
| Mask | array of True/False | df["a"] > 3 |
| Vectorized | whole column at once, no loop | df.a + df.b |
| Broadcast | scalar stretched across an array | arr * 2 |
| Axis 0 / axis 1 | down the rows / across the columns | .sum(axis=0) |
| Wide / long format | one row per entity / one row per measurement | .pivot_table() / .melt() |
| Outlier | value far from the rest | filter on quantiles |
| Cardinality | how many distinct values | .nunique() |
input() returns a string. Coerce it..sort() returns None. sorted() returns the list.Nothing matches.
Try a tag: