Python Basics Crash Course

Python Basics Crash Course

This article serves as a quick refresher or a jumpstart for Python before delving into machine learning concepts. While it is not a comprehensive Python course, it provides a solid foundation and helps you choose the direction to pursue. Let's dive into the key concepts of Python programming!

This course is part of the following article:

We will be using Google Colaboratory Python notebooks to avoid setup and environment delays. The focus of this article is to get you up and running in Machine Learning with Python, and we can do all that we need there. Here is the link below:

============================

Focused Topics:

Important topics in case you want to get deeper into those areas:

Install Python

Lists and list operations:

Strings

Sets

Tuples

Dictionaries

Mutable vs Immutable variables and Pass By Reference vs Value

Object-Oriented Programing (OOP) in Python

File management


Exception Handling in Python

NumPy

Pandas


Network Calls with "requests":

=============================

Variables and Data Types:

Python allows you to assign values to variables and perform operations on them. It supports various data types such as integers, floats, strings, booleans, lists, tuples, and dictionaries.


Numbers

Python supports both integers (int) and float. You can get the type of a number using "type()" as follows:

No alt text provided for this image

Numbers' Operations

Addition, multiplications, Division, Subtraction.

No alt text provided for this image

Exponentiation.?

In Python, the exponentiation operator is `**`. To raise a number to the power of another number, you can use this operator.

For example, to calculate 2 raised to the power of 3, you would write:

```python

result = 2 ** 3

```

In this case, the value of `result` will be 8, as 2 raised to the power of 3 is equal to 8.

No alt text provided for this image

The Modulo Operator

The mod operator, represented by the symbol `%`, is known as the modulo operator in Python. It performs the modulo operation, which calculates the remainder when one number is divided by another.


The modulo operation is useful in various scenarios, such as determining if a number is even or odd, checking divisibility, cycling through a set of values, and more.


Here's how the modulo operator works:


```python

a % b

```


In this expression, `a` and `b` are numbers. The modulo operator divides `a` by `b` and returns the remainder.

No alt text provided for this image


Examples:

- Assigning values to variables:


x = 10

name = "John"

is_student = True


- Numbers and mathematical operations:

# Numbers and mathematical operations:
a = 5


b = 3


addition = a + b
print ("addition = ", addition)


multiplication = a * b
print ("multiplication = ", multiplication)


division = a / b
print ("division = ", division)



modulo = a % b
print ("modulo = ", modulo)        
No alt text provided for this image

- Strings and string operations:


In Python, strings are sequences of characters and they can be manipulated in a variety of ways using built-in methods and operations. Here's a breakdown of some commonly used Python string operations:


1. Concatenation (`+`): You can use the `+` operator to combine two strings together.


```python

greeting = "Hello"

name = "John"

message = greeting + ", " + name?# "Hello, John"

```


2. Repetition (`*`): The `*` operator allows you to repeat a string a specified number of times.


```python


```


3. String Interpolation: There are several ways to format strings in Python to insert variables.



name = "John"

age = 30


# Using f-strings (Python 3.6+)

message = f"My name is {name} and I am {age} years old."


# Using .format() method

message = "My name is {} and I am {} years old.".format(name, age)



4. Length (`len()`): The `len()` function returns the number of characters in a string.



length = len("Hello, World!")?# 13



5. Case Conversion: Python provides string methods to convert strings to lower case or upper case.



s = "Hello, World!"

lower_case = s.lower()?# "hello, world!"

upper_case = s.upper()?# "HELLO, WORLD!"



6. Stripping Whitespace (`strip()`): The `strip()` method removes leading and trailing whitespace from a string.


```python

s = "??Hello, World!??"

stripped = s.strip()?# "Hello, World!"

```


7. Replacing Substrings (`replace()`): The `replace()` method replaces occurrences of a substring within a string.



s = "Hello, Bob!"

new_s = s.replace("Bob", "John")?# "Hello, John!"


??

8. Splitting Strings (`split()`): The `split()` method divides a string into a list of substrings based on a delimiter.



s = "Hello, World!"

words = s.split(" ")?# ['Hello,', 'World!']



These are just a few of the numerous operations and methods available for strings in Python. For a more complete picture, refer to Python's official documentation on string methods.


# Strings and string operations
greeting = "Hello"
print ("greeting = ", greeting)
# greeting =  Hello



name = "Alice"
print ("name = ", name)
# name =  Alice



message = greeting + ", " + name
print ("message = ", message)
# message =  Hello, Alice


length = len(message)
print ("length = ", length)
# length =  12



uppercase = message.upper()
print ("uppercase = ", uppercase)
# uppercase =  HELLO, ALICE



lowercase = message.lower()
print ("lowercase = ", lowercase)
# lowercase =  hello, alice

        
No alt text provided for this image


- Lists and list operations:


# Lists and list operations:
fruits = ['apple', 'banana', 'orange']
print ("fruits = ", fruits)
# fruits =  ['apple', 'banana', 'orange']


first_fruit = fruits[0]
print ("first_fruit = ", first_fruit)
# first_fruit =  apple


fruits.append('pear')
print ("fruits = ", fruits)
# fruits=['apple', 'banana', 'orange', 'pear']

fruits.remove('banana')
print ("fruits = ", fruits)
# fruits =  ['apple', 'orange', 'pear']
        
No alt text provided for this image


- Dictionaries and dictionary operations:

A dictionary in Python is an unordered collection of data values that are used to store data values like a map. Dictionaries are mutable, which means they can be changed. Each item in a dictionary has a key-value pair.



Creating a Dictionary: Dictionaries are defined by enclosing a comma-separated list of key-value pairs in curly braces `{}`.?


```python

my_dict = {'name': 'John', 'age': 27, 'job': 'Engineer'}

```


In this example, 'name', 'age', and 'job' are the keys, and 'John', 27, 'Engineer' are their respective values.


Dictionary Operations:


1. Accessing Items: You can access the items of a dictionary by referring to their key name.



name = my_dict['name']?# 'John'



2. Changing Values: You can change the value of a specific item by referring to its key name.



my_dict['age'] = 30?# change the age to 30



3. Adding Items: Adding an item to the dictionary is done by using a new index key and assigning a value to it.



my_dict['city'] = 'New York'?# adds a new key-value pair

```


4. Removing Items: The `pop()` method removes the item with the specified key name.


```python

my_dict.pop('job')?# removes 'job' from dictionary



5. Looping through a Dictionary: You can loop through a dictionary by using a `for` loop.



for key in my_dict:

?print(key)?# prints all keys in my_dict

?print(my_dict[key])?# prints all values in my_dict



6. Checking if a Key Exists: To determine if a specified key is present in a dictionary, use the `in` keyword.



if "name" in my_dict:

?print("'name' is a key in my_dict")



7. Dictionary Length: To determine how many items (key-value pairs) a dictionary has, use the `len()` function.



print(len(my_dict))



8. Clearing a Dictionary: The `clear()` method empties the dictionary.



my_dict.clear()



9. Copying a Dictionary: The `copy()` method makes a copy of the dictionary.


```python

new_dict = my_dict.copy()

```


The above are some of the most common operations you can perform with Python dictionaries. Python's official documentation offers a comprehensive list of dictionary methods.

# Dictionaries and dictionary operations


person = {'name': 'John', 'age': 25, 'occupation': 'engineer'}
print("person = ", person)
# person =  {'name': 'John', 'age': 25, 'occupation': 'engineer'}


person['age'] = 26
print("person['age'] = ", person['age'])
# person['age'] =  26


occupation = person['occupation']
print("occupation = ", occupation)
# occupation =  engineer        
No alt text provided for this image


2. Control Flow:

Control flow statements allow you to control the execution of your code based on certain conditions. It includes if statements, for loops, while loops, and functions.


Examples:

- If statement:

# If statement:


age = 18


if age >= 18:


  print("You are an adult.")


else:


  print("You are a minor.")



# You are an adult.

        
No alt text provided for this image


- For loop:

# - For loop:


fruits = ['apple', 'banana', 'orange']


for fruit in fruits:


  print(fruit)


 
'''
apple
banana
orange
'''        
No alt text provided for this image


- While loop:

# - While loop:


counter = 0


while counter < 5:


  print(counter)


  counter += 1



'''
0
1
2
3
4
'''        
No alt text provided for this image


- Functions:

# - Functions:


def greet(name):
  print('Hello, ' + name + '!' )


greet('Rany ElHousieny')


# Hello, Rany ElHousieny!        
No alt text provided for this image

The range() Function:

The `range()` function in Python is used to generate a sequence of numbers within a specified range. It is commonly used in for loops to iterate over a sequence of numbers.


The `range()` function takes up to three arguments: `start`, `stop`, and `step`. The `start` argument specifies the starting point of the range (inclusive), the `stop` argument specifies the ending point of the range (exclusive), and the `step` argument specifies the increment between each number in the range (default is 1).


Here are a few examples to illustrate the usage of the `range()` function:


1. Example of generating a sequence of numbers:

```python

for i in range(5):

??print(i)

```

Output:


0

1

2

3

4


In this example, the `range(5)` generates a sequence of numbers from 0 to 4. The for loop iterates over each number in the range and prints it.


2. Example of specifying a start and stop:

```python

for i in range(2, 7):








5

6


In this example, the `range(2, 7)` generates a sequence of numbers from 2 to 6. The for loop iterates over each number in the range and prints it.


3. Example of specifying a start, stop, and step:


for i in range(1, 10, 2):








7

9


In this example, the `range(1, 10, 2)` generates a sequence of odd numbers from 1 to 9. The `step` argument of 2 specifies that the range should increment by 2 between each number. The for loop iterates over each number in the range and prints it.


The `range()` function is a versatile tool for generating sequences of numbers in Python and is commonly used in various programming tasks, such as looping and indexing.

3. Input and Output:

Python provides functions to interact with the user through input and display output.


Examples:

- Input:

# - Input:


def greet(name):
  print('Hello, ' + name + '!' )


name = input ('Enter your name:')
greet(name)


# Hello, Rany ElHousieny!        
No alt text provided for this image
No alt text provided for this image
No alt text provided for this image
No alt text provided for this image


- Output:

# - Output:


name = 'Rany'
print('Hello, ' + name + '!' )



# Hello, Rany!        
No alt text provided for this image


4. Libraries and Modules:

Python has a rich ecosystem of libraries and modules that provide additional functionality. You can import and use these libraries in your programs.

A module in Python is a file that contains a set of functions, classes, and variables that you can include in your application. Think of a module as a code library that provides a collection of related code that can be reused in different programs.


There are several reasons why we use modules in Python:


1. Modularity: Modules allow you to organize your code into logical units, making it easier to understand, maintain, and reuse. Instead of writing all your code in a single file, you can separate it into modules based on functionality.


2. Code Reusability: By defining functions, classes, and variables in a module, you can reuse them in multiple programs without having to rewrite the code. This saves time and effort in developing new applications.


In Python, you can use the `import` statement to include a module in your program. For example, `import math` imports the `math` module, which provides various mathematical functions and values. You can access the functions and variables defined in the `math` module using the dot notation, like `math.pi` to access the value of pi.

# 4. Libraries and Modules:
import math
print(math.pi)


# 3.141592653589793        


You can also use the `import` statement to rename a module for convenience. For example, `import numpy as np` imports the `numpy` module and assigns it the alias `np`. This allows you to use the functions and classes provided by `numpy` by prefixing them with `np`, such as `np.array` to create a NumPy array.


Another way to import from a module is by using the `from` keyword. For example, `from math import pi` imports only the `pi` variable from the `math` module, so you can directly use `pi` without the need to prefix it with `math`.

# 4. Libraries and Modules:
from math import pi


print(pi)


# 3.141592653589793        


Similarly, you can import specific elements from a module using the `from` keyword. In the example `from numpy import array`, only the `array` function from the `numpy` module is imported, allowing you to use `array` directly without referencing `numpy`.


Overall, modules in Python help in organizing and structuring your code, promoting reusability, and making it easier to work with external code libraries or custom code you have created.

5. Scope of Variables in Python

No alt text provided for this image


The scope of a variable determines where the variable can be accessed or referenced in a program. In Python, there are four types of scopes: global scope, local scope, enclosing scope, and built-in scope.


1. Global Scope: Variables declared outside any function or class have global scope. They can be accessed from anywhere within the program. Global variables are usually defined at the beginning of a program and are available to all functions.


2. Local Scope: Variables declared inside a function have local scope. They can only be accessed within that specific function. Local variables are created when the function is called and are destroyed when the function completes its execution. Local variables can have the same name as global variables, but the local variable takes precedence over the global variable within the function.


3. Enclosing Scope: If a function is defined inside another function, the inner function has access to variables in the outer function. These variables belong to the enclosing scope. The inner function can access and modify the variables of the enclosing scope, but not vice versa.


4. Built-in Scope: The built-in scope contains names that are pre-defined in Python. These names include keywords, functions, exceptions, and other attributes. They are always available to use in any Python program.


The order of scope resolution is local, enclosing, global, and then built-in. When a variable is referenced, Python looks for it in the local scope first, then the enclosing scope, global scope, and finally the built-in scope. If the variable is not found in any of these scopes, a NameError is raised.


Understanding the concept of scope is important for variable management and avoiding conflicts between different parts of your program.

Here are some examples:

  1. Global Variables: Global variables are declared outside of functions or in global scope. They can be accessed inside or outside of functions throughout the program.

Example:

x = 10  # This is a global variable

def func():
   print(x)  # We can access the global variable inside this function

func()  # Will print: 10
print(x)  # We can also access the global variable outside the function. Will print: 10
        

2. Local Variables: Local variables are declared inside a function or local scope and they can only be used inside that function.

Example:

def func():
   y = 5  # This is a local variable, it only exists inside this function
   print(y)

func()  # Will print: 5
print(y)  # Will raise a NameError because y is not defined in the global scope
        

3. The?global?Keyword: If you need to modify a global variable from within a function, you can use the?global?keyword.

Example:

x = 10

def func():
   global x  # This tells Python that we want to use the global x, not create a local one
   x = 5  # This changes the global x, not a local one

func()
print(x)  # Will print: 5, because the function changed the global x
        

Without the?global?keyword in the function, Python would create a new local variable?x, and changes to?x?in the function would not affect the global?x.

It's generally better to avoid relying on global variables in your code, because they can lead to confusion and errors, especially in larger programs. If you find you're using them a lot, it might be a sign that you should reorganize your code, perhaps by passing variables as arguments to functions or by using classes.



Python in Production

Python is a dynamically typed language, meaning types are checked during runtime and not before it. While this provides flexibility, it may lead to potential bugs in a production environment due to undefined or unexpected types. Here are several strategies to avoid such issues:


1. **Use Type Annotations**: Python 3.5 introduced optional type hints, where you can "hint" the type of the variables. While Python's interpreter doesn't enforce them, these hints can be checked by third-party tools like Mypy, helping identify potential type errors in your code.


??```python

??def greet(name: str) -> str:

????return 'Hello ' + name

??```

??In the above code, `name` is expected to be of type `str`, and the function is expected to return a `str`.


2. **Use Docstrings**: Detailed documentation strings ("docstrings") for functions can help clarify the intended types of arguments and return values.


??```python

??def add(a, b):

????"""

????Function to add two numbers

????:param a: int: a number

????:param b: int: another number

????:return: int: returns the sum

????"""

????return a + b

??```

??Here, the docstring clearly mentions the expected types of `a` and `b` (both integers), and also mentions the return type.


3. **Implement Unit Testing**: Unit tests involve testing individual portions of your code to ensure they behave as expected. By providing a range of inputs and their expected outputs, you can catch and correct potential bugs before deployment.


4. **Use 'isinstance' Python Built-in Function**: The 'isinstance' function can be used to ensure a variable is a particular type before continuing. This can prevent bugs due to unexpected types.


??```python

??if isinstance(var, expected_type):

????# proceed with specific operation on 'var'

??```

5. **Error Handling**: Write your code to anticipate and gracefully handle error conditions. By using Python's 'try and except' blocks, you can catch exceptions and deal with them, rather than letting your program crash.


??```python

??try:

????# operation that may raise an exception

??except ExceptionType:

????# code to handle the exception

??```


6. **Code Reviews**: Regularly review your code as well as your team's code. This may help identify potential type-related bugs. It's also a chance to establish and adhere to best coding practices.


7. **Use IDEs or Linters**: Tools like PyCharm, pylint, or flake8 can detect potential issues in your code, such as use of an undefined or unexpected type.


Remember that while Python's flexibility allows you to avoid specifying type information, doing so can make your code more predictable and easier to debug, particularly for other developers or for your future self. Establishing good coding practices can greatly reduce the incidence of bugs related to undefined or unexpected types in your Python code.


Google's Python style guide

Google's Python style guide provides a set of rules for Python coding style, including naming conventions. Here's a quick summary of the naming standards:

Here's a summary of Google's Python Naming standards with examples:


1. Module Names: Modules should have short, lowercase names. If needed, you can use underscores to improve readability.?

Example: `my_module.py`


2. Class Names: Class names should follow the UpperCaseCamelCase convention, also known as CapWords or PascalCase.?

Example: `MyClass`


3. Exception Names: Exceptions should be classes and are named like classes. However, if the class is an exception, ensure it ends with `Error`.

Example: `MyCustomError`

In Python, exceptions are errors that occur during the execution of a program. When these errors occur, Python creates an exception object. If not handled, this results in the program stopping and displaying an error message.

Exception names in Python are usually class names. According to Google's Python style guide, these names should adhere to the UpperCaseCamelCase convention or CapWords, and they should typically end with the word "Error". This is a common practice that improves code readability by making it clear that the class is intended to be an exception.

For example, consider a custom exception that you'd raise when there's an error in connection (like a network issue):

```python
class ConnectionError(Exception):
??pass
```

In this example, `ConnectionError` is the exception name. If a connection error occurred in your program, you could raise this exception with the `raise` keyword:

```python
raise ConnectionError("Unable to connect to server")
```

In this context, following the naming convention allows anyone reading your code to recognize `ConnectionError` as an exception.

4. Function Names: Function names should be lowercase, with underscore separating words to enhance readability. This style is often referred to as snake_case.?

Example: `my_function()`


5. Function and Method Arguments: The first argument of an instance method should be `self`, and the first argument of a class method should be `cls`.

Example:

```python

class MyClass:

?def instance_method(self, arg1, arg2):

??pass


?@classmethod

?def class_method(cls, arg1, arg2):

??pass

```


6. Constant Names: Constants, typically declared at a module level, are written in all caps with underscores separating words.

Example: `MY_CONSTANT = 50`


7. Variable Names: Variables should be in lowercase, with words separated by underscores to improve readability.?

Example: `my_variable = 10`


8. Method Names and Instance Variables: Method names and instance variables follow the same convention as function names i.e., snake_case.

Example:?

```python

class MyClass:

?def my_method(self):

??pass

?my_instance_variable = 10

```


9. Non-public Methods and Instance Variables: To indicate a method or an instance variable is intended for internal use (non-public), prefix the name with a single underscore `_`.

Example:?

```python

class MyClass:

?def _my_internal_method(self):

??pass

?_my_internal_variable = 10

```


10. Naming Conventions for Maximum Clarity: Names should be descriptive and meaningful to clearly indicate the purpose of your variables, functions, classes, or modules. Avoid vague names like `tmp` or `v`.

Example:

```python

# Good

student_scores = [89, 90, 88, 92]


# Bad

s = [89, 90, 88, 92]

```

Remember, these guidelines aim to enhance code clarity, maintainability, and consistency in Python programming.

Practice Problems:

Reverse An Array

Reverse a given list of numbers.

Example One

{
"nums": [50, 35, 78, 66, 17]
}        

Output:

[17, 66, 78, 35, 50]        

Example Two

{
"nums": [50, 40, 30, 20]
}        

Output:

[20, 30, 40, 50]        

Notes

  • Modify the input array in-place and return the modified array.

Constraints:

  • 1 <= size of the input array <= 106
  • 0 <= any element of the input array <= 106

------

Solution:

To reverse the given list of numbers, we can use two pointers approach. We will start with one pointer at the beginning of the list and another pointer at the end of the list. We will swap the elements at these two pointers and move the pointers towards each other until they meet in the middle of the list.


Here is the step-by-step algorithm to reverse an array:


1. Initialize two pointers, one at the beginning of the array (start) and another at the end of the array (end).

2. While start < end, do the following:

??a. Swap the elements at start and end pointers.

??b. Move the start pointer one step forward.

??c. Move the end pointer one step backward.

3. Return the modified array.


Here is the implementation of the algorithm in Python:


```python

def reverse_array(nums):

??start = 0

??end = len(nums) - 1

???

??while start < end:

????nums[start], nums[end] = nums[end], nums[start]

????start += 1

????end -= 1

???

??return nums

```


Let's test the implementation with the given examples:


```python

print(reverse_array([50, 35, 78, 66, 17]))

# Output: [17, 66, 78, 35, 50]


print(reverse_array([50, 40, 30, 20]))

# Output: [20, 30, 40, 50]

```


The implemented function takes an array as input, modifies it in-place, and returns the modified array. The time complexity of the algorithm is O(n), where n is the length of the input array.

Let's explore other solutions.

Solution 2

Of course, you can use the reverse method.

def reverse_array(nums):
? ? nums.reverse()
? ? return nums


        

The .reverse() method in Python also runs in O(n) time complexity where n is the length of the list. Using .reverse() method can be faster because Python is optimized for its built-in functions, but in terms of time complexity, both approaches are equivalent. The reverse() function also reverses the elements in place, so it does not use any extra space. It's a matter of preference and style which one to use.

Solution 3

def reverse_array(nums):

??return [x for x in nums[::-1]]        


The previous code does indeed reverse the array, however, it's not being done in-place and it creates a new list which is the reverse of the input list. This means the original list stays unchanged, which might not be desired in scenarios where memory efficiency is a concern. It also doesn't meet the specification given in the problem to modify the input array in-place.


In terms of time complexity, slicing with a negative step like nums[::-1] makes a reversed copy of the list and requires O(n) time, where n is the length of the list. The list comprehension also requires O(n) time, so overall, the time complexity of the provided function is O(n).

Solution 4:

def reverse_array(nums):
? ? 
? ? return nums[::-1]        

The previous code does indeed reverse the array, but similar to the previous example with list comprehension, it's not being done in-place. It creates a new list which is the reverse of the input list. This means that the original list stays unchanged. If memory efficiency is a concern, this method could potentially use twice as much space as necessary.


In terms of time complexity, slicing with a negative step like nums[::-1] makes a reversed copy of the list and requires O(n) time, where n is the length of the list.?


If in-place modification of the input array is not a requirement, this is a perfectly valid and efficient way to reverse a list in Python. However, according to the requirements given in the problem, we are required to modify the input array in-place. For in-place reversal, you should use the two-pointers approach or the built-in reverse() function.

----------------------------

Problem 2

???


Insert An Element At A Specific Position In An Array

Given an array of numbers, insert a given element at the specified position in the array.

Example One

{
"nums": [2, 4, 5, 6, -1],
"element": 3,
"position": 2
}        

Output:

[2, 3, 4, 5, 6]        

Example Two

{
"nums": [70, 60, 50, -1],
"element": 40,
"position": 4
}        

Output:

[70, 60, 50, 40]        

Notes

  • The last element of the array is?-1?indicating a blank position.
  • The given position follows 1-based indexing.
  • Return the modified array.

Constraints:

  • 2 <= size of the input array <= 106
  • 0 <= elements of the array <= 106
  • 1 <= position <= size of the input array

Solution 1

You can use the Python's built-in list method `insert` to insert an element in the list at a specific position. The `insert` method takes two arguments: the index at which the element needs to be inserted, and the element itself.


However, you need to take care of the fact that the given position follows 1-based indexing, while Python's list indices start from 0. Therefore, we need to subtract one from the position before passing it to the `insert` method.


Also, we need to remove the -1 at the end of the list which indicates a blank position. This can be done using Python's `pop` method which removes and returns the last element from the list.


Here is the Python implementation of the problem:


```python

def insert_element(nums, element, position):

??nums.pop()?# Remove the -1 indicating a blank position.

??nums.insert(position - 1, element)?# Subtract one from the position because Python lists use 0-based indexing.

??return nums

```


Let's test the function with the given examples:


```python

print(insert_element([2, 4, 5, 6, -1], 3, 2))

# Output: [2, 3, 4, 5, 6]


print(insert_element([70, 60, 50, -1], 40, 4))

# Output: [70, 60, 50, 40]

```


The time complexity of the `insert` method is O(n) where n is the length of the list. This is because it requires shifting all elements at positions greater or equal to the specified position to make room for the new element. The `pop` method runs in constant time, i.e., O(1). Therefore, the overall time complexity of the function is O(n).

----------

Solution 2:

def insert_element_at_position(nums, element, position):
? ?
? ? if (position <= len(nums)):
? ? ? ? i = len(nums) - 1
? ? ? ? while i >= (position):
? ? ? ? ? ? nums [i] = nums [i-1]
? ? ? ? ? ? i -= 1
? ? ? ? ? ??
? ? ? ? nums[position - 1] = element
? ? ? ? ? ??
? ? return nums

        

This is another valid way to solve the problem without using Python's built-in `insert` method. This is a manual approach where you shift all elements from the last index to the given position one step to the right, thereby making space for the new element. The new element is then placed in the correct position.


Here is the commented Python code for better understanding:




def insert_element_at_position(nums, element, position):

??if (position <= len(nums)):?# Ensure the position is within the list's length

????i = len(nums) - 1?# Start from the last element

????while i >= (position):?# Continue until reaching the position

??????nums[i] = nums[i-1]?# Shift the element one step towards the right

??????i -= 1?# Move one step towards the beginning

????nums[position - 1] = element?# Place the new element in the correct position

??return nums
        



Let's test it with the given examples:


```python

print(insert_element_at_position([2, 4, 5, 6, -1], 3, 2))?# Output: [2, 3, 4, 5, 6]

print(insert_element_at_position([70, 60, 50, -1], 40, 4))?# Output: [70, 60, 50, 40]

```


The time complexity of this function is O(n) where n is the length of the list, as in the worst case we may have to shift all elements in the list one step towards the right. This is same as the function using `insert`. The space complexity is O(1) as we are using a fixed amount of space and modifying the list in-place.


Solution 3

def insert_element_at_position(nums, element, position):
? ? 
? ? l = len(nums)
? ? nums.insert(position-1,element)
? ? return nums[:l]        

This function first inserts the element at the given position. Then, it returns the array up to the length of the original array, effectively dropping the -1 from the end of the array.


Here is a breakdown of the function:


```python

def insert_element_at_position(nums, element, position):

??l = len(nums)?# Get the length of the input array

??nums.insert(position-1,element)?# Insert the element at the specified position

??return nums[:l]?# Return the array up to the length of the input array

```


Let's test this function with the given examples:


```python

print(insert_element_at_position([2, 4, 5, 6, -1], 3, 2))?# Output: [2, 3, 4, 5, 6]

print(insert_element_at_position([70, 60, 50, -1], 40, 4))?# Output: [70, 60, 50, 40]

```


The time complexity of this function is O(n) where n is the length of the list, same as the previous implementations. The space complexity is O(1) as we are modifying the list in-place and not using any additional space.

Solution 4:

Another possible solution could involve manually shifting the elements to the right of the position where the new element needs to be inserted. Here's how you can do it:


```python

def insert_element_at_position(nums, element, position):

??for i in range(len(nums) - 1, position - 1, -1):

????nums[i] = nums[i-1]

??nums[position - 1] = element

??return nums

```


In this function, we start from the end of the array and move each element one step to the right, until we reach the position where the new element is to be placed. Then, we place the new element at that position.


Let's test this function with the given test cases:


```python

print(insert_element_at_position([2, 4, 5, 6, -1], 3, 2))?# Output: [2, 3, 4, 5, 6]

print(insert_element_at_position([70, 60, 50, -1], 40, 4))?# Output: [70, 60, 50, 40]

```


This function is similar to the one provided earlier which manually shifts the elements, and it also has a time complexity of O(n) and a space complexity of O(1).


Conclusion:

This Python crash course serves as a quick refresher or jumpstart before exploring machine learning concepts. It covers the essential elements of Python programming, including variables, data types, control flow, input/output, and working with libraries. By familiarizing yourself with these concepts, you'll be well-prepared to embark on your journey into the exciting world of machine learning using Python.


Appendix

PyCharm


No alt text provided for this image
No alt text provided for this image
No alt text provided for this image


要查看或添加评论,请登录

Rany ElHousieny, PhD???的更多文章

社区洞察

其他会员也浏览了