Skip to content

Commit 0060d10

Browse files
davidagustinclaude
andcommitted
feat(python): add 25 dictionary and data manipulation problems
Add problems covering Counter, defaultdict, ChainMap, OrderedDict, dictionary comprehensions, nested operations, and Python 3.9+ merge operators. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
1 parent cc1717d commit 0060d10

File tree

1 file changed

+354
-0
lines changed

1 file changed

+354
-0
lines changed

lib/problems/python.ts

Lines changed: 354 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3898,6 +3898,360 @@ export const pythonProblems: Problem[] = [
38983898
validPatterns: [/SequenceMatcher\s*\(\s*None\s*,\s*s1\s*,\s*s2\s*\)\.ratio\s*\(\s*\)/],
38993899
tags: ['difflib', 'sequence-matcher', 'similarity', 'advanced'],
39003900
},
3901+
3902+
// ============================================================
3903+
// DICTIONARY AND DATA MANIPULATION - ADVANCED (25 problems)
3904+
// ============================================================
3905+
{
3906+
id: 'py-dict-020',
3907+
category: 'dict',
3908+
difficulty: 'easy',
3909+
title: 'Counter Basic Usage',
3910+
text: 'Count occurrences of each character in the string using Counter',
3911+
setup: 'from collections import Counter\ntext = "abracadabra"',
3912+
setupCode: 'from collections import Counter\ntext = "abracadabra"',
3913+
expected: { a: 5, b: 2, r: 2, c: 1, d: 1 },
3914+
sample: 'dict(Counter(text))',
3915+
hints: ['Counter counts hashable objects', 'It returns a Counter object (subclass of dict)'],
3916+
validPatterns: [/Counter\s*\(\s*text\s*\)/, /dict\s*\(\s*Counter\s*\(\s*text\s*\)\s*\)/],
3917+
tags: ['counter', 'collections'],
3918+
},
3919+
{
3920+
id: 'py-dict-021',
3921+
category: 'dict',
3922+
difficulty: 'easy',
3923+
title: 'Counter Most Common',
3924+
text: 'Find the 2 most common elements in the list using Counter',
3925+
setup: 'from collections import Counter\nnums = [1, 2, 2, 3, 3, 3, 4, 4, 4, 4]',
3926+
setupCode: 'from collections import Counter\nnums = [1, 2, 2, 3, 3, 3, 4, 4, 4, 4]',
3927+
expected: [[4, 4], [3, 3]],
3928+
sample: 'Counter(nums).most_common(2)',
3929+
hints: ['most_common(n) returns the n most frequent elements'],
3930+
validPatterns: [/Counter\s*\(\s*nums\s*\)\.most_common\s*\(\s*2\s*\)/],
3931+
tags: ['counter', 'collections'],
3932+
},
3933+
{
3934+
id: 'py-dict-022',
3935+
category: 'dict',
3936+
difficulty: 'easy',
3937+
title: 'Merge with Pipe Operator',
3938+
text: 'Merge base config with override config using | operator',
3939+
setup: 'base = {"debug": False, "timeout": 30}\noverride = {"debug": True, "retries": 3}',
3940+
setupCode: 'base = {"debug": False, "timeout": 30}\noverride = {"debug": True, "retries": 3}',
3941+
expected: { debug: true, timeout: 30, retries: 3 },
3942+
sample: 'base | override',
3943+
hints: ['Use | to merge dictionaries (Python 3.9+)'],
3944+
validPatterns: [/base\s*\|\s*override/],
3945+
tags: ['merge', 'dict-operator'],
3946+
},
3947+
{
3948+
id: 'py-dict-023',
3949+
category: 'dict',
3950+
difficulty: 'easy',
3951+
title: 'Dictionary from Two Lists',
3952+
text: 'Create a dictionary pairing names with ages',
3953+
setup: 'names = ["Alice", "Bob", "Charlie"]\nages = [25, 30, 35]',
3954+
setupCode: 'names = ["Alice", "Bob", "Charlie"]\nages = [25, 30, 35]',
3955+
expected: { Alice: 25, Bob: 30, Charlie: 35 },
3956+
sample: 'dict(zip(names, ages))',
3957+
hints: ['Use zip() to pair corresponding elements'],
3958+
validPatterns: [/dict\s*\(\s*zip\s*\(\s*names\s*,\s*ages\s*\)\s*\)/],
3959+
tags: ['dict-comprehension', 'zip'],
3960+
},
3961+
{
3962+
id: 'py-dict-024',
3963+
category: 'dict',
3964+
difficulty: 'easy',
3965+
title: 'Check Key Existence',
3966+
text: 'Check if "email" key exists in the dictionary',
3967+
setup: 'user = {"name": "Alice", "age": 30}',
3968+
setupCode: 'user = {"name": "Alice", "age": 30}',
3969+
expected: false,
3970+
sample: '"email" in user',
3971+
hints: ['Use the "in" operator to check key existence'],
3972+
validPatterns: [/["']email["']\s+in\s+user/],
3973+
tags: ['membership', 'dict-method'],
3974+
},
3975+
{
3976+
id: 'py-dict-025',
3977+
category: 'dict',
3978+
difficulty: 'easy',
3979+
title: 'Clear Dictionary',
3980+
text: 'Remove all items from the dictionary and return its length',
3981+
setup: 'data = {"a": 1, "b": 2, "c": 3}\ndata.clear()',
3982+
setupCode: 'data = {"a": 1, "b": 2, "c": 3}\ndata.clear()',
3983+
expected: 0,
3984+
sample: 'len(data)',
3985+
hints: ['clear() removes all items in-place'],
3986+
validPatterns: [/len\s*\(\s*data\s*\)/],
3987+
tags: ['clear', 'dict-method'],
3988+
},
3989+
{
3990+
id: 'py-dict-026',
3991+
category: 'dict',
3992+
difficulty: 'easy',
3993+
title: 'Enumerate to Index Map',
3994+
text: 'Create a dictionary mapping index to fruit using enumerate',
3995+
setup: 'fruits = ["apple", "banana", "cherry"]',
3996+
setupCode: 'fruits = ["apple", "banana", "cherry"]',
3997+
expected: { 0: 'apple', 1: 'banana', 2: 'cherry' },
3998+
sample: 'dict(enumerate(fruits))',
3999+
hints: ['enumerate() returns index-value pairs'],
4000+
validPatterns: [/dict\s*\(\s*enumerate\s*\(\s*fruits\s*\)\s*\)/],
4001+
tags: ['dict-comprehension', 'enumerate'],
4002+
},
4003+
{
4004+
id: 'py-dict-027',
4005+
category: 'dict',
4006+
difficulty: 'easy',
4007+
title: 'Pop with Default',
4008+
text: 'Remove and return "status" key with default "unknown" if not found',
4009+
setup: 'data = {"name": "test", "value": 42}',
4010+
setupCode: 'data = {"name": "test", "value": 42}',
4011+
expected: 'unknown',
4012+
sample: 'data.pop("status", "unknown")',
4013+
hints: ['pop() can take a default value as second argument'],
4014+
validPatterns: [/data\.pop\s*\(\s*["']status["']\s*,\s*["']unknown["']\s*\)/],
4015+
tags: ['pop', 'dict-method'],
4016+
},
4017+
{
4018+
id: 'py-dict-028',
4019+
category: 'dict',
4020+
difficulty: 'medium',
4021+
title: 'defaultdict with List',
4022+
text: 'Group names by their first letter using defaultdict(list)',
4023+
setup: 'from collections import defaultdict\nnames = ["Alice", "Bob", "Anna", "Charlie", "Amy"]\nresult = defaultdict(list)\nfor name in names:\n result[name[0]].append(name)',
4024+
setupCode: 'from collections import defaultdict\nnames = ["Alice", "Bob", "Anna", "Charlie", "Amy"]\nresult = defaultdict(list)\nfor name in names:\n result[name[0]].append(name)',
4025+
expected: { A: ['Alice', 'Anna', 'Amy'], B: ['Bob'], C: ['Charlie'] },
4026+
sample: 'dict(result)',
4027+
hints: ['defaultdict(list) auto-creates empty lists'],
4028+
validPatterns: [/dict\s*\(\s*result\s*\)/],
4029+
tags: ['defaultdict', 'collections', 'grouping'],
4030+
},
4031+
{
4032+
id: 'py-dict-029',
4033+
category: 'dict',
4034+
difficulty: 'medium',
4035+
title: 'defaultdict with Int',
4036+
text: 'Count word occurrences using defaultdict(int)',
4037+
setup: 'from collections import defaultdict\nwords = ["a", "b", "a", "c", "b", "a"]\ncounts = defaultdict(int)\nfor w in words:\n counts[w] += 1',
4038+
setupCode: 'from collections import defaultdict\nwords = ["a", "b", "a", "c", "b", "a"]\ncounts = defaultdict(int)\nfor w in words:\n counts[w] += 1',
4039+
expected: { a: 3, b: 2, c: 1 },
4040+
sample: 'dict(counts)',
4041+
hints: ['defaultdict(int) initializes missing keys to 0'],
4042+
validPatterns: [/dict\s*\(\s*counts\s*\)/],
4043+
tags: ['defaultdict', 'collections', 'counting'],
4044+
},
4045+
{
4046+
id: 'py-dict-030',
4047+
category: 'dict',
4048+
difficulty: 'medium',
4049+
title: 'Nested Dictionary Access',
4050+
text: 'Safely get a nested value with get() chaining',
4051+
setup: 'data = {"user": {"profile": {"name": "Alice"}}}',
4052+
setupCode: 'data = {"user": {"profile": {"name": "Alice"}}}',
4053+
expected: 'Alice',
4054+
sample: 'data.get("user", {}).get("profile", {}).get("name", "Unknown")',
4055+
hints: ['Chain get() calls with empty dict defaults'],
4056+
validPatterns: [/data\.get\s*\(.*\)\.get\s*\(.*\)\.get\s*\(/],
4057+
tags: ['nested', 'safe-access'],
4058+
},
4059+
{
4060+
id: 'py-dict-031',
4061+
category: 'dict',
4062+
difficulty: 'medium',
4063+
title: 'Update Nested Dictionary',
4064+
text: 'Update the nested name field to "Bob"',
4065+
setup: 'data = {"user": {"profile": {"name": "Alice", "age": 30}}}',
4066+
setupCode: 'data = {"user": {"profile": {"name": "Alice", "age": 30}}}',
4067+
expected: { user: { profile: { name: 'Bob', age: 30 } } },
4068+
sample: 'data["user"]["profile"]["name"] = "Bob"; data',
4069+
hints: ['Access nested keys with chained brackets'],
4070+
validPatterns: [/data\s*\[.*\]\s*\[.*\]\s*\[.*\]\s*=\s*["']Bob["']/],
4071+
tags: ['nested', 'update'],
4072+
},
4073+
{
4074+
id: 'py-dict-032',
4075+
category: 'dict',
4076+
difficulty: 'medium',
4077+
title: 'Counter Arithmetic',
4078+
text: 'Subtract inventory sold from inventory using Counter subtraction',
4079+
setup: 'from collections import Counter\ninventory = Counter({"apple": 10, "banana": 5, "cherry": 3})\nsold = Counter({"apple": 3, "banana": 2})',
4080+
setupCode: 'from collections import Counter\ninventory = Counter({"apple": 10, "banana": 5, "cherry": 3})\nsold = Counter({"apple": 3, "banana": 2})',
4081+
expected: { apple: 7, banana: 3, cherry: 3 },
4082+
sample: 'dict(inventory - sold)',
4083+
hints: ['Counter supports arithmetic operations'],
4084+
validPatterns: [/inventory\s*-\s*sold/],
4085+
tags: ['counter', 'collections', 'arithmetic'],
4086+
},
4087+
{
4088+
id: 'py-dict-033',
4089+
category: 'dict',
4090+
difficulty: 'medium',
4091+
title: 'ChainMap for Config Layers',
4092+
text: 'Create a layered config using ChainMap (user overrides defaults)',
4093+
setup: 'from collections import ChainMap\ndefaults = {"color": "blue", "size": "medium"}\nuser_prefs = {"color": "red"}',
4094+
setupCode: 'from collections import ChainMap\ndefaults = {"color": "blue", "size": "medium"}\nuser_prefs = {"color": "red"}',
4095+
expected: { color: 'red', size: 'medium' },
4096+
sample: 'dict(ChainMap(user_prefs, defaults))',
4097+
hints: ['ChainMap searches maps in order'],
4098+
validPatterns: [/ChainMap\s*\(\s*user_prefs\s*,\s*defaults\s*\)/],
4099+
tags: ['chainmap', 'collections', 'config'],
4100+
},
4101+
{
4102+
id: 'py-dict-034',
4103+
category: 'dict',
4104+
difficulty: 'medium',
4105+
title: 'Dict Comprehension with Conditional Value',
4106+
text: 'Create a dict with "pass" or "fail" based on score >= 60',
4107+
setup: 'scores = {"Alice": 85, "Bob": 55, "Charlie": 72, "Diana": 45}',
4108+
setupCode: 'scores = {"Alice": 85, "Bob": 55, "Charlie": 72, "Diana": 45}',
4109+
expected: { Alice: 'pass', Bob: 'fail', Charlie: 'pass', Diana: 'fail' },
4110+
sample: '{k: ("pass" if v >= 60 else "fail") for k, v in scores.items()}',
4111+
hints: ['Use ternary expression in dict comprehension'],
4112+
validPatterns: [/\{.*["']pass["'].*if.*else.*["']fail["'].*for.*in\s+scores\.items\s*\(\s*\)\s*\}/],
4113+
tags: ['dict-comprehension', 'conditional'],
4114+
},
4115+
{
4116+
id: 'py-dict-035',
4117+
category: 'dict',
4118+
difficulty: 'medium',
4119+
title: 'In-Place Update with |=',
4120+
text: 'Update the config dict in-place with new settings using |=',
4121+
setup: 'config = {"debug": False, "timeout": 30}\nnew_settings = {"timeout": 60, "retries": 3}',
4122+
setupCode: 'config = {"debug": False, "timeout": 30}\nnew_settings = {"timeout": 60, "retries": 3}',
4123+
expected: { debug: false, timeout: 60, retries: 3 },
4124+
sample: 'config |= new_settings; config',
4125+
hints: ['Use |= for in-place dictionary merge (Python 3.9+)'],
4126+
validPatterns: [/config\s*\|=\s*new_settings/],
4127+
tags: ['merge', 'dict-operator', 'in-place'],
4128+
},
4129+
{
4130+
id: 'py-dict-036',
4131+
category: 'dict',
4132+
difficulty: 'medium',
4133+
title: 'Flatten Nested Dict Values',
4134+
text: 'Extract all leaf values from nested dict into a flat list',
4135+
setup: 'nested = {"a": {"b": 1, "c": 2}, "d": {"e": 3}}',
4136+
setupCode: 'nested = {"a": {"b": 1, "c": 2}, "d": {"e": 3}}',
4137+
expected: [1, 2, 3],
4138+
sample: '[v for inner in nested.values() for v in inner.values()]',
4139+
hints: ['Use nested comprehension to flatten'],
4140+
validPatterns: [/\[.*for.*in\s+nested\.values\s*\(\s*\)\s+for.*in.*\.values\s*\(\s*\)\s*\]/],
4141+
tags: ['nested', 'flatten', 'comprehension'],
4142+
},
4143+
{
4144+
id: 'py-dict-037',
4145+
category: 'dict',
4146+
difficulty: 'medium',
4147+
title: 'Counter Total Count',
4148+
text: 'Get the total count of all items in the Counter',
4149+
setup: 'from collections import Counter\ncounts = Counter({"apple": 5, "banana": 3, "cherry": 2})',
4150+
setupCode: 'from collections import Counter\ncounts = Counter({"apple": 5, "banana": 3, "cherry": 2})',
4151+
expected: 10,
4152+
sample: 'counts.total()',
4153+
hints: ['Counter has a total() method (Python 3.10+)'],
4154+
validPatterns: [/counts\.total\s*\(\s*\)/, /sum\s*\(\s*counts\.values\s*\(\s*\)\s*\)/],
4155+
tags: ['counter', 'collections'],
4156+
},
4157+
{
4158+
id: 'py-dict-038',
4159+
category: 'dict',
4160+
difficulty: 'medium',
4161+
title: 'Sort Dictionary by Value',
4162+
text: 'Sort the dictionary by values in descending order',
4163+
setup: 'scores = {"Alice": 85, "Bob": 92, "Charlie": 78, "Diana": 95}',
4164+
setupCode: 'scores = {"Alice": 85, "Bob": 92, "Charlie": 78, "Diana": 95}',
4165+
expected: { Diana: 95, Bob: 92, Alice: 85, Charlie: 78 },
4166+
sample: 'dict(sorted(scores.items(), key=lambda x: x[1], reverse=True))',
4167+
hints: ['Use sorted() with a key function'],
4168+
validPatterns: [/dict\s*\(\s*sorted\s*\(\s*scores\.items\s*\(\s*\).*reverse\s*=\s*True/],
4169+
tags: ['sorting', 'dict-method'],
4170+
},
4171+
{
4172+
id: 'py-dict-039',
4173+
category: 'dict',
4174+
difficulty: 'medium',
4175+
title: 'OrderedDict Move to End',
4176+
text: 'Move the "b" key to the end of the OrderedDict',
4177+
setup: 'from collections import OrderedDict\nod = OrderedDict([("a", 1), ("b", 2), ("c", 3)])\nod.move_to_end("b")',
4178+
setupCode: 'from collections import OrderedDict\nod = OrderedDict([("a", 1), ("b", 2), ("c", 3)])\nod.move_to_end("b")',
4179+
expected: { a: 1, c: 3, b: 2 },
4180+
sample: 'dict(od)',
4181+
hints: ['OrderedDict has move_to_end() method'],
4182+
validPatterns: [/dict\s*\(\s*od\s*\)/],
4183+
tags: ['ordereddict', 'collections'],
4184+
},
4185+
{
4186+
id: 'py-dict-040',
4187+
category: 'dict',
4188+
difficulty: 'hard',
4189+
title: 'Deep Merge Dictionaries',
4190+
text: 'Merge nested dictionaries recursively (nested values should merge, not replace)',
4191+
setup: 'def deep_merge(d1, d2):\n result = d1.copy()\n for k, v in d2.items():\n if k in result and isinstance(result[k], dict) and isinstance(v, dict):\n result[k] = deep_merge(result[k], v)\n else:\n result[k] = v\n return result\nbase = {"a": {"x": 1, "y": 2}, "b": 3}\nupdate = {"a": {"y": 20, "z": 30}, "c": 4}',
4192+
setupCode: 'def deep_merge(d1, d2):\n result = d1.copy()\n for k, v in d2.items():\n if k in result and isinstance(result[k], dict) and isinstance(v, dict):\n result[k] = deep_merge(result[k], v)\n else:\n result[k] = v\n return result\nbase = {"a": {"x": 1, "y": 2}, "b": 3}\nupdate = {"a": {"y": 20, "z": 30}, "c": 4}',
4193+
expected: { a: { x: 1, y: 20, z: 30 }, b: 3, c: 4 },
4194+
sample: 'deep_merge(base, update)',
4195+
hints: ['Recursively merge when both values are dicts'],
4196+
validPatterns: [/deep_merge\s*\(\s*base\s*,\s*update\s*\)/],
4197+
tags: ['nested', 'merge', 'recursive'],
4198+
},
4199+
{
4200+
id: 'py-dict-041',
4201+
category: 'dict',
4202+
difficulty: 'hard',
4203+
title: 'Group and Aggregate Sales',
4204+
text: 'Group sales by product and sum the amounts',
4205+
setup: 'from collections import defaultdict\nsales = [{"product": "A", "amount": 100}, {"product": "B", "amount": 200}, {"product": "A", "amount": 150}, {"product": "B", "amount": 50}]\nresult = defaultdict(int)\nfor s in sales:\n result[s["product"]] += s["amount"]',
4206+
setupCode: 'from collections import defaultdict\nsales = [{"product": "A", "amount": 100}, {"product": "B", "amount": 200}, {"product": "A", "amount": 150}, {"product": "B", "amount": 50}]\nresult = defaultdict(int)\nfor s in sales:\n result[s["product"]] += s["amount"]',
4207+
expected: { A: 250, B: 250 },
4208+
sample: 'dict(result)',
4209+
hints: ['Use defaultdict(int) for summing'],
4210+
validPatterns: [/dict\s*\(\s*result\s*\)/],
4211+
tags: ['defaultdict', 'grouping', 'aggregation'],
4212+
},
4213+
{
4214+
id: 'py-dict-042',
4215+
category: 'dict',
4216+
difficulty: 'hard',
4217+
title: 'Transform JSON-like Data',
4218+
text: 'Extract usernames from nested user data into a list',
4219+
setup: 'data = {"users": [{"id": 1, "profile": {"username": "alice"}}, {"id": 2, "profile": {"username": "bob"}}, {"id": 3, "profile": {"username": "charlie"}}]}',
4220+
setupCode: 'data = {"users": [{"id": 1, "profile": {"username": "alice"}}, {"id": 2, "profile": {"username": "bob"}}, {"id": 3, "profile": {"username": "charlie"}}]}',
4221+
expected: ['alice', 'bob', 'charlie'],
4222+
sample: '[u["profile"]["username"] for u in data["users"]]',
4223+
hints: ['Access nested structure with bracket notation'],
4224+
validPatterns: [/\[.*\[.*profile.*\].*\[.*username.*\].*for.*in\s+data\s*\[.*users.*\]\s*\]/],
4225+
tags: ['json', 'nested', 'transform'],
4226+
},
4227+
{
4228+
id: 'py-dict-043',
4229+
category: 'dict',
4230+
difficulty: 'hard',
4231+
title: 'Counter Elements Expansion',
4232+
text: 'Expand Counter back to list of individual elements',
4233+
setup: 'from collections import Counter\ncounts = Counter({"a": 3, "b": 2, "c": 1})',
4234+
setupCode: 'from collections import Counter\ncounts = Counter({"a": 3, "b": 2, "c": 1})',
4235+
expected: ['a', 'a', 'a', 'b', 'b', 'c'],
4236+
sample: 'list(counts.elements())',
4237+
hints: ['Counter has an elements() method'],
4238+
validPatterns: [/list\s*\(\s*counts\.elements\s*\(\s*\)\s*\)/],
4239+
tags: ['counter', 'collections', 'expansion'],
4240+
},
4241+
{
4242+
id: 'py-dict-044',
4243+
category: 'dict',
4244+
difficulty: 'hard',
4245+
title: 'Pivot Data Structure',
4246+
text: 'Pivot list of dicts to dict of lists by key',
4247+
setup: 'records = [{"name": "Alice", "score": 85}, {"name": "Bob", "score": 90}, {"name": "Charlie", "score": 78}]',
4248+
setupCode: 'records = [{"name": "Alice", "score": 85}, {"name": "Bob", "score": 90}, {"name": "Charlie", "score": 78}]',
4249+
expected: { name: ['Alice', 'Bob', 'Charlie'], score: [85, 90, 78] },
4250+
sample: '{k: [r[k] for r in records] for k in records[0].keys()}',
4251+
hints: ['Get keys from first record'],
4252+
validPatterns: [/\{.*:\s*\[.*for.*in\s+records\s*\].*for.*in\s+records\s*\[\s*0\s*\]/],
4253+
tags: ['pivot', 'transform', 'comprehension'],
4254+
},
39014255
];
39024256

39034257
export default pythonProblems;

0 commit comments

Comments
 (0)