we can concatenate two tubles using ‘+’ symbol See below example
tuple_odd = (1, 3 , 5)
tuple_even = (2, 4, 6)
tuple_int = tuple_odd + tuple_even
print( tuple_int ) # (1, 3, 5, 2, 4, 6)
Tutorialshore
Python interview questions for beginners
we can concatenate two tubles using ‘+’ symbol See below example
tuple_odd = (1, 3 , 5)
tuple_even = (2, 4, 6)
tuple_int = tuple_odd + tuple_even
print( tuple_int ) # (1, 3, 5, 2, 4, 6)
Finding duplicates in a list can be approached in several ways, depending on the requirements and constraints (e.g., time complexity, memory usage). Here are various methods:
This approach uses a dictionary (or a collections.Counter
) to count occurrences of each element.
def find_duplicates(lst):
element_counts = {}
duplicates = []
for item in lst:
if item in element_counts:
element_counts[item] += 1
else:
element_counts[item] = 1
for item, count in element_counts.items():
if count > 1:
duplicates.append(item)
return duplicates
# Example usage
lst = [1, 2, 3, 2, 4, 5, 1, 6, 1]
print(find_duplicates(lst)) # Output: [1, 2]
Time Complexity: O(n)O(n)
Space Complexity: O(n)O(n) (for the dictionary)
collections.Counter
A cleaner way to count occurrences is to use collections.Counter
.
from collections import Counter
def find_duplicates(lst):
counts = Counter(lst)
return [item for item, count in counts.items() if count > 1]
# Example usage
lst = [1, 2, 3, 2, 4, 5, 1, 6, 1]
print(find_duplicates(lst)) # Output: [1, 2]
Time Complexity: O(n)O(n)
Space Complexity: O(n)O(n)
This approach uses a set to track seen elements and another set to store duplicates.
def find_duplicates(lst):
seen = set()
duplicates = set()
for item in lst:
if item in seen:
duplicates.add(item)
else:
seen.add(item)
return list(duplicates)
# Example usage
lst = [1, 2, 3, 2, 4, 5, 1, 6, 1]
print(find_duplicates(lst)) # Output: [1, 2]
Time Complexity: O(n)O(n)
Space Complexity: O(n)O(n) (for the sets)
This approach first sorts the list, then checks adjacent elements for duplicates.
def find_duplicates(lst):
lst.sort() # Sort the list (in-place)
duplicates = []
for i in range(1, len(lst)):
if lst[i] == lst[i - 1] and lst[i] not in duplicates:
duplicates.append(lst[i])
return duplicates
# Example usage
lst = [1, 2, 3, 2, 4, 5, 1, 6, 1]
print(find_duplicates(lst)) # Output: [1, 2]
Time Complexity: O(nlogn)O(n \log n) (due to sorting)
Space Complexity: O(1)O(1) (in-place sorting)
This naive approach compares each element to every other element in the list.
def find_duplicates(lst):
duplicates = []
for i in range(len(lst)):
for j in range(i + 1, len(lst)):
if lst[i] == lst[j] and lst[i] not in duplicates:
duplicates.append(lst[i])
return duplicates
# Example usage
lst = [1, 2, 3, 2, 4, 5, 1, 6, 1]
print(find_duplicates(lst)) # Output: [1, 2]
Time Complexity: O(n2)O(n^2)
Space Complexity: O(n)O(n) (for the duplicates list)
Method | Time Complexity | Space Complexity | Best For |
---|---|---|---|
Dictionary/Counter | O(n)O(n) | O(n)O(n) | Large lists where speed matters |
collections.Counter | O(n)O(n) | O(n)O(n) | Concise, Pythonic implementations |
Set-Based | O(n)O(n) | O(n)O(n) | Avoiding duplicates during search |
Sorting | O(nlogn)O(n \log n) | O(1)O(1) | Memory constraints or sorted output needed |
Brute Force | O(n2)O(n^2) | O(n)O(n) | Small lists or educational purposes |
For most practical purposes, dictionary-based or set-based approaches are preferred due to their efficiency.
A Python decorator is a way to modify or extend the behavior of a function or method without directly changing its code. It is a special kind of function that takes another function as input, adds some functionality to it, and then returns the modified function.
Decorators are often used for things like logging, authentication, timing, or modifying function outputs.
Using the @decorator_name
syntax, you can easily apply a decorator to a function.
@decorator_name
def function_to_decorate():
pass
The line @decorator_name
is equivalent to writing:
function_to_decorate = decorator_name(function_to_decorate)
Here’s a simple decorator that adds logging:
def log_decorator(func):
def wrapper(*args, **kwargs):
print(f"Calling function: {func.__name__}")
result = func(*args, **kwargs)
print(f"Function {func.__name__} finished.")
return result
return wrapper
You can apply the decorator to a function using the @
syntax:
@log_decorator
def say_hello(name):
print(f"Hello, {name}!")
say_hello("Alice")
Calling function: say_hello
Hello, Alice!
Function say_hello finished.
Here’s a decorator that measures how long a function takes to run:
import time
def timer_decorator(func):
def wrapper(*args, **kwargs):
start_time = time.time()
result = func(*args, **kwargs)
end_time = time.time()
print(f"Function {func.__name__} took {end_time - start_time:.2f} seconds to execute.")
return result
return wrapper
@timer_decorator
def compute_square(numbers):
return [n ** 2 for n in numbers]
compute_square(range(1, 1000000))
If you want your decorator to take arguments, you need to add another level of nesting:
def repeat_decorator(times):
def decorator(func):
def wrapper(*args, **kwargs):
for _ in range(times):
func(*args, **kwargs)
return wrapper
return decorator
@repeat_decorator(times=3)
def greet():
print("Hello!")
greet()
Hello!
Hello!
Hello!
Decorators are an essential feature in Python that can simplify code and add powerful functionality with minimal changes! Let me know if you’d like further clarification or more examples. 😊
The Fibonacci sequence is a series of numbers where each number is the sum of the two preceding ones, starting from 0 and 1. Here are several methods to generate the Fibonacci sequence:
def fibonacci_iterative(n):
sequence = []
a, b = 0, 1
for _ in range(n):
sequence.append(a)
a, b = b, a + b
return sequence
# Example usage
print(fibonacci_iterative(10)) # Output: [0, 1, 1, 2, 3, 5, 8, 13, 21, 34]
def fibonacci_recursive(n):
if n <= 1:
return n
return fibonacci_recursive(n - 1) + fibonacci_recursive(n - 2)
# Generate a sequence
n = 10
sequence = [fibonacci_recursive(i) for i in range(n)]
print(sequence) # Output: [0, 1, 1, 2, 3, 5, 8, 13, 21, 34]
Note: This approach has exponential time complexity (O(2n)O(2^n)) due to repeated calculations.
from functools import lru_cache
@lru_cache(maxsize=None)
def fibonacci_memoized(n):
if n <= 1:
return n
return fibonacci_memoized(n - 1) + fibonacci_memoized(n - 2)
# Generate a sequence
n = 10
sequence = [fibonacci_memoized(i) for i in range(n)]
print(sequence) # Output: [0, 1, 1, 2, 3, 5, 8, 13, 21, 34]
def fibonacci_generator(n):
a, b = 0, 1
for _ in range(n):
yield a
a, b = b, a + b
# Example usage
print(list(fibonacci_generator(10))) # Output: [0, 1, 1, 2, 3, 5, 8, 13, 21, 34]
This method uses matrix exponentiation for a logarithmic time complexity solution.
import numpy as np
def fibonacci_matrix(n):
F = np.matrix([[1, 1], [1, 0]])
result = (F ** (n - 1))[0, 0]
return result
# Generate a sequence
n = 10
sequence = [fibonacci_matrix(i) for i in range(1, n + 1)]
print(sequence) # Output: [1, 1, 2, 3, 5, 8, 13, 21, 34, 55]
The Fibonacci number can also be computed using the golden ratio (ϕ\phi): F(n)=ϕn−(1−ϕ)n5F(n) = \frac{\phi^n – (1 – \phi)^n}{\sqrt{5}}
import math
def fibonacci_formula(n):
phi = (1 + math.sqrt(5)) / 2
return round((phi**n - (-1/phi)**n) / math.sqrt(5))
# Generate a sequence
n = 10
sequence = [fibonacci_formula(i) for i in range(n)]
print(sequence) # Output: [0, 1, 1, 2, 3, 5, 8, 13, 21, 34]