SWISS ARRAYpython reference
199 tools

False friends (Python vs JS)

Fix these before they cost you minutes.

You reach forDoesn't exist / does something elseUse instead
.splice()Not Python (that's JS arrays)slicing lst[1:3], .pop(i), del lst[i], lst[1:3] = [...]
.length / .sizenot an attributelen(x)
.substring(a, b)no such methods[a:b]
.toString()nostr(x)
.indexOf()no.index(x) (raises if absent) or .find(x) (returns -1)
.push()no.append(x)
.map { } / .filter { }exist but return lazy iteratorscomprehensions [f(x) for x in xs if cond]
s[0] = "a"strings are immutable — TypeErrorrebuild: "a" + s[1:]
x++no such operatorx += 1
&& || !noand or not
nullnoNone
switch(3.10+ has match, don't bother)if/elif chain or a dict

Strings

len(s)

  • #string
  • #list
  • #int

Number of characters. Works on any sequence (string, list, dict, set, tuple).

len("hello")            # 5

.lower() / .upper()

  • #string
  • #cleaning

Returns a new string in that case. The standard first move for case-insensitive comparison.

"HeLLo".lower()         # "hello"

.swapcase() / .title() / .capitalize()

  • #string

Flip each letter's case / Title Case Each Word / Capitalize only the first char.

"hello world".title()   # "Hello World"
"hELLO".swapcase()      # "Hello"

.strip() / .lstrip() / .rstrip()

  • #string
  • #cleaning

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"

.split(sep=None)

  • #string
  • #string-to-list
  • #wrangling

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)

"sep".join(iterable)

  • #string
  • #list-to-string

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"

.replace(old, new)

  • #string
  • #cleaning

Replaces every occurrence. Add a count to limit it. Deleting = replace with "".

"a-b-c".replace("-", "")   # "abc"
"aaa".replace("a", "b", 2) # "bba"

.find(sub) vs .index(sub)

  • #string
  • #searching
  • #int

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")       # 2

in

  • #string
  • #list
  • #bool
  • #searching

Substring / membership test. Reads like English, works on strings, lists, dicts (checks keys), sets.

"ell" in "hello"        # True
3 in [1, 2, 3]          # True

.count(sub)

  • #string
  • #counting
  • #int

Counts non-overlapping occurrences. Fastest way to answer "how many X are in this?" for a single X.

"banana".count("a")     # 3

.startswith(p) / .endswith(p)

  • #string
  • #bool
  • #searching

Boolean prefix/suffix check. Accepts a tuple to test several at once.

"hello.py".endswith((".py", ".txt"))   # True

.isalpha() / .isdigit() / .isalnum() / .isspace()

  • #string
  • #char
  • #bool
  • #cleaning
  • #filtering

True 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 filter

.isupper() / .islower()

  • #string
  • #bool

True if all cased chars are upper/lower. Ignores digits and punctuation.

"HI!".isupper()         # True

.zfill(n) / .rjust(n, c) / .ljust(n, c)

  • #string
  • #cleaning

Pads to width n — with zeros on the left, or with any character on the right/left.

"7".zfill(3)            # "007"
"7".rjust(3, "*")       # "**7"

f"{value}" — f-strings

  • #string
  • #int-to-char
  • #cleaning

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"

ord(c) / chr(n)

  • #char-to-int
  • #int-to-char
  • #char
  • #math

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, wrapping

str.maketrans() + .translate()

  • #string
  • #cleaning

Bulk 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)

Slicing

seq[start:stop:step]

  • #slicing
  • #string
  • #list

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)

Slice assignment (lists only)

  • #slicing
  • #list
  • #gotcha

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)

Lists

.append(x) vs .extend(iterable) vs +

  • #list
  • #gotcha

.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(i, x) / .pop(i) / .remove(x) / del

  • #list

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(iterable) vs .sort()

  • #sorting
  • #list
  • #string
  • #gotcha

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 None

key= — sorting by a rule

  • #sorting
  • #list
  • #dict

Pass 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, descending

.reverse() / reversed() / [::-1]

  • #list
  • #slicing

In-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]

.index(x) / .count(x)

  • #list
  • #searching
  • #counting

First position of a value / how many times it appears.

[1,2,2].index(2)        # 1
[1,2,2].count(2)        # 2

list() / tuple()

  • #string-to-list
  • #list
  • #tuple

Convert 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)

Dicts & Sets

dict() / {}

  • #dict

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)

.get(key, default)

  • #dict
  • #counting

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 this

.keys() / .values() / .items()

  • #dict
  • #loop

Views 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())         # 3

.setdefault(k, default) / .pop(k, default) / .update(other)

  • #dict
  • #wrangling

Get-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 dict

max(d, key=d.get)

  • #dict
  • #counting
  • #searching

The "most frequent item" one-liner — the key with the highest value.

max(counts, key=counts.get)

set() / {1,2,3}

  • #set
  • #filtering
  • #cleaning

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?

Set operations

  • #set
  • #filtering

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 appear

collections.Counter

  • #counting
  • #dict
  • #string

Purpose-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 check

collections.defaultdict

  • #dict
  • #wrangling

A 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]}

Numbers, math & coercion

int() / float() / str()

  • #string-to-int
  • #int
  • #gotcha
  • #cleaning

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)

// % ** divmod()

  • #math
  • #int

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)

abs() / round() / min() / max() / sum()

  • #math
  • #int
  • #float
  • #list

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 condition

math module essentials

  • #math
  • #float
  • #int
import 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"

Truthiness

  • #bool
  • #gotcha

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 falsy

Loops & iteration

range(start, stop, step)

  • #loop
  • #int

Integer 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): ...  # backwards

Loop the items, not the indices

  • #loop

Default to iterating directly. Only reach for range(len(x)) when you truly need the index.

for c in "hello": ...
for item in lst:  ...

enumerate(iterable, start=0)

  • #loop
  • #list
  • #string

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-based

zip(a, b)

  • #loop
  • #list
  • #dict
  • #wrangling

Walks 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 <-> columns

break / continue / else

  • #loop

Exit 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")

Accumulator pattern

  • #loop
  • #math
  • #gotcha

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

Comprehensions & functional tools

List comprehension

  • #list
  • #filtering
  • #cleaning

[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

Conditional expression inside

  • #list
  • #gotcha

[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]

Dict & set comprehensions

  • #dict
  • #set
  • #counting

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 positives

Nested loops in a comprehension

  • #list
  • #wrangling

Read 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]))]   # transpose

any() / all()

  • #bool
  • #filtering
  • #searching

True 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?

map() / filter() / lambda

  • #list
  • #string-to-int
  • #wrangling

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])

Regex (`import re`)

Reach for regex only when string methods get ugly. Always use raw strings: r"...".

Cheat patterns

\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] range

re.findall(pattern, s)

  • #regex
  • #string-to-list
  • #wrangling

Returns 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 words

re.sub(pattern, repl, s)

  • #regex
  • #cleaning

Replace 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 whitespace

re.search(pattern, s) / re.match(...)

  • #regex
  • #searching

Find 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()

re.split(pattern, s)

  • #regex
  • #string-to-list

Split on a pattern rather than a fixed separator.

re.split(r"[,;]\s*", "a, b;c")     # ['a', 'b', 'c']

Data wrangling & cleaning (pure Python)

Normalize a string

  • #cleaning
  • #string

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()

Parse numbers from stdin

  • #string-to-int
  • #cleaning
  • #gotcha

input() gives text. Coerce explicitly.

n = int(input())
nums = [int(x) for x in input().split(",")]

Dedupe, keeping order

  • #cleaning
  • #list

set() loses order; dict.fromkeys preserves it.

list(dict.fromkeys([3,1,3,2]))     # [3, 1, 2]

Flatten a nested list

  • #wrangling
  • #list
[x for sub in nested for x in sub]

Group by a key

  • #wrangling
  • #dict
groups = {}
for item in items:
    groups.setdefault(key(item), []).append(item)

Frequency map

  • #counting
  • #dict
from collections import Counter
Counter(items)
# or: counts[x] = counts.get(x, 0) + 1

Swap keys and values

  • #dict
  • #wrangling
{v: k for k, v in d.items()}

Transpose a matrix

  • #wrangling
  • #list
list(zip(*matrix))                  # list of tuples
[list(r) for r in zip(*matrix)]     # list of lists

Filter out empties / None

  • #cleaning
  • #filtering
  • #gotcha
[x for x in lst if x]               # drops "", 0, None, []
[x for x in lst if x is not None]   # drops only None

Safe cast with a fallback

  • #cleaning
  • #string-to-int
def to_int(x, default=None):
    try:
        return int(x)
    except (ValueError, TypeError):
        return default

NumPy (`import numpy as np`)

Arrays are fixed-type and vectorized: operate on the whole array at once, no loop.

np.array(list)

  • #numpy

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)

np.arange / np.linspace / np.zeros / np.ones / np.full

  • #numpy

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.0

Vectorized math & broadcasting

  • #numpy
  • #math

Arithmetic 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)

Boolean indexing

  • #numpy
  • #filtering
  • #gotcha

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]

np.where(cond, x, y)

  • #numpy
  • #filtering

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]),)

Aggregations & axis

  • #numpy
  • #math
  • #gotcha

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 value

.reshape() / .T / .flatten()

  • #numpy
  • #wrangling

Change 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()

np.unique / np.concatenate / np.isnan

  • #numpy
  • #cleaning
  • #counting

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 NaNs

Pandas (`import pandas as pd`)

A DataFrame is a table; a Series is one column. Column-first thinking, not row loops.

Load & look

  • #pandas
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

Select columns and rows

  • #pandas
  • #gotcha

.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 block

Filter with a boolean mask

  • #pandas
  • #filtering

Same 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 form

Missing data

  • #pandas
  • #cleaning
df.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())

Duplicates

  • #pandas
  • #cleaning
df.duplicated().sum()
df.drop_duplicates()
df.drop_duplicates(subset=["id"], keep="last")

Types & coercion

  • #pandas
  • #cleaning
  • #string-to-int

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")

The .str accessor

  • #pandas
  • #cleaning
  • #string

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)

Rename, drop, add

  • #pandas
  • #wrangling
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 swap

Counting & uniques

  • #pandas
  • #counting
df["city"].value_counts()               # frequency table, sorted desc
df["city"].value_counts(normalize=True) # proportions
df["city"].nunique()
df["city"].unique()

Sort

  • #pandas
  • #sorting
df.sort_values("age", ascending=False)
df.sort_values(["city", "age"])
df.nlargest(3, "age")

Group & aggregate

  • #pandas
  • #wrangling
  • #counting

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")

Combine tables

  • #pandas
  • #wrangling

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 rows

Reshape

  • #pandas
  • #wrangling
df.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)

Chained-assignment gotcha

  • #pandas
  • #gotcha

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      # GOOD

Translator — problem-statement English → Python

Ctrl-F the word from the prompt.

Word / string vocabulary

TermWhat it meansReach for
Character / chara single letter, digit, or symbols[i], loop for c in s
Substringa contiguous run of charactersslicing s[i:j], in
Subsequencecharacters in order, gaps allowedloop with a pointer
Delimiter / separatorthe thing you split on.split(sep)
Tokenone piece after splitting.split()
Concatenatejoin end to end+, "".join()
Alphanumericletters + digits only.isalnum()
Alphabetical / lexicographicdictionary ordersorted()
Case-insensitiveignore upper/lower.lower() both sides
Whitespacespaces, tabs, newlines.strip(), .split(), \s
Palindromereads the same reverseds == s[::-1]
Anagramsame letters, reorderedsorted(a) == sorted(b) or Counter
Permutationa reordering of the elementssorted(), itertools.permutations
Vowels / consonantsaeiou / the restc in "aeiou"
ASCII codethe integer behind a charord() / chr()
Encode / cipher / shiftmap chars to other charsord/chr + % 26

Structure vocabulary

TermWhat it meansReach for
Element / itemone value in a collectionfor x in lst
Indexits position (0-based)lst[i], enumerate
Iterableanything you can loop overlist, str, dict, set, range
Mutablecan be changed in placelist, dict, set (not str/tuple)
In-placemodify the original, return nothing.sort(), .append()
Nesteda collection inside a collection[[1,2],[3]], double loop
Contiguousside by side, no gapsslicing, sliding window
Distinct / uniqueno repeatsset(), .nunique()
Traverse / iteratevisit each element oncefor loop
Matrix / 2-D arraylist of rowsm[row][col]
Transposeflip rows and columnszip(*m), .T
Key–value pairone dict entry.items()
Frequency / occurrencehow many times it appearsCounter, .count()
Cumulative / running totaltotal so far at each stepaccumulator loop
Sentinela placeholder "impossible" valueNone, -1, math.inf

Math vocabulary

TermWhat it meansReach for
Sumadd them allsum()
Productmultiply them allaccumulator, math.prod()
Mean / averagesum ÷ countsum(x)/len(x), .mean()
Medianmiddle value when sortedsorted() then middle index
Modemost frequent valueCounter().most_common(1)
Absolute valuedistance from zeroabs()
Floor / ceilinground down / upmath.floor / math.ceil
Truncatechop the decimals offint(x)
Remainder / modulowhat's left after division%
Even / odddivisible by 2 or notn % 2 == 0
Divisor / factordivides with no remaindern % d == 0
Multiplen × some integerx % n == 0
Primedivisible only by 1 and itselftrial division to sqrt(n)
Factorial (n!)1×2×…×naccumulator or math.factorial
Fibonaccieach = sum of previous twoa, b = b, a + b
GCD / LCMgreatest common divisor / least common multiplemath.gcd, a*b//gcd
Exponent / powerrepeated multiplication**
Ascending / descendingsmall→large / large→smallsorted(..., reverse=)
Consecutiveone after another with no gapcompare x[i+1] - x[i] == 1
Ordered pair / tuplea fixed small group(a, b)
Swapexchange two valuesa, b = b, a
BooleanTrue / Falsebool, comparisons
Cast / coerce / parseconvert typeint(), str(), float()
Rounded to n placesround(x, n), f"{x:.2f}"
Inclusive / exclusiveendpoint counted or notrange(1, n+1) for inclusive

Data / stats vocabulary (for the pandas-flavoured stuff)

TermWhat it meansReach for
Record / observationone rowdf.iloc[i]
Field / feature / attributeone columndf["col"]
Schema / dtypecolumn names and typesdf.info()
Null / NaN / missingabsent value.isna(), .fillna()
Imputefill missing values with something.fillna(mean)
Deduplicateremove repeated rows.drop_duplicates()
Normalizeput on a common scale/format(x - min)/(max - min), .str.lower()
Aggregatecollapse many rows to one number.groupby().agg()
Group bysplit into buckets, then aggregate.groupby()
Join / mergematch rows across tables by keypd.merge(..., on=)
Concatenate (tables)stack thempd.concat()
Filter / subsetkeep only matching rowsboolean mask
Maskarray of True/Falsedf["a"] > 3
Vectorizedwhole column at once, no loopdf.a + df.b
Broadcastscalar stretched across an arrayarr * 2
Axis 0 / axis 1down the rows / across the columns.sum(axis=0)
Wide / long formatone row per entity / one row per measurement.pivot_table() / .melt()
Outliervalue far from the restfilter on quantiles
Cardinalityhow many distinct values.nunique()

Test-day reflexes

  • Save, then run. Output identical to input = stale file, not broken logic.
  • input() returns a string. Coerce it.
  • .sort() returns None. sorted() returns the list.
  • Strings are immutable — build a new one, don't assign into one.
  • Read the examples before the prose; they define the edge cases.
  • Get something returning first, then make it correct. A working ugly answer beats an elegant unfinished one.