''' In Python, a list is a built-in data structure used to store multiple items in a single variable. Lists are: Ordered (items maintain their position) Mutable (can change elements) Allow duplicates Can hold any data type (integers, strings, other lists, etc.) ''' # Creating a List # Empty list my_list = [] print(my_list) my_list1 = list() # using constructor print(my_list1) # List of numbers numbers = [1, 2, 3, 4, 5] print(numbers) # List of strings fruits = ["apple", "banana", "cherry"] print(fruits) # List with mixed data types mixed = [1, "MS Dhoni", 7.0, True] print(mixed) # Nested list nested = [1, [2, 3], 4] print(nested) print(type(mixed), type(nested)) # all are lists only! # Accessing List Elements print(numbers[0]) # 1 (first element) print(numbers[-1]) # 5 (last element) print(nested[1][1]) # 3 # Modifying a List numbers[0] = 10 # Change 1 to 10 print(numbers) # [10, 2, 3, 4, 5] # List Methods # append(): Adds an item to the end of the list players = ['Dhoni', 'Kohli'] players.append('Raina') print("append:", players) print() # clear(): Removes all items from the list players.clear() print("clear:", players) print() # copy(): Returns a shallow copy of the list players = ['Dhoni', 'Kohli'] team_copy = players.copy() print("copy:", team_copy) print() # count(): Returns the number of times a value appears jerseys = [7, 18, 7, 45, 7] print("count:", jerseys.count(7)) print() # extend(): Adds all elements from another iterable team1 = ['Dhoni'] team2 = ['Kohli', 'Raina'] team1.extend(team2) print("extend:", team1) print() # index(): Returns the index of the first matching value players = ['Dhoni', 'Kohli', 'Raina', 'Kohli'] print("index:", players.index('Kohli')) print("index after 2:", players.index('Kohli', 2)) print() # insert(): Inserts an item at a given index players.insert(1, 'Jadeja') print("insert:", players) print() # pop(): Removes and returns the item at the given index (default last) last_player = players.pop() print("pop:", last_player, players) print() # remove(): Removes the first matching value players.remove('Jadeja') # value based removal; check if the element is present before removal print("remove:", players) print() # reverse(): Reverses the list in-place players.reverse() print("reverse:", players) print() # sort(): Sorts the list in-place (ascending by default) scores = [100, 60, 45, 7] scores.sort() print("sort:", scores) scores.sort(reverse = True) print("sort (descending):", scores) print() # sorted(): Returns a new sorted list without modifying the original unsorted_scores = [90, 20, 50] print("sorted:", sorted(unsorted_scores, reverse = True)) print("original:", unsorted_scores) print("sorted (descending):", sorted(unsorted_scores)) print("original:", unsorted_scores) print() # reversed(): Returns a reversed iterator (not in-place) players = ['Dhoni', 'Kohli', 'Raina'] print("reversed:", list(reversed(players))) # Iterating through list items = [7, "Dhoni", 7.7, True, None, 3+14j, ["Ziva", "CSK"], ("IPL", "MI"), {"Best": "CSK"}, {"CSK", "MI", "RCB"}] print("Using range() and indexing") for i in range(len(items)): print(f"Index {i}: {items[i]} --> {type(items[i])}") print("Sequence-based (direct iteration)") for i in items: print(f"Item: {i}") # can't access index directly # but complicated [] notation is simplified. idx = 0 for i in items: print(f"Index {idx}: {i} --> {type(i)}") idx += 1 print("Using enumerate() (index + value)") for idx, val in enumerate(items): # hybrid mode of type 1 and 2. print(f"Index {idx}: {val} --> {type(i)}") print("Using zip() for combining two lists") # advancement of type 2 types = [] for i in items: types.append(type(i)) for val, dt in zip(items, types): print(f"{val}: {dt}") for idx, (val, dtype) in enumerate(zip(items, types)): # complex method enumerate + zip for accessing index as well print(f"Index {idx}: {val} --> {dtype}") # common errors l1 = [1,2,3] l2 = ["a", "b", "c"] # using range for i in range(len(l1)): # in case of same length print(l1[i], l2[i]) print() # using zip for i, j in zip(l1, l2): print(i, j) # making the list 1 length to 4 l1.append(7) for i in range(len(l1)): print(l1[i], l2[i]) for i, j in zip(l1, l2): # ignores the extra element and no error print(i, j) # Incorrect Indexing l1 = [1,2,3] for i in l1: print(l1[i]) # Error if 'i' is not an integer index for i in range(len(l1)): # correct method using range print(l1[i]) # remove elements ERROR # List with no elements empty_list = [] # Attempting to pop from an empty list item = empty_list.pop() # This will raise an IndexError print(item) # List with no elements empty_list = [] # Check if the list is empty before popping if empty_list: item = empty_list.pop() print("Popped item:", item) else: print("The list is empty, cannot pop.") # List of fruits fruits = ["apple", "banana", "orange"] # Attempting to remove an element not in the list fruits.remove("grape") # This will raise a ValueError because "grape" is not in the list print(fruits) # List of fruits fruits = ["apple", "banana", "orange"] # Check if the item exists before removing rem = "grape" if rem in fruits: fruits.remove(rem) print(f"{rem} removed from the list.") else: print(f"{rem} not found in the list.") # List of numbers numbers = [1, 2, 3, 4, 5] # Attempting to delete an invalid index del numbers[10] # This will raise an IndexError because the index 10 is out of range print(numbers) numbers = [1, 2, 3, 4, 5] # Check if the index is valid before deleting idx = 10 if 0 <= idx < len(numbers): del numbers[idx] print("Item deleted:", numbers) else: print(f"Index {idx} is out of range. Cannot delete.") numbers = [10, 20, 30, 40, 50] # Check if the negative index is within the valid range idx = -7 if -len(numbers) <= idx < 0: del numbers[idx] print("Item deleted:", numbers) else: print(f"Negative index {idx} is out of range. Cannot delete.") # adding elements numbers = [1, 2, 3] # Attempting to append a non-iterable object (a string) as a single item numbers.append("4", "5") # This will raise a TypeError because append() accepts only one argument print(numbers) numbers = [1, 2, 3] # Correctly append a single element numbers.append("4") # Output: [1, 2, 3, "4"] # To append multiple elements, use a list or another method like extend() numbers.append(["5", "6"]) # This will append the entire list as a sublist print(numbers) # Output: [1, 2, 3, "4", ["5", "6"]] numbers = [10, 20, 30] # Attempting to insert an element at an invalid index (larger than the list length) numbers.insert(10, 40) # This will add the element at last print(numbers) numbers = [1, 2, 3] # Attempting to extend the list with a non-iterable object (an integer) numbers.extend(4) # This will raise a TypeError because extend() expects an iterable (e.g., list, tuple) print(numbers) numbers = [1, 2, 3] # Correctly extend the list with an iterable (another list) numbers.extend([4, 5]) # Output: [1, 2, 3, 4, 5] # Attempting to extend with a non-iterable object (like a single integer) # This would raise a TypeError, so we make sure to provide an iterable: numbers.extend([6]) # Output: [1, 2, 3, 4, 5, 6] print(numbers) # Appending vs Extending l = [1, 2] print("Original List",l) l.append([3, 4]) # Result: [1, 2, [3, 4]] print("After append",l) # adds as sublist l.extend([5, 6]) # Result: [1, 2, [3, 4], 5, 6] print("After extend",l) # unpacks the list and adds as individual elements # Confusing copy() with assignment a = [1, 2, 3] b = a # Same reference print(id(a), id(b)) c = a.copy() # Independent copy print(id(a), id(c)) # List Slicing ''' list[start:stop:step] start: The index to start the slice (inclusive). stop: The index to end the slice (exclusive). step: The step between indices. ''' items = [10, 20, 30, 40, 50, 60, 70] # Slicing from index 1 to index 4 (exclusive) print(items[1:4]) # Output: [20, 30, 40] # Omitting start and stop (Whole list) # Slicing the entire list print(items[:]) # Output: [10, 20, 30, 40, 50, 60, 70] # Omitting start (From beginning to index 4) # Start from the beginning and go till index 4 (exclusive) print(items[:4]) # Output: [10, 20, 30, 40] # Omitting stop (From index 2 to the end) # Start from index 2 till the end print(items[2:]) # Output: [30, 40, 50, 60, 70] # Negative Indices (Counting from the end) # Using negative indices print(items[-3:]) # Output: [50, 60, 70] (Last 3 elements) print(items[:-3]) # Output: [10, 20, 30, 40] (All except last 3 elements) # Using Step (Skipping Elements) # Step 2, starting from index 0 print(items[::2]) # Output: [10, 30, 50, 70] (Every 2nd element) # Step -1 (Reversing the list) print(items[::-1]) # Output: [70, 60, 50, 40, 30, 20, 10] (Reversed list) print(items[len(items)-1::-1]) # for this the above line is the shortcut # Using Step with Start and Stop # Start from index 1 to 5 (exclusive) with step 2 print(items[1:5:2]) # Output: [20, 40] # Start from index 0 to 6 (exclusive) with step 3 print(items[0:6:3]) # Output: [10, 40] # Using Step with Negative Indices # Start from the end of the list and skip 2 elements print(items[-1:-6:-2]) # Output: [70, 50, 30] (Start from 70 and step backwards) # Extracting Sublist Using Variables start, stop, step = 1, 5, 2 print(items[start:stop:step]) # Output: [20, 40] # Slicing Nested Lists nested_items = [1, [2, 3, 4], 5, [6, 7, 8], 9] # Slice the sublist [2, 3, 4] print(nested_items[1][1:3]) # Output: [3, 4] # List Concatenation and Repetition # Concatenation list1 = [1, 2] list2 = [3, 4] combined = list1 + list2 # Output: [1, 2, 3, 4] print(combined) # Repetition repeated = list1 * 3 # Output: [1, 2, 1, 2, 1, 2] print(repeated) # Nested Lists & Multi-level Access nested = [1, [2, 3], [4, [5, 6]]] # Accessing the nested list print(nested[1][1]) # Output: 3 print(nested[2][1][0]) # Output: 5 # Using del for Deleting List Elements # Deleting a specific index l2 = [10, 20, 30, 40] del l2[2] # Removes 30, output: [10, 20, 40] print(l2) # Deleting the entire list del l2 # The list is now deleted. print(l2) # Error because it is no longer available # Using in for Membership Test l3 = [10, 20, 30] print(20 in l3) # Output: True print(50 in l3) # Output: False # Using list() to Convert Iterables to Lists # Convert string to list my_str = "hello" my_list = list(my_str) # Output: ['h', 'e', 'l', 'l', 'o'] print(my_list) # Convert tuple to list my_tuple = (1, 2, 3) my_list = list(my_tuple) # Output: [1, 2, 3] print(my_list) # Sum of All Elements in a List # List of numbers numbers = [10, 20, 30, 40, 50] # Calculate the sum total = sum(numbers) print("Sum of all elements:", total) # elaborate method total = 0 for i in numbers: total += i print("Sum of all elements:", total) # Find the Maximum and Minimum Elements in a List numbers = [10, 20, 30, 40, 50] # Find maximum and minimum max_num = max(numbers) min_num = min(numbers) print("Maximum element:", max_num) print("Minimum element:", min_num) # # elaborate method max_num = numbers[0] min_num = numbers[0] for i in numbers: if i > max_num: max_num = i if i < min_num: min_num = i print("Maximum element:", max_num) print("Minimum element:", min_num) # Segregate even and odd numbers from the list numbers = list(range(1,11)) print(numbers) even = [] odd = [] for i in numbers: if i % 2 == 0: even.append(i) else: odd.append(i) print("Even numbers:", even) print("Odd numbers:", odd)