'''
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!
[] [] [1, 2, 3, 4, 5] ['apple', 'banana', 'cherry'] [1, 'MS Dhoni', 7.0, True] [1, [2, 3], 4] <class 'list'> <class 'list'>
# Accessing List Elements
print(numbers[0]) # 1 (first element)
print(numbers[-1]) # 5 (last element)
print(nested[1][1]) # 3
1 5 3
# Modifying a List
numbers[0] = 10 # Change 1 to 10
print(numbers) # [10, 2, 3, 4, 5]
[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)))
append: ['Dhoni', 'Kohli', 'Raina'] clear: [] copy: ['Dhoni', 'Kohli'] count: 3 extend: ['Dhoni', 'Kohli', 'Raina'] index: 1 index after 2: 3 insert: ['Dhoni', 'Jadeja', 'Kohli', 'Raina', 'Kohli'] pop: Kohli ['Dhoni', 'Jadeja', 'Kohli', 'Raina'] remove: ['Dhoni', 'Kohli', 'Raina'] reverse: ['Raina', 'Kohli', 'Dhoni'] sort: [7, 45, 60, 100] sort (descending): [100, 60, 45, 7] sorted: [90, 50, 20] original: [90, 20, 50] sorted (descending): [20, 50, 90] original: [90, 20, 50] reversed: ['Raina', 'Kohli', 'Dhoni']
# 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])}")
Using range() and indexing Index 0: 7 --> <class 'int'> Index 1: Dhoni --> <class 'str'> Index 2: 7.7 --> <class 'float'> Index 3: True --> <class 'bool'> Index 4: None --> <class 'NoneType'> Index 5: (3+14j) --> <class 'complex'> Index 6: ['Ziva', 'CSK'] --> <class 'list'> Index 7: ('IPL', 'MI') --> <class 'tuple'> Index 8: {'Best': 'CSK'} --> <class 'dict'> Index 9: {'RCB', 'MI', 'CSK'} --> <class 'set'>
print("Sequence-based (direct iteration)")
for i in items:
print(f"Item: {i}") # can't access index directly
# but complicated [] notation is simplified.
Sequence-based (direct iteration) Item: 7 Item: Dhoni Item: 7.7 Item: True Item: None Item: (3+14j) Item: ['Ziva', 'CSK'] Item: ('IPL', 'MI') Item: {'Best': 'CSK'} Item: {'RCB', 'MI', 'CSK'}
idx = 0
for i in items:
print(f"Index {idx}: {i} --> {type(i)}")
idx += 1
Index 0: 7 --> <class 'int'> Index 1: Dhoni --> <class 'str'> Index 2: 7.7 --> <class 'float'> Index 3: True --> <class 'bool'> Index 4: None --> <class 'NoneType'> Index 5: (3+14j) --> <class 'complex'> Index 6: ['Ziva', 'CSK'] --> <class 'list'> Index 7: ('IPL', 'MI') --> <class 'tuple'> Index 8: {'Best': 'CSK'} --> <class 'dict'> Index 9: {'RCB', 'MI', 'CSK'} --> <class 'set'>
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)}")
Using enumerate() (index + value) Index 0: 7 --> <class 'set'> Index 1: Dhoni --> <class 'set'> Index 2: 7.7 --> <class 'set'> Index 3: True --> <class 'set'> Index 4: None --> <class 'set'> Index 5: (3+14j) --> <class 'set'> Index 6: ['Ziva', 'CSK'] --> <class 'set'> Index 7: ('IPL', 'MI') --> <class 'set'> Index 8: {'Best': 'CSK'} --> <class 'set'> Index 9: {'RCB', 'MI', 'CSK'} --> <class 'set'>
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}")
Using zip() for combining two lists 7: <class 'int'> Dhoni: <class 'str'> 7.7: <class 'float'> True: <class 'bool'> None: <class 'NoneType'> (3+14j): <class 'complex'> ['Ziva', 'CSK']: <class 'list'> ('IPL', 'MI'): <class 'tuple'> {'Best': 'CSK'}: <class 'dict'> {'RCB', 'MI', 'CSK'}: <class 'set'>
for idx, (val, dtype) in enumerate(zip(items, types)): # complex method enumerate + zip for accessing index as well
print(f"Index {idx}: {val} --> {dtype}")
Index 0: 7 --> <class 'int'> Index 1: Dhoni --> <class 'str'> Index 2: 7.7 --> <class 'float'> Index 3: True --> <class 'bool'> Index 4: None --> <class 'NoneType'> Index 5: (3+14j) --> <class 'complex'> Index 6: ['Ziva', 'CSK'] --> <class 'list'> Index 7: ('IPL', 'MI') --> <class 'tuple'> Index 8: {'Best': 'CSK'} --> <class 'dict'> Index 9: {'RCB', 'MI', 'CSK'} --> <class 'set'>
# 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)
1 a 2 b 3 c 1 a 2 b 3 c
# making the list 1 length to 4
l1.append(7)
for i in range(len(l1)):
print(l1[i], l2[i])
1 a 2 b 3 c
--------------------------------------------------------------------------- IndexError Traceback (most recent call last) <ipython-input-13-fec756fc19f0> in <cell line: 0>() 2 l1.append(7) 3 for i in range(len(l1)): ----> 4 print(l1[i], l2[i]) IndexError: list index out of range
for i, j in zip(l1, l2): # ignores the extra element and no error
print(i, j)
1 a 2 b 3 c
# Incorrect Indexing
l1 = [1,2,3]
for i in l1:
print(l1[i]) # Error if 'i' is not an integer index
2 3
--------------------------------------------------------------------------- IndexError Traceback (most recent call last) <ipython-input-15-204aa3d7bc6d> in <cell line: 0>() 2 l1 = [1,2,3] 3 for i in l1: ----> 4 print(l1[i]) # Error if 'i' is not an integer index IndexError: list index out of range
for i in range(len(l1)): # correct method using range
print(l1[i])
1 2 3
# 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)
--------------------------------------------------------------------------- IndexError Traceback (most recent call last) <ipython-input-17-56b1018a0d47> in <cell line: 0>() 4 5 # Attempting to pop from an empty list ----> 6 item = empty_list.pop() # This will raise an IndexError 7 print(item) IndexError: pop from empty list
# 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.")
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)
--------------------------------------------------------------------------- ValueError Traceback (most recent call last) <ipython-input-19-f12ab3eac305> in <cell line: 0>() 3 4 # Attempting to remove an element not in the list ----> 5 fruits.remove("grape") # This will raise a ValueError because "grape" is not in the list 6 print(fruits) ValueError: list.remove(x): x not in list
# 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.")
grape 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)
--------------------------------------------------------------------------- IndexError Traceback (most recent call last) <ipython-input-21-2f2f892aedc3> in <cell line: 0>() 3 4 # Attempting to delete an invalid index ----> 5 del numbers[10] # This will raise an IndexError because the index 10 is out of range 6 print(numbers) IndexError: list assignment index out of range
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.")
Index 10 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.")
Negative index -7 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)
--------------------------------------------------------------------------- TypeError Traceback (most recent call last) <ipython-input-24-715e2a39ddc8> in <cell line: 0>() 3 4 # Attempting to append a non-iterable object (a string) as a single item ----> 5 numbers.append("4", "5") # This will raise a TypeError because append() accepts only one argument 6 print(numbers) TypeError: list.append() takes exactly one argument (2 given)
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"]]
[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)
[10, 20, 30, 40]
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)
--------------------------------------------------------------------------- TypeError Traceback (most recent call last) <ipython-input-27-62288c7951fb> in <cell line: 0>() 2 3 # Attempting to extend the list with a non-iterable object (an integer) ----> 4 numbers.extend(4) # This will raise a TypeError because extend() expects an iterable (e.g., list, tuple) 5 print(numbers) TypeError: 'int' object is not iterable
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)
[1, 2, 3, 4, 5, 6]
# 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
Original List [1, 2] After append [1, 2, [3, 4]] After extend [1, 2, [3, 4], 5, 6]
# 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))
137634742193856 137634742193856 137634742193856 137634742193728
# 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]
[20, 30, 40]
# Omitting start and stop (Whole list)
# Slicing the entire list
print(items[:]) # Output: [10, 20, 30, 40, 50, 60, 70]
[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]
[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]
[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)
[50, 60, 70] [10, 20, 30, 40]
# 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
[10, 30, 50, 70] [70, 60, 50, 40, 30, 20, 10] [70, 60, 50, 40, 30, 20, 10]
# 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]
[20, 40] [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)
[70, 50, 30]
# Extracting Sublist Using Variables
start, stop, step = 1, 5, 2
print(items[start:stop:step]) # Output: [20, 40]
[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]
[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)
[1, 2, 3, 4] [1, 2, 1, 2, 1, 2]
# 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
3 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
[10, 20, 40]
--------------------------------------------------------------------------- NameError Traceback (most recent call last) <ipython-input-43-9c6d90b1cb04> in <cell line: 0>() 7 # Deleting the entire list 8 del l2 # The list is now deleted. ----> 9 print(l2) # Error because it is no longer available NameError: name 'l2' is not defined
# Using in for Membership Test
l3 = [10, 20, 30]
print(20 in l3) # Output: True
print(50 in l3) # Output: False
True 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)
['h', 'e', 'l', 'l', 'o'] [1, 2, 3]
# 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)
Sum of all elements: 150
# elaborate method
total = 0
for i in numbers:
total += i
print("Sum of all elements:", total)
Sum of all elements: 150
# 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)
Maximum element: 50 Minimum element: 10
# # 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)
Maximum element: 50 Minimum element: 10
# 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)
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10] Even numbers: [2, 4, 6, 8, 10] Odd numbers: [1, 3, 5, 7, 9]