2 Syntax and Control Flow
Control flow statements determine the order in which code is executed, allowing programs to make logical decisions, perform repetitive tasks, and handle errors efficiently. To learn more, consider watching the following video:
There are three main types of control flow statements:
- ✅ Conditional Statements → Enable decision-making in a program (e.g., if, if-else, if-elif-else).
- ✅ Loops → Facilitate repetition of actions (e.g., for, while, with control keywords like break and continue).
- ✅ Error Handling → Ensure smooth program execution by managing unexpected errors (e.g., try-except in Python, tryCatch in R).
2.1 Conditional Statements
Conditional statements let a program execute different code depending on whether a condition is true or false.
- ✅
if
statement → Executes code only if a condition is true. - ✅
if-else
statement → Executes one block if true, another if false. - ✅
if-elif-else
statement → Checks multiple conditions.
2.1.1 Simple Example
Check if a number is positive, negative, or zero.
Python Code
= 10
x
if x > 0:
print("Positive number")
elif x == 0:
print("Zero")
else:
print("Negative number")
Positive number
R Code
<- 10
x
if (x > 0) {
print("Positive number")
else if (x == 0) {
} print("Zero")
else {
} print("Negative number")
}
[1] "Positive number"
2.1.2 Medium Example
Check if a number is even or odd, with an additional condition.
Python Code
try:
= int(input("Enter a number: "))
x
if x % 2 == 0:
print(f"{x} is even.")
if x % 4 == 0:
print(f"{x} is also a multiple of 4.")
else:
print(f"{x} is odd.")
except ValueError:
print("Invalid input! Please enter a valid integer.")
R Code
<- as.integer(readline("Enter a number: "))
x
if (x %% 2 == 0) {
print(paste(x, "is even."))
if (x %% 4 == 0) {
print(paste(x, "is also a multiple of 4."))
}else {
} print(paste(x, "is odd."))
}
2.1.3 Complex Example
Categorizing a person’s age group.
Python Code
= int(input("Enter your age: "))
age
if age < 0:
print("Invalid age")
elif age <= 12:
print("You are a child.")
elif age <= 19:
print("You are a teenager.")
elif age <= 59:
print("You are an adult.")
else:
print("You are a senior.")
R Code
<- as.integer(readline("Enter your age: "))
age
if (age < 0) {
print("Invalid age")
else if (age <= 12) {
} print("You are a child.")
else if (age <= 19) {
} print("You are a teenager.")
else if (age <= 59) {
} print("You are an adult.")
else {
} print("You are a senior.")
}
2.2 Loops
Loops allow programs to repeat actions multiple times.
- ✅ For Loop → Used when the number of iterations is known. The counter is set, the condition is checked, the code executes, then the counter increments until the condition is no longer met.
- ✅ While Loop → Used when looping should continue as long as the condition is true. If the condition remains valid, the code executes and is checked again until the condition becomes false.
- ✅ Break → Stops the loop early, immediately exiting the loop without completing all iterations.
- ✅ Continue → Skips the current iteration without stopping the loop, returning directly to the condition check for the next iteration. The loop stops when the condition is no longer met or a break statement is used. The loop continues if the condition remains true unless a break occurs.
2.2.1 Simple Example
Print numbers from 1 to 5 using a for loop.
Python Code
for i in range(1, 6):
print(i)
1
2
3
4
5
R Code
for (i in 1:5) {
print(i)
}
[1] 1
[1] 2
[1] 3
[1] 4
[1] 5
2.2.2 Medium Example
Using a while loop to print numbers up to a limit.
Python Code
= 1
x while x <= 5:
print(x)
+= 1 x
1
2
3
4
5
R Code
<- 1
x while (x <= 5) {
print(x)
<- x + 1
x }
[1] 1
[1] 2
[1] 3
[1] 4
[1] 5
2.2.3 Complex Example
Using break and continue to modify loop behavior.
Python Code
for i in range(1, 11):
if i == 5:
continue # Skip number 5
if i == 8:
break # Stop when i = 8
print(i)
1
2
3
4
6
7
R Code
for (i in 1:10) {
if (i == 5) {
next # Skip number 5
}if (i == 8) {
break # Stop when i = 8
}print(i)
}
[1] 1
[1] 2
[1] 3
[1] 4
[1] 6
[1] 7
2.3 Error Handling
Error handling allows a program to recover from unexpected issues rather than terminating abruptly.
- ✅ try-except (Python) → Captures errors and ensures the program continues running.
- ✅ tryCatch (R) → Provides similar functionality in R, allowing controlled error management.
2.3.1 Simple Example
Handling incorrect date formats during user input
Python Code
from datetime import datetime
try:
= input("Enter date (YYYY-MM-DD): ") # Input may have wrong format
date_str = datetime.strptime(date_str, "%Y-%m-%d")
date_obj print(f"Entered date: {date_obj}")
except ValueError:
print("Error: Date format must be YYYY-MM-DD!")
R Code
<- function() {
safe_date <- readline("Enter date (YYYY-MM-DD): ")
date_str tryCatch({
<- as.Date(date_str, format="%Y-%m-%d")
date_obj if (is.na(date_obj)) stop("Incorrect date format!")
print(paste("Entered date:", date_obj))
error = function(e) {
}, print(paste("Error:", e$message))
})
}
safe_date()
Enter date (YYYY-MM-DD):
[1] "Error: Incorrect date format!"
2.3.2 Medium Example
Handling missing values and invalid dates in datasets.
Python Code
# inport library
import pandas as pd
# dataset example (this is dictionary type)
= {"event": ["A", "B", "C"], "date": ["2024-01-15", "2024-15-10", None]}
data = pd.DataFrame(data)
df
# error handaling program
try:
"date"] = pd.to_datetime(df["date"], errors="coerce") # dates to NaT
df[=["date"], inplace=True) # Remove rows with invalid dates
df.dropna(subsetprint(df)
except Exception as e:
print(f"Error processing dates: {e}")
R Code
library(dplyr)
library(lubridate)
# dataset example (this is dictionary type)
<- data.frame(event = c("A", "B", "C"),
data date = c("2024-01-15", "2024-15-10", NA))
# error handaling program
<- function(df) {
safe_process_dates tryCatch({
<- df %>%
df mutate(date = ymd(date)) %>% # Convert dates
filter(!is.na(date)) # Remove invalid dates
print(df)
error = function(e) {
}, print(paste("Error processing dates:", e$message))
})
}
safe_process_dates(data)
2.3.3 Complex Example
This Python code replicates the R functionality while improving date handling.
Python Code
import pandas as pd
from dateutil import parser
import warnings
# Example dataset with various incorrect date formats
= pd.DataFrame({
data "event": ["A", "B", "C", "D", "E"],
"date": ["2024-01-15", "2024-15-10", None, "15-03-2024", "2024/04/05"]
})
def safe_process_dates(df):
def parse_date(date_str):
try:
return parser.parse(date_str, dayfirst=True).strftime("%d-%m-%Y")
except (ValueError, TypeError):
return None
# Apply date parsing
"parsed_date"] = df["date"].apply(parse_date)
df[
# Find invalid dates
= df[df["parsed_date"].isna()]["date"].dropna().tolist()
invalid_dates
if invalid_dates:
f"Some dates are invalid: {', '.join(invalid_dates)}")
warnings.warn(
# Filter out invalid dates
= df.dropna(subset=["parsed_date"])
df
print(df)
safe_process_dates(data)
event date parsed_date
0 A 2024-01-15 15-01-2024
1 B 2024-15-10 15-10-2024
3 D 15-03-2024 15-03-2024
4 E 2024/04/05 04-05-2024
R Code
library(dplyr)
library(lubridate)
# Example dataset with various incorrect date formats
<- data.frame(event = c("A", "B", "C", "D", "E"),
data date = c("2024-01-15", "2024-15-10", NA,
"15-03-2024", "2024/04/05"))
# Function to handle errors in date conversion
<- function(df) {
safe_process_dates tryCatch({
<- df %>%
df mutate(
parsed_date = parse_date_time(date,
orders = c("ymd", "dmy", "mdy", "Y/m/d"),
quiet = TRUE)
%>%
) filter(!is.na(parsed_date)) %>% # Remove dates that failed to convert
mutate(formatted_date = format(parsed_date, "%d-%m-%Y")) # Reformat dates
# Check if there are any invalid dates
<- df$date[is.na(df$parsed_date)]
invalid_dates if (length(invalid_dates) > 0) {
warning("Some dates are invalid: ", paste(invalid_dates, collapse = ", "))
}
print(df)
error = function(e) {
}, print(paste("Error processing dates:", e$message))
})
}
safe_process_dates(data)
event date parsed_date formatted_date
1 A 2024-01-15 2024-01-15 15-01-2024
2 D 15-03-2024 2024-03-15 15-03-2024
3 E 2024/04/05 2024-04-05 05-04-2024
Explanation:
- ✅
dateutil.parser.parse()
is used for flexible date recognition. - ✅ Handles multiple date formats including
YYYY-MM-DD
,DD-MM-YYYY
,YYYY/MM/DD
, etc. - ✅ Removes invalid dates and displays warnings for them.
- ✅ Formats valid dates to
YYYY-MM-DD
for consistency.
2.4 Best Practices
In this section you will learn the Best Practices about Syntax & Control Flow in Python and R:
2.4.1 Readability & Formatting
- ✅ Follow PEP 8 for clean and readable code.
- ✅ Use consistent indentation (4 spaces per level).
- ✅ Keep line length ≤ 79 characters.
- ✅ Use meaningful variable and function names.
Python Code
# ✅ Good: Readable and follows PEP 8
def calculate_total(price, tax_rate):
"Calculate the total price after tax."
= price + (price * tax_rate)
total return total
# ❌ Bad: Poor formatting and unclear naming
def calc(p, t): return p+(p*t) # One-liner (not recommended)
R Code
# ✅ Good: Readable and follows conventions
<- function(price, tax_rate) {
total_price "Calculate the total price after tax."
<- price + (price * tax_rate)
total return(total)
}
# ❌ Bad: Poor formatting and unclear naming
<- function(p, t) { p + (p * t) } # One-liner (not recommended) total
2.4.2 Efficient Control Flow
- ✅ Use
if-elif-else
correctly to avoid redundant checks.
- ✅ Avoid deep nesting; use guard clauses to improve readability.
Python Code
# ✅ Good: Uses guard clause to return early
def check_access(user):
if not user.is_authenticated:
return "Access Denied"
if user.is_admin:
return "Access Granted: Admin"
return "Access Granted: User"
# ❌ Bad: Deeply nested structure
def check_access(user):
if user.is_authenticated:
if user.is_admin:
return "Access Granted: Admin"
else:
return "Access Granted: User"
else:
return "Access Denied"
R Code
# ✅ Good: Uses early return
<- function(user) {
check_access if (!user$authenticated) {
return("Access Denied")
}
if (user$admin) {
return("Access Granted: Admin")
}
return("Access Granted: User")
}
2.4.3 Looping Best Practices
- ✅ Use list comprehensions for simple loops.
- ✅ Use
enumerate()
instead of manually managing indexes.
- ✅ Use
zip()
for iterating over multiple lists simultaneously.
Python Code
# ✅ Good: List comprehension for efficiency
= [x**2 for x in range(10) if x % 2 == 0]
squares
# ✅ Good: Using enumerate
= ["Alice", "Bob", "Charlie"]
names for index, name in enumerate(names, start=1):
print(f"{index}: {name}")
# ✅ Good: Using zip()
= ["name", "age", "city"]
keys = ["Alice", 25, "New York"]
values = dict(zip(keys, values)) person
# ✅ Good: Vectorized operation
<- (0:9)^2
squares
# ✅ Good: Using sapply
<- c("Alice", "Bob", "Charlie")
names print(sapply(seq_along(names), function(i) paste(i, names[i])))
[1] "1 Alice" "2 Bob" "3 Charlie"
2.4.4 Common Mistakes in Loops
- ✅ Don’t modify lists while iterating (use a copy instead).
- ✅ Use
break
andcontinue
sparingly to maintain readability.
Python Code
# ✅ Good: Iterating over a copy when modifying a list
= [1, 2, 3, 4, 5]
numbers for num in numbers[:]: # Copy of the list
if num % 2 == 0:
numbers.remove(num)
# ❌ Bad: Modifying a list while iterating (can cause unexpected behavior)
for num in numbers:
if num % 2 == 0:
numbers.remove(num)
R Code
# ✅ Good: Using which to filter elements
<- c(1, 2, 3, 4, 5)
numbers <- numbers[numbers %% 2 != 0] numbers
2.4.5 Cleaner Conditionals
Use match-case
instead of long if-elif
chains when checking specific values Python 3.10+.
Python
# ✅ Good: Using match-case
def get_status(code):
match code:
case 200:
return "OK"
case 404:
return "Not Found"
case 500:
return "Internal Server Error"
case _:
return "Unknown Status"
# ❌ Bad: Using multiple if-elif
def get_status(code):
if code == 200:
return "OK"
elif code == 404:
return "Not Found"
elif code == 500:
return "Internal Server Error"
else:
return "Unknown Status"
R Code
# ✅ Good: Using switch
<- function(code) {
get_status switch(as.character(code),
"200" = "OK",
"404" = "Not Found",
"500" = "Internal Server Error",
"Unknown Status")
}
2.4.6 Error Handling
- ✅ Catch only specific exceptions instead of using a general
except
clause.
- ✅ Use
finally
for cleanup operations (e.g., closing files, releasing resources).
Python Code
# ✅ Good: Handling specific exceptions
try:
= int(input("Enter a number: "))
number = 10 / number
result except ValueError:
print("Invalid input! Please enter a number.")
except ZeroDivisionError:
print("Cannot divide by zero.")
finally:
print("Execution complete.")
R Code
# ✅ Good: Handling specific exceptions
<- function(a, b) {
safe_divide tryCatch({
<- a / b
result return(result)
warning = function(w) {
}, message("Warning: ", w$message)
error = function(e) {
}, message("Error: Cannot divide by zero.")
}) }
2.4.7 Resource Management
Use with
statements when working with files to ensure proper cleanup.
Python Code
# ✅ Good: Using with statement (auto-closes file)
with open("data.txt", "r") as file:
= file.read() content
# ❌ Bad: Forgetting to close the file
file = open("data.txt", "r")
= file.read()
content file.close()
R Code
# ✅ Good: Using on.exit() to clean up
<- function(file) {
read_data <- file(file, "r")
con on.exit(close(con))
<- readLines(con)
data return(data)
}
2.4.8 Mutable Default Arguments
Use immutable types (e.g., None
) as default arguments instead of mutable ones.
Python Code
# ✅ Good: Using None to avoid unintended behavior
def add_item(item, items=None):
if items is None:
= []
items
items.append(item)return items
R Code
# ✅ Good: Using NULL to avoid unintended behavior
<- function(item, items = NULL) {
add_item if (is.null(items)) {
<- list()
items
}<- append(items, item)
items return(items)
}
2.4.9 Using Generators for
Use yield
for efficient memory usage when handling large datasets.
Python Code
# ✅ Good: Using generator function
def count_up_to(n):
= 1
count while count <= n:
yield count
+= 1
count
for num in count_up_to(5):
print(num)
R Code
# ✅ Good: Using closures to generate a sequence
<- function(n) {
count_up_to <- 1
count function() {
if (count <= n) {
<- count
result <<- count + 1
count return(result)
else {
} return(NULL)
}
}
}
<- count_up_to(5)
counter while (!is.null(value <- counter())) {
print(value)
}
By following these best practices, you can write clean, efficient, and maintainable Python and R code. 🚀
2.5 Practicum
Independent Practice: Conditional Statements and Loops in Python & R
2.5.1 Objective
- Understand and implement conditional statements (
if
,if-else
,if-elif-else
). - Apply loops (
for loop
,while loop
,break
,continue
) to analyze a dataset.
Use the following dummy dataset:
ID | Name | Age | Salary | Position | Performance |
---|---|---|---|---|---|
1 | Bagas | 25 | 5000 | Staff | Good |
2 | Joan | 30 | 7000 | Supervisor | Very Good |
3 | Alya | 27 | 6500 | Staff | Average |
4 | Dwi | 35 | 10000 | Manager | Good |
5 | Nabil | 40 | 12000 | Director | Very Good |
2.5.2 Conditional Statements
Determine bonus levels based on employee performance:
- Very Good → 20% of salary
- Good → 10% of salary
- Average → 5% of salary
Your Task:
- Write a program in Python and R to calculate each employee’s bonus.
- Display the output in this format:
"Name: Bagas, Bonus: 500"
2.5.3 Loops (For & While)
- Use a for loop to list employees with a salary greater than 6000.
Expected Output:
Name: Joan, Salary: 7000
Name: Alya, Salary: 6500
Name: Dwi, Salary: 10000
Name: Nabil, Salary: 12000
- Use a while loop to display employees until a “Manager” is found.
Expected Output:
Name: Bagas, Position: Staff
Name: Joan, Position: Supervisor
Name: Alya, Position: Staff
Name: Dwi, Position: Manager (Stop here)
- Use break to stop the loop when an employee with a salary above 10,000 is found.
Expected Output:
Name: Bagas, Salary: 5000
Name: Joan, Salary: 7000
Name: Alya, Salary: 6500
Name: Dwi, Salary: 10000
(Stopped because Nabil has a salary above 10,000)
- Use continue to skip employees with “Average” performance.
Expected Output:
Name: Bagas, Performance: Good
Name: Joan, Performance: Very Good
Name: Dwi, Performance: Good
Name: Nabil, Performance: Very Good
(Alya is skipped because the performance is "Average")
Submission Guidelines:
- Submit your Python and R code using your
Google Colab
andRpubs
. - Ensure the output is displayed correctly.
- Add comments in the code to explain your logic.