S
Saurav Danej
90-Day AI/ML LinkedIn Content System
← All days
4
Day 4 of 90Python

Lists & dicts — the workhorses of every Python program

POST 1 of 5 MorningPythonConcept

Lists are arrays. Dicts are hash maps. That's it.

If I had to teach a beginner exactly one thing about Python data structures, it would be this — list and dict do 95% of the work, and choosing the right one is mostly about knowing what you'll do with it.

A Python list is a dynamic array. Same shape as a Java ArrayList or a C++ vector. Memory-contiguous, doubles capacity when full, indexed by integer position. Append is O(1) amortised, index is O(1), but searching for a value is O(n) because the list has no idea what it contains.

A Python dict is a hash table. Same shape as a Java HashMap or a C++ unordered_map. Indexed by any hashable key. Set, get, and 'in' tests are all O(1) on average. Iteration order matches insertion order since Python 3.7 (this is now part of the language spec, not a CPython implementation detail).

Those two complexities — O(1) for dict lookup, O(n) for list search — drive about 95% of structure-choice decisions in real Python code. If you're going to look things up by an identifier, dict. If you're going to iterate everything in order, list. If you only care about membership, set. If the value won't change, tuple.

The other 5% of cases reach for collections.deque, heapq, defaultdict, Counter, OrderedDict. We cover those during DSA week.

A pattern I see in real-world code over and over: parse data into a list, build a dict to look things up fast, iterate to do work. If you're comfortable with these two, you can ship most of what your job throws at you. Master one, you write Python. Master both, you understand it.
#AI#MachineLearning#Python#100DaysOfCode#BuildInPublic#DataStructures#PythonBasics
POST 2 of 5 MiddayPythonDeep dive

Slicing — the most underused superpower

Most Python beginners learn lst[0] and lst[-1] and stop. They never internalise the full slicing syntax — and as a result, write five-line loops where one slice would do.

The full syntax is lst[start:stop:step]. Every part is optional. Combine the optionals and you get a small DSL for sequence manipulation.

Reverse a list — lst[::-1]. Step is -1, so we walk backwards. Way faster than reversed() + list() and arguably more readable.

Every other element — lst[::2]. Step is 2.

Drop the first element — lst[1:]. Drop the last — lst[:-1]. Drop both — lst[1:-1].

Delete a slice in place — lst[a:b] = []. The list shrinks by (b-a) elements, no new list created.

Replace contents without rebinding — lst[:] = other. The variable still points at the same list object, but its contents are now whatever 'other' contained. Useful when other code holds a reference to your list and you want them to see the change.

String slicing works the same way. 'hello world'[6:] gives 'world'. 'racecar'[::-1] gives 'racecar'. NumPy arrays slice by the same syntax (with multi-dimensional extensions).

Why does this matter? Because every for-loop you replace with a slice is fewer lines, fewer index-off-by-one bugs, and faster code (slicing happens in C). The number of times I've seen new developers write 'for i in range(len(lst)): if i > 0: result.append(lst[i])' when 'result = lst[1:]' would do…

Learn the full syntax once. It pays back forever.
#AI#MachineLearning#Python#100DaysOfCode#BuildInPublic#PythonTricks#Slicing
POST 3 of 5 AfternoonPythonCode

List & dict comprehensions — the loops you don't write

If I could pick one syntax feature to teach beginners and turn them into 'Python developers' overnight, it would be comprehensions. Every Pythonic codebase is full of them.

The basic shape — [expr for x in iterable if cond]. Read it left to right: 'a list of expr, for each x in iterable, where cond is true'. It builds a new list directly, no .append() loop.

Squares of even numbers up to 20 — [x*x for x in range(20) if x % 2 == 0]. One line, intent obvious, and faster than the equivalent for-loop because CPython optimises the bytecode.

Dict comprehensions follow the same shape with curly braces and a key:value expression. {w: i for i, w in enumerate(words)} builds a word-to-index map from a list. Useful for tokenisers, lookup tables, anywhere you transform a sequence into a dict.

Set comprehensions look like dict comprehensions but without the colon. {c.lower() for c in text if c.isalpha()} gives unique lowercase letters. The set deduplicates automatically.

Nested comprehensions exist but use them sparingly. Two levels deep is the limit before readability collapses. If you find yourself writing a triple-nested comprehension, that's a sign to break it up.

When NOT to use them. Comprehensions are for transforms and filters. If your loop body has side effects — writing to a file, printing, mutating a global — write a regular for-loop. The comprehension's purpose is to produce a new collection cleanly. Mixing in side effects is what gives comprehensions a bad name.

Generator expressions, the lazy cousin of list comprehensions, get their own day on Day 11. Same syntax with parentheses instead of brackets. Same speed-up; way less memory.
#AI#MachineLearning#Python#100DaysOfCode#BuildInPublic#Comprehensions#PythonStyle
POST 4 of 5 EveningPythonTip

Three dict moves you probably don't know

Most Python developers learn dicts up to d[k] and d[k] = v and then stop. There are three more dict moves that, once internalised, will cut your data-wrangling code in half. I'm not exaggerating.

First — dict.get(key, default). Returns d[key] if key exists, otherwise the default. No more KeyError, no more 'if key in d' checks. Use this any time you're reading from a dict and aren't 100% sure the key exists. Especially common when parsing API responses where some fields are optional.

Second — collections.defaultdict(list). Auto-creates an empty list (or anything else) the first time you access a missing key. Now d[key].append(x) just works. The classic group-by pattern that used to take five lines becomes two. defaultdict(int) gives you a counter — d[key] += 1 works on every key, even unseen ones. defaultdict(set) gives you unique-per-key. Nest them for matrices.

Third — d1 | d2. The dict-merge operator from Python 3.9. Returns a new dict with both d1 and d2's keys (d2 wins on conflicts). The old way was {**d1, **d2}, which still works. The new way is more readable and slightly faster.

Bonus — dict(zip(keys, values)) builds a dict from two parallel lists. Useful when you have ['name', 'age', 'city'] and ['Saurav', 30, 'Bengaluru'] from a CSV.

Bonus 2 — d.items() lets you iterate keys and values together. for key, value in d.items(): ... Always cleaner than for key in d: value = d[key].

Dicts have more sharp tools than people use. Take an afternoon and explore the docs. The pyhon 'collections' module also has Counter, OrderedDict, ChainMap — useful when the situation calls for it.
#AI#MachineLearning#Python#100DaysOfCode#BuildInPublic#PythonDict#PythonTips
POST 5 of 5 NightPythonRecap

Day 4 — pick the right container, win the day

End of Day 4. Twenty posts in. We're 4.4% of the way through the sprint and Python is starting to feel native, not foreign. That's the goal.

What we covered today.

Morning, the foundation — list and dict. Dynamic array versus hash map. Two structures, two complexity profiles, 95% of the choices you'll ever make. Get this right and your code is fast by default; get it wrong and you'll find yourself optimising loops that shouldn't have been loops.

Midday, slicing as a superpower. The lst[start:stop:step] syntax that most beginners never fully internalise. Reversal, every-other, drop-first, drop-last, in-place delete and replace — all one-liners. Every slice you write is a for-loop you didn't.

Afternoon, comprehensions — the loops you don't write at all. List, dict, and set forms. Faster than for-loops in CPython because the bytecode is optimised. Cleaner than for-loops because the intent is in the expression. The shape becomes muscle memory after about 50 of them.

Evening, three dict moves that compound across every project — .get(k, default), defaultdict, and the | merge operator. Plus dict(zip()) and .items(). Each one of these saves a few lines per use; across a year they save hundreds.

Reflection on pacing. We're four days in and you've already seen: project framing, environment setup, type system, control flow, comprehensions. By the end of week 1, you'll be able to write idiomatic Python from a blank file. By week 2 we go OOP and decorators.

Tomorrow, Day 5, we cover loops and control flow done right. Why range(len(lst)) is a code smell. The for/else clause Python actually has. The walrus operator's two real uses.

See you tomorrow.
#AI#MachineLearning#Python#100DaysOfCode#BuildInPublic#PythonProgress#DailyRecap