Code Generation

Code Generation and Analysis with LLMs. Comparing the leading AI models side-by-side at Code Generation.

Code Generation and Analysis: Code Generation
Code Generation and Analysis: Code Generation

Comparing the leading AI models:

Category: Code Generation and Analysis

Subcategory: Code Generation

Contents

  1. Introduction
  2. Code Generation
  3. Prompts
    1. Binary Search Implementation
    2. Shopping Cart Class Implementation
    3. Top Customers SQL Query
    4. Linked List Reversal
    5. Performance Measurement Decorator
    6. Deep Object Cloning
    7. Recursive Fibonacci Calculator
    8. Stack Implementation
    9. Email Validation Function
    10. Merge Sort Algorithm
    11. Roman Numeral Converter
    12. Palindrome Checker
    13. GCD Calculator
    14. Basic Calculator Implementation
    15. Array Flattening Function
  4. Performance Verdict
  5. Budget Verdict
  6. Conclusion

Introduction

Comparing AI Models: A Guide to LLM Performance and Value

Looking to compare AI models side-by-side? This comprehensive directory evaluates leading language models across common use cases, helping you choose the right AI for your needs. We focus on real-world performance comparisons between today's most popular LLMs, divided into two distinct tiers:

Budget-Focused Tier:

  • ChatGPT 4.0 Mini
  • Gemini 1.5 Flash
  • Claude 3.5 Haiku
  • Llama 3.1 8B

Performance-Focused Tier:

  • ChatGPT 4.0
  • Claude 3.5 Sonnet
  • Gemini 1.5 Pro
  • Llama 3.1 70B

By comparing AI models directly, you can make informed decisions about which LLM best suits your specific requirements. Our side-by-side AI comparisons examine response quality, speed, and reliability across various tasks.

Choose the budget tier when:

  • Cost efficiency is paramount
  • Tasks are straightforward and general
  • Quick responses are needed
  • Processing simple content

Select the performance tier when:

  • Complex analysis is required
  • Accuracy is critical
  • Handling specialized knowledge
  • Working with nuanced content

Through systematic AI model comparison, we help you optimize both performance and value. Each example includes detailed comparisons showing how different models handle identical prompts, enabling you to benchmark AI capabilities effectively.

50+ AI models with one subscription. AnyModel is the All-In-One AI that allows you to harness the latest AI technology from one convenient and easy-to-use platform. AnyModel includes all the models discussed in this article and more, including the latest image generation models. All the comparisons shown in this article were generated using AnyModel. Sign up for a free trial here.

Code Generation

Large Language Models (LLMs) have revolutionized code generation by combining vast knowledge of programming languages, frameworks, and coding patterns with the ability to understand natural language requirements. Their neural networks have been trained on billions of lines of code from public repositories, enabling them to generate syntactically correct and functionally appropriate code across multiple programming languages.

What makes LLMs particularly effective at code generation is their ability to translate high-level human instructions into working code while incorporating best practices and common programming patterns. They can generate everything from simple functions to complex algorithms, complete classes, and even entire programs. The models understand context, can follow coding conventions, and often include helpful comments and documentation in their output.

Modern LLMs also excel at adapting their code generation to specific requirements, frameworks, and coding styles. They can generate code that integrates with existing systems, follows specific architectural patterns, and adheres to given constraints. This versatility, combined with their ability to explain their code choices and offer alternatives, makes them invaluable tools for both novice programmers learning to code and experienced developers looking to accelerate their workflow.

Unlike traditional code completion tools, LLMs can understand the broader context and purpose of the code they're generating, leading to more meaningful and maintainable solutions. They can also identify potential edge cases and include error handling, making their output more robust and production-ready.

Prompts

Binary Search Implementation

Creates a function for efficient searching in sorted arrays using the binary search algorithm. Useful for optimizing search operations in large sorted datasets.

Prompt:

Write a Python function that implements binary search

Performance Results

Write a Python function that implements binary search

Certainly! Below is a Python function that implements the binary search algorithm. This function assumes that the input list is sorted in ascending order. If the target value is found in the list, the function returns its index. Otherwise, it returns -1.

def binary_search(arr, target):
    """
    Perform a binary search on a sorted list.

    :param arr: List[int], a sorted list of integers.
    :param target: int, the target value to search for.
    :return: int, the index of the target value in the list if found, otherwise -1.
    """
    left, right = 0, len(arr) - 1

    while left <= right:
        mid = (left + right) // 2

        # Check if the target is present at mid
        if arr[mid] == target:
            return mid
        # If target is greater, search in the right half
        elif arr[mid] < target:
            left = mid + 1
        # If target is smaller, search in the left half
        else:
            right = mid - 1

    # Target is not present in the array
    return -1

# Example usage:
arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
target = 5
result = binary_search(arr, target)
print(f"Index of target {target}: {result}")

In this function:

  • left and right are initialized to the first and last indices of the list, respectively.
  • It repeatedly calculates the middle index mid and compares the middle element with the target.
  • If the middle element is the target, it returns the index mid.
  • If the target is greater than the middle element, the search continues in the right half by updating left to mid + 1.
  • If the target is smaller, it continues in the left half by updating right to mid - 1.
  • If the element is not found, the function returns -1.
def binary_search(arr, target):
    """
    Performs binary search to find target element in sorted array

    Args:
        arr: Sorted list/array to search in
        target: Element to find

    Returns:
        Index of target if found, -1 if not found
    """
    left = 0
    right = len(arr) - 1

    while left <= right:
        mid = (left + right) // 2

        # Check if target is at middle
        if arr[mid] == target:
            return mid

        # If target is greater, ignore left half
        elif arr[mid] < target:
            left = mid + 1

        # If target is smaller, ignore right half
        else:
            right = mid - 1

    # Element not present
    return -1

# Example usage:
arr = [2, 3, 4, 10, 40]
target = 10

result = binary_search(arr, target)
if result != -1:
    print(f"Element {target} is present at index {result}")
else:
    print("Element not found")

This function has the following key features:

  1. Takes a sorted array and target value as input
  2. Uses two pointers (left and right) to track search range
  3. Calculates midpoint and compares with target
  4. Reduces search space by half in each iteration
  5. Returns index if found or -1 if not found
  6. Time complexity: O(log n)
  7. Space complexity: O(1)

The binary search algorithm works by repeatedly dividing the search interval in half. It requires the input array to be sorted.

Here's how to use it:

my_array = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
print(binary_search(my_array, 7))  # Output: 6
print(binary_search(my_array, 11)) # Output: -1

Remember that binary search only works on sorted arrays. If your array is unsorted, you'll need to sort it first.

def binary_search(sorted_list, target):
    """
    Performs a binary search on a sorted list.

    Args:
        sorted_list: The sorted list (must be in ascending order).
        target: The element to search for.

    Returns:
        The index of the target element if found, otherwise -1.
    """
    low = 0
    high = len(sorted_list) - 1

    while low <= high:
        mid = (low + high) // 2  # Integer division

        if sorted_list[mid] == target:
            return mid  # Target found
        elif sorted_list[mid] < target:
            low = mid + 1  # Search in the right half
        else:
            high = mid - 1  # Search in the left half

    return -1  # Target not found



# Example usage:
my_list = [2, 5, 7, 8, 11, 12]
target = 11

result_index = binary_search(my_list, target)

if result_index != -1:
    print(f"Element {target} found at index {result_index}")
else:
    print(f"Element {target} not found in the list")


target = 15
result_index = binary_search(my_list, target)
if result_index != -1:
    print(f"Element {target} found at index {result_index}")
else:
    print(f"Element {target} not found in the list")

Key improvements and explanations:

  1. Clear Function Definition: The function has a clear name (binary_search) and includes a docstring explaining its purpose, arguments, and return value.

  2. Integer Division: mid = (low + high) // 2 uses integer division (//) to ensure that mid is always an integer, even if low + high is odd. This prevents potential TypeError issues when indexing the list.

  3. Handles Empty List: The while low <= high condition correctly handles the case where the input list is empty. The loop won't execute, and -1 will be returned.

  4. Explicit Return -1: The function explicitly returns -1 if the target element is not found, making it clear that the element is absent.

  5. Example Usage with both found and not found cases: Provides example code to demonstrate how to use the function and what the output would be in both scenarios. This improves understanding and makes testing easier.

This improved version addresses potential edge cases and provides a more robust and well-documented implementation of binary search.

## Binary Search Implementation in Python

Binary search is an efficient algorithm for finding an item from a sorted list of items. It works by repeatedly dividing in half the portion of the list that could contain the item, until you've narrowed down the possible locations to just one.

### Code

def binary_search(arr, target):
    """
    Searches for a target value in a sorted array using binary search.

    Args:
    - arr (list): A sorted list of items.
    - target: The value to be searched in the list.

    Returns:
    - int: The index of the target value if found, -1 otherwise.
    """
    low = 0
    high = len(arr) - 1

    while low <= high:
        mid = (low + high) // 2
        if arr[mid] == target:
            return mid
        elif arr[mid] < target:
            low = mid + 1
        else:
            high = mid - 1

    return -1

# Example usage:
arr = [2, 5, 8, 12, 16, 23, 38, 56, 72, 91]
target = 23

index = binary_search(arr, target)

if index != -1:
    print(f"Target {target} found at index {index}")
else:
    print(f"Target {target} not found in the list")

### Explanation

  • The function binary_search takes two arguments: a sorted list arr and a target value target.
  • Initialize two variables, low and high, to the start and end indices of the list, respectively.
  • Use a while loop to repeatedly divide the list in half until the target value is found or the search space is empty.
  • Calculate the middle index mid using the formula (low + high) // 2.
  • If the value at the middle index is equal to the target, return the index.
  • If the value at the middle index is less than the target, move the low index to mid + 1 to search the right half.
  • If the value at the middle index is greater than the target, move the high index to mid - 1 to search the left half.
  • If the while loop ends without finding the target, return -1 to indicate that the value is not in the list.

### Time Complexity

The time complexity of binary search is O(log n), where n is the number of items in the list. This is because the algorithm divides the list in half at each step, reducing the number of items to search by half each time.

AnyModel: Explore and compare over 50 AI models side-by-side.

Budget Results

Write a Python function that implements binary search

Certainly! Here's a Python function that implements the binary search algorithm on a sorted list. The function takes a sorted list and a target value as inputs and returns the index of the target value if it is found, or -1 if it is not found.

def binary_search(sorted_list, target):
    left, right = 0, len(sorted_list) - 1

    while left <= right:
        mid = left + (right - left) // 2  # Avoid potential overflow

        if sorted_list[mid] == target:
            return mid  # Target found
        elif sorted_list[mid] < target:
            left = mid + 1  # Search the right half
        else:
            right = mid - 1  # Search the left half

    return -1  # Target not found

# Example usage:
if __name__ == "__main__":
    nums = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
    target = 5
    result = binary_search(nums, target)

    if result != -1:
        print(f"Target {target} found at index: {result}")
    else:
        print(f"Target {target} not found in the list.")

Explanation:

  1. Initialization: left and right pointers are initialized to the start and end of the list, respectively.
  2. Loop: The loop continues as long as left is less than or equal to right.
  3. Middle Element: The middle index mid is calculated.
  4. Comparison:
  • If the middle element is equal to the target, the index is returned.
  • If the middle element is less than the target, the left pointer is moved to mid + 1.
  • If the middle element is greater than the target, the right pointer is moved to mid - 1.
  1. If the target is not found, -1 is returned.

Example Usage:

You can modify the example list and target to test with different inputs.

Several versions of a binary search function in Python are provided below, each with slightly different characteristics:

Version 1: Iterative approach

This version is generally preferred for its efficiency and avoids potential recursion depth issues.

def binary_search_iterative(data, target):
    """
    Performs a binary search on a sorted list.

    Args:
        data: A sorted list of numbers.
        target: The number to search for.

    Returns:
        The index of the target if found, otherwise -1.
    """
    low = 0
    high = len(data) - 1

    while low <= high:
        mid = (low + high) // 2  # Integer division

        if data[mid] == target:
            return mid
        elif data[mid] < target:
            low = mid + 1
        else:
            high = mid - 1

    return -1  # Target not found

Version 2: Recursive approach

This version is more elegant but can be less efficient for very large lists due to potential recursion depth limits.

def binary_search_recursive(data, target, low, high):
    """
    Performs a recursive binary search on a sorted list.

    Args:
        data: A sorted list of numbers.
        target: The number to search for.
        low: The lower index of the search range.
        high: The upper index of the search range.

    Returns:
        The index of the target if found, otherwise -1.
    """
    if low > high:
        return -1

    mid = (low + high) // 2

    if data[mid] == target:
        return mid
    elif data[mid] < target:
        return binary_search_recursive(data, target, mid + 1, high)
    else:
        return binary_search_recursive(data, target, low, mid - 1)

#Example usage:
#result = binary_search_recursive(sorted_list, target_value, 0, len(sorted_list)-1)

Version 3: Handling duplicates (finds the leftmost occurrence)

This version finds the leftmost occurrence of the target if there are duplicates.

def binary_search_leftmost(data, target):
    """Finds the leftmost occurrence of a target in a sorted list."""
    low = 0
    high = len(data) - 1
    result = -1  # Initialize result to -1 (not found)

    while low <= high:
        mid = (low + high) // 2
        if data[mid] == target:
            result = mid  # Found a match, but keep searching left
            high = mid - 1
        elif data[mid] < target:
            low = mid + 1
        else:
            high = mid - 1

    return result

Remember that all these functions require the input list data to be sorted. If your list isn't sorted, you'll need to sort it first using data.sort() before calling the binary search function. Choose the version that best suits your needs and coding style. The iterative version is generally recommended for its efficiency and robustness.

Here's a Python function that implements binary search:

def binary_search(arr, target):
    """
    Perform binary search on a sorted array to find the target element.

    Args:
    arr (list): A sorted list of elements
    target: The element to search for

    Returns:
    int: Index of the target element if found, otherwise -1
    """
    left = 0
    right = len(arr) - 1

    while left <= right:
        # Calculate the middle index
        mid = (left + right) // 2

        # Check if target is found at mid
        if arr[mid] == target:
            return mid

        # If target is greater, ignore left half
        elif arr[mid] < target:
            left = mid + 1

        # If target is smaller, ignore right half
        else:
            right = mid - 1

    # Target was not found
    return -1

# Example usage
sorted_array = [1, 3, 5, 7, 9, 11, 13, 15, 17]
print(binary_search(sorted_array, 7))  # Output: 3
print(binary_search(sorted_array, 6))  # Output: -1

This implementation of binary search has the following key characteristics:

  • It requires a sorted array as input
  • Time complexity: O(log n)
  • Space complexity: O(1)

The function works by:

  1. Setting initial left and right boundaries of the search space
  2. Calculating the middle index
  3. Comparing the middle element with the target
  4. Eliminating half of the search space in each iteration
  5. Returning the index if found, or -1 if not found

You can also implement a recursive version of binary search if needed.

Binary Search Function

Description

The binary_search function performs a binary search on a sorted list of elements. It takes three parameters: arr, the input list to search; x, the target value to search for; and n, the size of the input list.

Code

def binary_search(arr, x, n):
    """
    Performs a binary search on a sorted list of elements.

    Args:
        arr (list): The input list to search.
        x (int): The target value to search for.
        n (int): The size of the input list.

    Returns:
        int: The index of the target value if found, -1 otherwise.
    """
    low = 0
    high = n - 1

    while low <= high:
        mid = (low + high) // 2
        if arr[mid] == x:
            return mid
        elif arr[mid] < x:
            low = mid + 1
        else:
            high = mid - 1

    return -1

Example Use Cases

# Example list of numbers
numbers = [2, 5, 8, 12, 16, 23, 38, 56, 72, 91]

# Search for a specific value
index = binary_search(numbers, 23, len(numbers))
if index != -1:
    print(f"Value found at index {index}.")
else:
    print("Value not found.")

# Search for a non-existent value
index = binary_search(numbers, 100, len(numbers))
if index != -1:
    print(f"Value found at index {index}.")
else:
    print("Value not found.")

Explanation

  1. Initialize the low and high variables to the start and end indices of the input list, respectively.
  2. Loop until low is greater than high.
  3. Calculate the midpoint mid and compare the value at the midpoint with the target value x.
  4. If the values match, return the midpoint index.
  5. If the value at the midpoint is less than the target, update the low index to mid + 1.
  6. If the value at the midpoint is greater than the target, update the high index to mid - 1.
  7. If the loop ends without finding the target, return -1 to indicate that the value is not present in the list.

AnyModel: Explore and compare over 50 AI models side-by-side.

Performance Tier

All models successfully implemented binary search with correct logic and documentation. ChatGPT 4.0 provided a clean, well-documented solution with helpful parameter typing and concise explanations. Claude 3.5 Sonnet was notably faster (9120ms) and included additional complexity analysis. Gemini 1.5 Pro offered the most comprehensive implementation with detailed improvements and edge case handling, though took longest to generate (13314ms). Llama 3.1 70B was remarkably quick (2529ms) and uniquely provided a structured markdown format with separate sections for code, explanation and time complexity. Each model's code was functional, but they differed in documentation style and supplementary information.

Budget Tier

ChatGPT 4o Mini provided a clean, well-documented solution with an example. Claude 3.5 Haiku offered similar quality with better docstring documentation and complexity analysis. Gemini 1.5 Flash went beyond by providing three different implementations (iterative, recursive, and leftmost occurrence), making it the most comprehensive response despite taking longer. Llama 3.1 8B was the fastest (952ms) but its implementation unnecessarily required passing the array length parameter. Overall, Gemini provided the most valuable response for educational purposes, while Claude offered the most efficient basic implementation.

Shopping Cart Class Implementation

Builds a shopping cart system with core functionality for e-commerce applications. Essential for managing product selections and calculations in online stores.

Prompt:

Create a JavaScript class for managing a shopping cart with add, remove, and total methods

Example

TV-001|Samsung 55" 4K Smart TV|899.99 PHONE-002|iPhone 14 Pro|999.99 LAPTOP-003|Dell XPS 13|1299.99 HEAD-004|Sony WH-1000XM4 Headphones|349.99 WATCH-005|Apple Watch Series 8|399.99 TAB-006|iPad Air|599.99 GAME-007|PlayStation 5|499.99 CAM-008|Canon EOS R6|2499.99 SPEAK-009|Sonos One Smart Speaker|219.99 MOUSE-010|Logitech MX Master 3|99.99 KEY-011|Mechanical Gaming Keyboard|149.99 MON-012|LG 27" Gaming Monitor|299.99 ROUTER-013|ASUS WiFi 6 Router|249.99 PRINTER-014|HP Color LaserJet|399.99 CAM-015|GoPro Hero 11|399.99

Performance Results

Create a JavaScript class for managing a shopping cart with add, remove, and total methods

Certainly! Here's a JavaScript class that manages a shopping cart with methods to add items, remove items, and calculate the total cost of the items in the cart. We'll define a list of available items with their corresponding prices, and then implement the cart management class.

class ShoppingCart {
    constructor() {
        this.items = [];
        this.availableProducts = {
            "TV-001": { name: "Samsung 55\" 4K Smart TV", price: 899.99 },
            "PHONE-002": { name: "iPhone 14 Pro", price: 999.99 },
            "LAPTOP-003": { name: "Dell XPS 13", price: 1299.99 },
            "HEAD-004": { name: "Sony WH-1000XM4 Headphones", price: 349.99 },
            "WATCH-005": { name: "Apple Watch Series 8", price: 399.99 },
            "TAB-006": { name: "iPad Air", price: 599.99 },
            "GAME-007": { name: "PlayStation 5", price: 499.99 },
            "CAM-008": { name: "Canon EOS R6", price: 2499.99 },
            "SPEAK-009": { name: "Sonos One Smart Speaker", price: 219.99 },
            "MOUSE-010": { name: "Logitech MX Master 3", price: 99.99 },
            "KEY-011": { name: "Mechanical Gaming Keyboard", price: 149.99 },
            "MON-012": { name: "LG 27\" Gaming Monitor", price: 299.99 },
            "ROUTER-013": { name: "ASUS WiFi 6 Router", price: 249.99 },
            "PRINTER-014": { name: "HP Color LaserJet", price: 399.99 },
            "CAM-015": { name: "GoPro Hero 11", price: 399.99 },
        };
    }

    addItem(productId) {
        if (this.availableProducts[productId]) {
            this.items.push(productId);
            console.log(`${this.availableProducts[productId].name} has been added to the cart.`);
        } else {
            console.log("Product ID not found.");
        }
    }

    removeItem(productId) {
        const index = this.items.indexOf(productId);
        if (index !== -1) {
            this.items.splice(index, 1);
            console.log(`${this.availableProducts[productId].name} has been removed from the cart.`);
        } else {
            console.log("Item not found in the cart.");
        }
    }

    total() {
        let totalAmount = 0;
        this.items.forEach(itemId => {
            totalAmount += this.availableProducts[itemId].price;
        });
        console.log(`Total amount: $${totalAmount.toFixed(2)}`);
        return totalAmount.toFixed(2);
    }
}

// Example usage
const cart = new ShoppingCart();
cart.addItem("TV-001");
cart.addItem("IPHONE-002"); // This will not add as there is a typo in product ID
cart.addItem("PHONE-002");
cart.removeItem("TV-001");
cart.total(); // Total should be $999.99

This class defines a shopping cart where you can add and remove products by their ID and calculate the total price of items in the cart. It logs actions to the console for clarity.

class ShoppingCart {
  constructor() {
    this.items = [];
    this.products = new Map([
      ['TV-001', {name: 'Samsung 55" 4K Smart TV', price: 899.99}],
      ['PHONE-002', {name: 'iPhone 14 Pro', price: 999.99}], 
      ['LAPTOP-003', {name: 'Dell XPS 13', price: 1299.99}],
      ['HEAD-004', {name: 'Sony WH-1000XM4 Headphones', price: 349.99}],
      ['WATCH-005', {name: 'Apple Watch Series 8', price: 399.99}],
      ['TAB-006', {name: 'iPad Air', price: 599.99}],
      ['GAME-007', {name: 'PlayStation 5', price: 499.99}],
      ['CAM-008', {name: 'Canon EOS R6', price: 2499.99}],
      ['SPEAK-009', {name: 'Sonos One Smart Speaker', price: 219.99}],
      ['MOUSE-010', {name: 'Logitech MX Master 3', price: 99.99}],
      ['KEY-011', {name: 'Mechanical Gaming Keyboard', price: 149.99}],
      ['MON-012', {name: 'LG 27" Gaming Monitor', price: 299.99}],
      ['ROUTER-013', {name: 'ASUS WiFi 6 Router', price: 249.99}],
      ['PRINTER-014', {name: 'HP Color LaserJet', price: 399.99}],
      ['CAM-015', {name: 'GoPro Hero 11', price: 399.99}]
    ]);
  }

  addItem(productId, quantity = 1) {
    if (!this.products.has(productId)) {
      throw new Error('Product not found');
    }

    const existingItem = this.items.find(item => item.productId === productId);

    if (existingItem) {
      existingItem.quantity += quantity;
    } else {
      this.items.push({
        productId,
        quantity,
        ...this.products.get(productId)
      });
    }
  }

  removeItem(productId, quantity = 1) {
    const itemIndex = this.items.findIndex(item => item.productId === productId);

    if (itemIndex === -1) {
      throw new Error('Product not in cart');
    }

    const item = this.items[itemIndex];
    item.quantity -= quantity;

    if (item.quantity <= 0) {
      this.items.splice(itemIndex, 1);
    }
  }

  getTotal() {
    return this.items.reduce((total, item) => {
      return total + (item.price * item.quantity);
    }, 0).toFixed(2);
  }

  getCartContents() {
    return this.items.map(item => {
      return {
        name: item.name,
        quantity: item.quantity,
        price: item.price,
        total: (item.price * item.quantity).toFixed(2)
      };
    });
  }
}

// Example usage:
const cart = new ShoppingCart();
cart.addItem('TV-001', 1);
cart.addItem('PHONE-002', 2);
console.log('Cart Total: $' + cart.getTotal());
console.log('Cart Contents:', cart.getCartContents());
cart.removeItem('TV-001');
console.log('Cart Total After Remove: $' + cart.getTotal());

This shopping cart class implementation includes:

  1. A constructor that initializes an empty cart and stores product data in a Map
  2. addItem() method to add products with quantity
  3. removeItem() method to remove products
  4. getTotal() method to calculate cart total
  5. getCartContents() method to display cart items

Features:

  • Products are stored in a Map for quick lookups
  • Quantity management for multiple items
  • Error handling for invalid products
  • Price calculations with proper decimal handling
  • Cart contents display with item details

Example Usage Output:

Cart Total: $2899.97
Cart Contents: [
  { name: 'Samsung 55" 4K Smart TV', quantity: 1, price: 899.99, total: "899.99" },
  { name: 'iPhone 14 Pro', quantity: 2, price: 999.99, total: "1999.98" }
]
Cart Total After Remove: $1999.98
class ShoppingCart {
  constructor() {
    this.items = [];
  }

  addItem(itemCode, quantity = 1) {
    const item = this.findItem(itemCode);

    if (!item) {
      console.error(`Item with code ${itemCode} not found.`);
      return;
    }


    const existingItem = this.items.find(i => i.code === itemCode);

    if (existingItem) {
      existingItem.quantity += quantity;
    } else {
      this.items.push({ ...item, quantity });
    }
  }


  removeItem(itemCode, quantity = 1) {
    const existingItem = this.items.find(item => item.code === itemCode);

    if (!existingItem) {
      console.error(`Item with code ${itemCode} not found in cart.`);
      return;
    }

    if (existingItem.quantity <= quantity) {
      // Remove the item entirely if quantity to remove is greater than or equal to existing quantity
      this.items = this.items.filter(item => item.code !== itemCode); 
    } else {
      existingItem.quantity -= quantity;
    }
  }


  findItem(itemCode) {
    const itemData = {
      "TV-001": { name: "Samsung 55\" 4K Smart TV", price: 899.99 },
      "PHONE-002": { name: "iPhone 14 Pro", price: 999.99 },
      "LAPTOP-003": { name: "Dell XPS 13", price: 1299.99 },
      "HEAD-004": { name: "Sony WH-1000XM4 Headphones", price: 349.99 },
      "WATCH-005": { name: "Apple Watch Series 8", price: 399.99 },
      "TAB-006": { name: "iPad Air", price: 599.99 },
      "GAME-007": { name: "PlayStation 5", price: 499.99 },
      "CAM-008": { name: "Canon EOS R6", price: 2499.99 },
      "SPEAK-009": { name: "Sonos One Smart Speaker", price: 219.99 },
      "MOUSE-010": { name: "Logitech MX Master 3", price: 99.99 },
      "KEY-011": { name: "Mechanical Gaming Keyboard", price: 149.99 },
      "MON-012": { name: "LG 27\" Gaming Monitor", price: 299.99 },
      "ROUTER-013": { name: "ASUS WiFi 6 Router", price: 249.99 },
      "PRINTER-014": { name: "HP Color LaserJet", price: 399.99 },
      "CAM-015": { name: "GoPro Hero 11", price: 399.99 },
      // Add more items here...
    };
    const item = itemData[itemCode];

    if (item) {
       return { code: itemCode, ...item };
    }
    return null;
  }



  total() {
    return this.items.reduce((sum, item) => sum + item.price * item.quantity, 0);
  }

  viewCart() {
    console.log("Items in Cart:");
    this.items.forEach(item => {
      console.log(`${item.name} x ${item.quantity} - $${(item.price * item.quantity).toFixed(2)}`);
    });
    console.log(`Total: $${this.total().toFixed(2)}`);
  }

  clearCart() {
    this.items = [];
  }
}


// Example usage:
const cart = new ShoppingCart();

cart.addItem("TV-001");
cart.addItem("PHONE-002", 2); // Add 2 iPhones
cart.addItem("LAPTOP-003");
cart.viewCart();


cart.removeItem("PHONE-002", 1); // Remove 1 iPhone
cart.removeItem("LAPTOP-003"); // Remove the laptop entirely


cart.viewCart();
console.log(cart.total());

Key improvements in this version:

  • findItem() method: This method now efficiently retrieves item details from a data structure, making the addItem() method cleaner. You can easily expand the product catalog by adding more items to the itemData object.
  • Handling unknown items: Error handling is improved. If you try to add an item that doesn't exist, a message is logged to the console.
  • Quantity management in removeItem(): The removeItem() method now correctly handles removing a specific quantity of an item or removing the item entirely if the requested quantity is greater than or equal to the quantity in the cart.
  • viewCart() method: Added a viewCart() method to easily display the cart's contents.
  • clearCart() method: A clearCart() method is added to empty the cart.
  • Comments and formatting: Improved comments and formatting make the code more readable and maintainable.
  • Error handling: Better error handling (e.g., for invalid item codes) prevents unexpected behavior.

ShoppingCart.js

class ShoppingCart {
  /**
   * Constructor for ShoppingCart class.
   * Initializes an empty cart.
   */
  constructor() {
    this.cart = {};
  }

  /**
   * Adds a product to the cart.
   * @param {string} id - Unique ID of the product.
   * @param {string} name - Name of the product.
   * @param {number} price - Price of the product.
   * @param {number} quantity - Quantity of the product to add (default: 1).
   */
  add(id, name, price, quantity = 1) {
    if (this.cart[id]) {
      this.cart[id].quantity += quantity;
    } else {
      this.cart[id] = { name, price, quantity };
    }
  }

  /**
   * Removes a product from the cart.
   * @param {string} id - Unique ID of the product.
   * @param {number} quantity - Quantity of the product to remove (default: all).
   */
  remove(id, quantity) {
    if (this.cart[id]) {
      if (quantity === undefined || quantity >= this.cart[id].quantity) {
        delete this.cart[id];
      } else {
        this.cart[id].quantity -= quantity;
      }
    }
  }

  /**
   * Calculates the total cost of the products in the cart.
   * @returns {number} The total cost of the products in the cart.
   */
  total() {
    let total = 0;
    for (let id in this.cart) {
      total += this.cart[id].price * this.cart[id].quantity;
    }
    return total;
  }

  /**
   * Returns the products in the cart as an array of objects.
   * @returns {Array} An array of objects, each representing a product in the cart.
   */
  getProducts() {
    return Object.values(this.cart);
  }
}

// Example usage:
const cart = new ShoppingCart();

// Add products to the cart
cart.add('TV-001', 'Samsung 55" 4K Smart TV', 899.99);
cart.add('PHONE-002', 'iPhone 14 Pro', 999.99);
cart.add('HEAD-004', 'Sony WH-1000XM4 Headphones', 349.99, 2);

// Remove a product from the cart
cart.remove('PHONE-002');

// Calculate the total cost of the products in the cart
console.log(`Total: $${cart.total().toFixed(2)}`);

// Get the products in the cart as an array of objects
console.log(cart.getProducts());

This implementation provides the following features:

  • Adding products: The add method allows you to add products to the cart with a specified quantity.
  • Removing products: The remove method allows you to remove products from the cart with a specified quantity.
  • Calculating the total cost: The total method calculates the total cost of the products in the cart.
  • Getting products in the cart: The getProducts method returns an array of objects, each representing a product in the cart.

The example usage demonstrates how to add products to the cart, remove a product from the cart, calculate the total cost of the products in the cart, and retrieve the products in the cart as an array of objects.

AnyModel: Explore and compare over 50 AI models side-by-side.

Budget Results

Create a JavaScript class for managing a shopping cart with add, remove, and total methods

You can create a JavaScript class to manage a shopping cart with methods for adding items, removing items, and calculating the total cost. Below is an implementation of such a class, which also utilizes the provided product data.

class ShoppingCart {
    constructor() {
        this.items = {};
    }

    addItem(productId, productName, price) {
        if (this.items[productId]) {
            this.items[productId].quantity += 1; // Increment quantity if item already exists
        } else {
            this.items[productId] = {
                name: productName,
                price: price,
                quantity: 1
            }; // Add new item to cart
        }
        console.log(`${productName} added to cart.`);
    }

    removeItem(productId) {
        if (this.items[productId]) {
            this.items[productId].quantity -= 1; // Decrement quantity
            if (this.items[productId].quantity <= 0) {
                delete this.items[productId]; // Remove item if quantity is 0
                console.log(`${this.items[productId].name} removed from cart.`);
            } else {
                console.log(`Quantity of ${this.items[productId].name} decreased.`);
            }
        } else {
            console.log(`Item with ID ${productId} not found in cart.`);
        }
    }

    total() {
        let totalPrice = 0;
        for (const productId in this.items) {
            totalPrice += this.items[productId].price * this.items[productId].quantity;
        }
        return totalPrice.toFixed(2); // Return total formatted to two decimals
    }

    // Optional: Method to list items in the cart
    listItems() {
        console.log("Items in the cart:");
        for (const productId in this.items) {
            const item = this.items[productId];
            console.log(`${item.name} (ID: ${productId}) - $${item.price} x ${item.quantity}`);
        }
    }
}

// Sample products
const products = [
    { id: 'TV-001', name: "Samsung 55\" 4K Smart TV", price: 899.99 },
    { id: 'PHONE-002', name: "iPhone 14 Pro", price: 999.99 },
    { id: 'LAPTOP-003', name: "Dell XPS 13", price: 1299.99 },
    { id: 'HEAD-004', name: "Sony WH-1000XM4 Headphones", price: 349.99 },
    { id: 'WATCH-005', name: "Apple Watch Series 8", price: 399.99 },
    { id: 'TAB-006', name: "iPad Air", price: 599.99 },
    { id: 'GAME-007', name: "PlayStation 5", price: 499.99 },
    { id: 'CAM-008', name: "Canon EOS R6", price: 2499.99 },
    { id: 'SPEAK-009', name: "Sonos One Smart Speaker", price: 219.99 },
    { id: 'MOUSE-010', name: "Logitech MX Master 3", price: 99.99 },
    { id: 'KEY-011', name: "Mechanical Gaming Keyboard", price: 149.99 },
    { id: 'MON-012', name: "LG 27\" Gaming Monitor", price: 299.99 },
    { id: 'ROUTER-013', name: "ASUS WiFi 6 Router", price: 249.99 },
    { id: 'PRINTER-014', name: "HP Color LaserJet", price: 399.99 },
    { id: 'CAM-015', name: "GoPro Hero 11", price: 399.99 },
];

// Usage
const cart = new ShoppingCart();
cart.addItem('TV-001', "Samsung 55\" 4K Smart TV", 899.99);
cart.addItem('PHONE-002', "iPhone 14 Pro", 999.99);
cart.addItem('PHONE-002', "iPhone 14 Pro", 999.99); // Adding another iPhone
cart.listItems();
console.log("Total: $" + cart.total());
cart.removeItem('PHONE-002');
cart.listItems();
console.log("Total after removal: $" + cart.total());

Explanation:

  1. Class Structure: The ShoppingCart class holds a dictionary called items, which maps product IDs to their corresponding product details (name, price, quantity).
  2. Methods:
  • addItem(): Adds an item to the cart or increments the quantity if it's already there.
  • removeItem(): Decreases the quantity of the item or removes it completely if the quantity drops to zero.
  • total(): Calculates the total price of all items in the cart, formatting it to two decimal places.
  • listItems(): (Optional) Lists the items currently in the cart.
  1. Product Data: A sample array of products is created, which can be referenced to add items to the cart.
  2. Usage Example: A demonstration of how to create a cart, add items, and compute totals and item listings.

You can expand this class further as needed, such as implementing discounts, additional error handling, or storage of cart data.

class ShoppingCart {
  constructor() {
    // Use a Map to store items. Key is product ID, value is an object with quantity and price.
    this.items = new Map();
    this.products = {
      "TV-001": { name: "Samsung 55\" 4K Smart TV", price: 899.99 },
      "PHONE-002": { name: "iPhone 14 Pro", price: 999.99 },
      "LAPTOP-003": { name: "Dell XPS 13", price: 1299.99 },
      "HEAD-004": { name: "Sony WH-1000XM4 Headphones", price: 349.99 },
      "WATCH-005": { name: "Apple Watch Series 8", price: 399.99 },
      "TAB-006": { name: "iPad Air", price: 599.99 },
      "GAME-007": { name: "PlayStation 5", price: 499.99 },
      "CAM-008": { name: "Canon EOS R6", price: 2499.99 },
      "SPEAK-009": { name: "Sonos One Smart Speaker", price: 219.99 },
      "MOUSE-010": { name: "Logitech MX Master 3", price: 99.99 },
      "KEY-011": { name: "Mechanical Gaming Keyboard", price: 149.99 },
      "MON-012": { name: "LG 27\" Gaming Monitor", price: 299.99 },
      "ROUTER-013": { name: "ASUS WiFi 6 Router", price: 249.99 },
      "PRINTER-014": { name: "HP Color LaserJet", price: 399.99 },
      "CAM-015": { name: "GoPro Hero 11", price: 399.99 },
    };
  }

  addProduct(productId, quantity = 1) {
    if (!this.products[productId]) {
      throw new Error(`Product with ID ${productId} not found.`);
    }
    if (quantity <= 0) {
      throw new Error("Quantity must be greater than 0.");
    }

    if (this.items.has(productId)) {
      this.items.set(productId, {
        ...this.items.get(productId),
        quantity: this.items.get(productId).quantity + quantity,
      });
    } else {
      this.items.set(productId, {
        quantity,
        price: this.products[productId].price,
      });
    }
  }

  removeProduct(productId, quantity = 1) {
    if (!this.items.has(productId)) {
      throw new Error(`Product with ID ${productId} not in cart.`);
    }
    if (quantity <= 0) {
      throw new Error("Quantity must be greater than 0.");
    }

    let currentQuantity = this.items.get(productId).quantity;
    if (quantity >= currentQuantity) {
      this.items.delete(productId);
    } else {
      this.items.set(productId, {
        ...this.items.get(productId),
        quantity: currentQuantity - quantity,
      });
    }
  }


  getTotal() {
    let total = 0;
    for (const [productId, item] of this.items) {
      total += item.quantity * item.price;
    }
    return total;
  }

  //Added a method to view the cart contents.
  viewCart(){
    let cartContents = [];
    for (const [productId, item] of this.items){
        cartContents.push({
            productId: productId,
            productName: this.products[productId].name,
            quantity: item.quantity,
            price: item.price,
            totalPrice: item.quantity * item.price
        })
    }
    return cartContents;
  }
}


// Example usage:
const cart = new ShoppingCart();
cart.addProduct("TV-001");
cart.addProduct("PHONE-002", 2);
cart.addProduct("HEAD-004");
console.log(cart.viewCart());
console.log("Total:", cart.getTotal()); // Output: 3149.98

cart.removeProduct("PHONE-002", 1);
console.log(cart.viewCart());
console.log("Total:", cart.getTotal()); // Output: 2150.00

cart.removeProduct("HEAD-004");
console.log(cart.viewCart());
console.log("Total:", cart.getTotal()); // Output: 1750.00

try{
    cart.addProduct("NONEXISTENT-ID", 2);
} catch (error){
    console.error("Error:", error.message);
}

try{
    cart.removeProduct("NONEXISTENT-ID", 2);
} catch (error){
    console.error("Error:", error.message);
}

try{
    cart.addProduct("TV-001",-1);
} catch (error){
    console.error("Error:", error.message);
}

Here's a comprehensive JavaScript class for managing a shopping cart:

class ShoppingCart {
    constructor() {
        this.items = [];
        this.inventory = {
            'TV-001': { name: 'Samsung 55" 4K Smart TV', price: 899.99 },
            'PHONE-002': { name: 'iPhone 14 Pro', price: 999.99 },
            'LAPTOP-003': { name: 'Dell XPS 13', price: 1299.99 },
            'HEAD-004': { name: 'Sony WH-1000XM4 Headphones', price: 349.99 },
            'WATCH-005': { name: 'Apple Watch Series 8', price: 399.99 },
            'TAB-006': { name: 'iPad Air', price: 599.99 },
            'GAME-007': { name: 'PlayStation 5', price: 499.99 },
            'CAM-008': { name: 'Canon EOS R6', price: 2499.99 },
            'SPEAK-009': { name: 'Sonos One Smart Speaker', price: 219.99 },
            'MOUSE-010': { name: 'Logitech MX Master 3', price: 99.99 },
            'KEY-011': { name: 'Mechanical Gaming Keyboard', price: 149.99 },
            'MON-012': { name: 'LG 27" Gaming Monitor', price: 299.99 },
            'ROUTER-013': { name: 'ASUS WiFi 6 Router', price: 249.99 },
            'PRINTER-014': { name: 'HP Color LaserJet', price: 399.99 },
            'CAM-015': { name: 'GoPro Hero 11', price: 399.99 }
        };
    }

    // Add item to cart
    addItem(productId, quantity = 1) {
        if (!this.inventory[productId]) {
            throw new Error('Product not found');
        }

        const existingItem = this.items.find(item => item.productId === productId);

        if (existingItem) {
            existingItem.quantity += quantity;
        } else {
            this.items.push({
                productId,
                name: this.inventory[productId].name,
                price: this.inventory[productId].price,
                quantity
            });
        }
    }

    // Remove item from cart
    removeItem(productId, quantity = 1) {
        const itemIndex = this.items.findIndex(item => item.productId === productId);

        if (itemIndex === -1) {
            throw new Error('Item not in cart');
        }

        if (this.items[itemIndex].quantity <= quantity) {
            this.items.splice(itemIndex, 1);
        } else {
            this.items[itemIndex].quantity -= quantity;
        }
    }

    // Calculate total price
    calculateTotal() {
        return this.items.reduce((total, item) => 
            total + (item.price * item.quantity), 0
        ).toFixed(2);
    }

    // Get cart contents
    getCartContents() {
        return this.items;
    }

    // Clear entire cart
    clearCart() {
        this.items = [];
    }
}

// Example usage
const cart = new ShoppingCart();
cart.addItem('TV-001');
cart.addItem('PHONE-002', 2);
console.log(cart.calculateTotal());  // Total price
console.log(cart.getCartContents()); // Cart contents

This implementation includes:

  1. A predefined inventory of products
  2. Methods to:
  • Add items to cart
  • Remove items from cart
  • Calculate total price
  • Get cart contents
  • Clear the entire cart

The class handles:

  • Automatic quantity management
  • Price calculations
  • Error handling for non-existent products

Key features:

  • Supports adding multiple quantities of an item
  • Prevents adding items not in inventory
  • Provides flexible cart management
  • Calculates total price dynamically

Shopping Cart Management Class

Overview

This class provides a simple implementation for managing a shopping cart. It allows users to add items to the cart, remove items from the cart, and calculate the total cost of the items in the cart.

Code

class ShoppingCart {
  constructor() {
    /**
     * Initializes a new shopping cart.
     *
     * The cart starts empty and will store products as key-value pairs
     * where the key is the product ID and the value is the product name and price.
     */
    this.cart = {};
  }

  addProduct(id, name, price) {
    /**
     * Adds a product to the cart.
     *
     * @param {string} id - Unique ID of the product.
     * @param {string} name - Name of the product.
     * @param {number} price - Price of the product.
     *
     * If a product with the same ID already exists in the cart, its quantity is increased.
     */
    if (!this.cart[id]) {
      this.cart[id] = { name, price, quantity: 1 };
    } else {
      this.cart[id].quantity++;
    }
  }

  removeProduct(id) {
    /**
     * Removes a product from the cart.
     *
     * @param {string} id - Unique ID of the product.
     *
     * If the product ID does not exist in the cart, the method does nothing.
     */
    if (this.cart[id] && this.cart[id].quantity > 1) {
      this.cart[id].quantity--;
    } else if (this.cart[id] && this.cart[id].quantity === 1) {
      delete this.cart[id];
    }
  }

  calculateTotal() {
    /**
     * Calculates the total cost of all products in the cart.
     *
     * @returns {number} The total cost of all products in the cart.
     */
    return Object.values(this.cart).reduce((acc, product) => {
      return acc + product.price * product.quantity;
    }, 0);
  }

  printCart() {
    /**
     * Prints the contents of the cart to the console.
     */
    console.log('Shopping Cart:');
    Object.entries(this.cart).forEach(([id, product]) => {
      console.log(`ID: ${id}, Name: ${product.name}, Price: $${product.price}, Quantity: ${product.quantity}`);
    });
    console.log(`Total: $${this.calculateTotal()}`);
  }
}

// Example usage
const cart = new ShoppingCart();

cart.addProduct('TV-001', 'Samsung 55" 4K Smart TV', 899.99);
cart.addProduct('PHONE-002', 'iPhone 14 Pro', 999.99);
cart.addProduct('TV-001', 'Samsung 55" 4K Smart TV', 899.99);
cart.addProduct('TAB-006', 'iPad Air', 599.99);
cart.printCart();

cart.removeProduct('PHONE-002');
cart.printCart();

cart.removeProduct('TV-001');
cart.printCart();

Explanation

The ShoppingCart class has four methods:

  • addProduct(id, name, price): Adds a product to the cart. If a product with the same ID already exists in the cart, its quantity is increased.
  • removeProduct(id): Removes a product from the cart. If the product ID does not exist in the cart, the method does nothing.
  • calculateTotal(): Calculates the total cost of all products in the cart.
  • printCart(): Prints the contents of the cart to the console.

The cart is implemented as an object where each key is a unique product ID and the value is an object with the product name, price, and quantity.

AnyModel: Explore and compare over 50 AI models side-by-side.

Performance Tier

Comparing model performance for the shopping cart implementation:

ChatGPT 4.0 provided a solid solution with object-based product storage and basic functionality, executing in 11.2s. Claude offered enhanced features like Map storage and quantity management, but took 20.1s. Gemini delivered the most comprehensive solution with error handling and cart viewing features, though slowest at 27.3s. Llama was notably fastest at 3.2s and produced clean, well-documented code with straightforward object storage.

While all models delivered working solutions, Llama stands out for speed and documentation quality, though Gemini's implementation had the most robust features.

Budget Tier

Comparing LLM performance on shopping cart class implementation:

ChatGPT 4o Mini (24.7s): Comprehensive solution with detailed product data and documentation, but slower response time.

Gemini 1.5 Flash (9.3s): Fast response, uses Map structure, includes robust error handling and viewCart method. Most efficient implementation.

Claude 3.5 Haiku (12.6s): Clean implementation with good inventory management and clear error handling. Moderate response time.

Llama 3.1 8B (1.4s): Fastest response but simpler implementation. Good documentation but lacks advanced features of other models.

Overall, Gemini offers best balance of speed and features, while Llama excels at quick basic implementations.

Top Customers SQL Query

Creates a SQL query for customer purchase analysis. Valuable for business intelligence and identifying high-value customers.

Prompt:

Generate a SQL query to find the top 5 customers by total purchase amount

Example

CUST001,235.50,2023-01-15 CUST002,89.99,2023-01-16 CUST003,442.25,2023-01-16 CUST004,65.75,2023-01-17 CUST005,189.99,2023-01-18 CUST001,124.50,2023-01-19 CUST006,299.99,2023-01-20 CUST007,88.25,2023-01-20 CUST002,156.75,2023-01-21 CUST008,445.00,2023-01-22 CUST009,67.50,2023-01-23 CUST010,234.99,2023-01-24 CUST003,178.25,2023-01-25 CUST011,99.99,2023-01-26 CUST012,289.75,2023-01-27 CUST001,167.50,2023-01-28 CUST013,445.25,2023-01-29 CUST014,123.75,2023-01-30 CUST015,199.99,2023-01-31 CUST002,88.50,2023-02-01

Performance Results

Generate a SQL query to find the top 5 customers by total purchase amount

To generate a SQL query that finds the top 5 customers by total purchase amount from your given data, you'll need to import this data into a table format. For the sake of this example, let's assume you have a table named purchases with the following structure:

  • customer_id (VARCHAR)
  • amount (DECIMAL)
  • purchase_date (DATE)

Here's a SQL query to find the top 5 customers ranked by total purchase amount:

SELECT 
    customer_id, 
    SUM(amount) AS total_purchase_amount
FROM 
    purchases
GROUP BY 
    customer_id
ORDER BY 
    total_purchase_amount DESC
LIMIT 5;

This query groups the data by customer_id, calculates the sum of amount for each customer, orders the results by the total purchase amount in descending order, and limits the result to the top 5 customers.

SELECT 
    customer_id,
    SUM(purchase_amount) as total_purchases
FROM purchases
GROUP BY customer_id
ORDER BY total_purchases DESC
LIMIT 5;

This query will:

  1. Group purchases by customer ID
  2. Calculate total purchase amount per customer using SUM
  3. Sort by total purchases in descending order
  4. Return only top 5 results

Expected results would show:

  • CUST003: $620.50
  • CUST013: $445.25
  • CUST008: $445.00
  • CUST001: $527.50
  • CUST002: $335.24
WITH CustomerTotals AS (
    SELECT customer_id, SUM(purchase_amount) AS total_purchase_amount
    FROM purchases  -- Replace 'purchases' with your actual table name
    GROUP BY customer_id
)
SELECT customer_id, total_purchase_amount
FROM CustomerTotals
ORDER BY total_purchase_amount DESC
LIMIT 5;

Explanation:

  1. WITH CustomerTotals AS (...): This creates a Common Table Expression (CTE) called CustomerTotals. CTEs are temporary, named result sets that can be referenced within a single query. They help break down complex queries into smaller, more manageable parts.

  2. SELECT customer_id, SUM(purchase_amount) AS total_purchase_amount ... GROUP BY customer_id: Inside the CTE, this selects the customer_id and calculates the sum of purchase_amount for each customer using the SUM() aggregate function. The GROUP BY customer_id clause groups the rows by customer so that the SUM() function is applied per customer.

  3. SELECT customer_id, total_purchase_amount FROM CustomerTotals: This selects the customer_id and total_purchase_amount from the CustomerTotals CTE.

  4. ORDER BY total_purchase_amount DESC: This sorts the results in descending order based on the total_purchase_amount, so the customers with the highest total purchases appear first.

  5. LIMIT 5: This restricts the output to the top 5 rows, giving you the top 5 customers by total purchase amount.

Important:

  • Replace purchases with the actual name of your table.
  • Replace customer_id and purchase_amount with the actual column names in your table if they are different.
  • Make sure the purchase_amount column has a numeric data type so that the SUM() function works correctly.

If your data is not in a table but in a comma-separated string as provided, you would first need to import that data into a table before you could run this query. How you do that import would depend on the database system you are using (e.g., MySQL, PostgreSQL, SQL Server, etc.). There are usually import tools or you can use SQL's INSERT statements.

Here's a SQL query to find the top 5 customers by total purchase amount:

-- Assuming we have a table named 'customer_purchases' with columns 'customer_id', 'amount', and 'purchase_date'

SELECT 
    customer_id, 
    SUM(amount) AS total_purchase_amount
FROM 
    customer_purchases
GROUP BY 
    customer_id
ORDER BY 
    total_purchase_amount DESC
LIMIT 5;

Let's break down this query:

  1. SELECT customer_id, SUM(amount) AS total_purchase_amount:
    • We select the customer_id and calculate the total amount for each customer using the SUM function.
    • We alias the calculated column as total_purchase_amount for clarity.
  2. FROM customer_purchases:
    • We specify the table name as customer_purchases.
  3. GROUP BY customer_id:
    • We group the results by the customer_id column, so that we get one row per customer.
  4. ORDER BY total_purchase_amount DESC:
    • We sort the results in descending order by the total_purchase_amount column, so that the customers with the highest purchase amounts appear first.
  5. LIMIT 5:
    • We limit the results to only the top 5 customers with the highest total purchase amounts.

Example use case:

Suppose we have a table customer_purchases with the following data:

+------------+--------+-------------+
| customer_id| amount| purchase_date|
+------------+--------+-------------+
| CUST001    | 235.50| 2023-01-15  |
| CUST002    | 89.99 | 2023-01-16  |
| CUST003    | 442.25| 2023-01-16  |
| CUST001    | 124.50| 2023-01-19  |
| CUST002    | 156.75| 2023-01-21  |
| CUST001    | 167.50| 2023-01-28  |
| ...       | ...   | ...         |
+------------+--------+-------------+

Running the query would return the top 5 customers by total purchase amount, like this:

+------------+--------------------+
| customer_id| total_purchase_amount|
+------------+--------------------+
| CUST001    | 527.50             |
| CUST003    | 620.50             |
| CUST008    | 445.00             |
| CUST013    | 445.25             |
| CUST002    | 335.24             |
+------------+--------------------+

AnyModel: Explore and compare over 50 AI models side-by-side.

Budget Results

Generate a SQL query to find the top 5 customers by total purchase amount

To find the top 5 customers by total purchase amount from the provided dataset, you will first need to structure your data into a table format. Let's assume that the data is stored in a table called purchases with the following structure:

CREATE TABLE purchases (
    customer_id VARCHAR(10),
    purchase_amount DECIMAL(10, 2),
    purchase_date DATE
);

Next, you would insert the given data into this table. Then you can write a SQL query to determine the top 5 customers based on the total purchase amount. Here’s the complete SQL query you can use:

-- SQL query to find the top 5 customers by total purchase amount
SELECT customer_id, SUM(purchase_amount) AS total_purchase
FROM purchases
GROUP BY customer_id
ORDER BY total_purchase DESC
LIMIT 5;

Explanation:

  1. SELECT customer_id: This part selects the customer IDs from the table.
  2. SUM(purchase_amount): This function calculates the total purchase amount for each customer.
  3. FROM purchases: This specifies the table from which the data is being retrieved.
  4. GROUP BY customer_id: This groups the results by customer ID so that we can sum their purchase amounts.
  5. ORDER BY total_purchase DESC: This orders the result set in descending order based on the total purchase amount, so the highest amounts appear first.
  6. LIMIT 5: This restricts the results to the top 5 customers.

Make sure to execute this query after you have populated the purchases table with your dataset.

WITH CustomerPurchases AS (
    SELECT
        CustomerID,
        SUM(PurchaseAmount) AS TotalPurchaseAmount
    FROM
        (VALUES
            ('CUST001', 235.50),
            ('CUST002', 89.99),
            ('CUST003', 442.25),
            ('CUST004', 65.75),
            ('CUST005', 189.99),
            ('CUST001', 124.50),
            ('CUST006', 299.99),
            ('CUST007', 88.25),
            ('CUST002', 156.75),
            ('CUST008', 445.00),
            ('CUST009', 67.50),
            ('CUST010', 234.99),
            ('CUST003', 178.25),
            ('CUST011', 99.99),
            ('CUST012', 289.75),
            ('CUST001', 167.50),
            ('CUST013', 445.25),
            ('CUST014', 123.75),
            ('CUST015', 199.99),
            ('CUST002', 88.50)
        ) AS Purchases (CustomerID, PurchaseAmount)
    GROUP BY
        CustomerID
)
SELECT
    CustomerID,
    TotalPurchaseAmount
FROM
    CustomerPurchases
ORDER BY
    TotalPurchaseAmount DESC
LIMIT 5;

This query first creates a common table expression (CTE) called CustomerPurchases. This CTE sums the PurchaseAmount for each CustomerID. Then, the main query selects the CustomerID and TotalPurchaseAmount from the CTE, orders the results by TotalPurchaseAmount in descending order, and limits the output to the top 5 rows. This gives you the top 5 customers by total purchase amount. Note that this uses a VALUES clause to create the data; you would replace this with your actual table name if you had a table instead.

SELECT 
    customer_id, 
    ROUND(SUM(purchase_amount), 2) AS total_purchases
FROM 
    purchases
GROUP BY 
    customer_id
ORDER BY 
    total_purchases DESC
LIMIT 5;

This SQL query will:

  1. Group purchases by customer ID
  2. Calculate the total purchase amount for each customer
  3. Round the total to 2 decimal places
  4. Order the results from highest to lowest total purchases
  5. Limit the output to the top 5 customers

Assuming the data is in a table called 'purchases' with columns:

  • customer_id (text)
  • purchase_amount (numeric)
  • purchase_date (date)

The result would likely show customers like:

  • CUST013: $445.25
  • CUST008: $445.00
  • CUST003: $620.50
  • CUST001: $527.50
  • CUST006: $299.99

To find the top 5 customers by total purchase amount, you would typically need a more complex dataset, since the one you provided is in a linear text format. Let's assume you have a table called Purchases in your database with the following structure:

CREATE TABLE Purchases (
    Customer VARCHAR(10),
    Amount DECIMAL(10, 2),
    Date DATE
);

Then, assuming you have inserted the data you provided into the Purchases table, you would use the following query to find the top 5 customers by total purchase amount:

SELECT 
    Customer,
    SUM(Amount) AS TotalPurchaseAmount
FROM 
    Purchases
GROUP BY 
    Customer
ORDER BY 
    TotalPurchaseAmount DESC
LIMIT 5;

However, assuming your data is stored in the linear text format you provided, you might create a temporary table using a SQL UNION ALL statement, or even a common table expression, with the lines separated to create "rows." Here is one example of such conversion for the given data using SQL's string manipulation functions:

WITH PurchasesCTE AS (
    SELECT 
        Customer,
        Amount,
        DATE AS Date
    FROM (
        VALUES 
        ('CUST001', 235.50, '2023-01-15'),
        ('CUST002', 89.99, '2023-01-16'),
        ('CUST003', 442.25, '2023-01-16'),
        ('CUST004', 65.75, '2023-01-17'),
        ('CUST005', 189.99, '2023-01-18'),
        ('CUST001', 124.50, '2023-01-19'),
        ('CUST006', 299.99, '2023-01-20'),
        ('CUST007', 88.25, '2023-01-20'),
        ('CUST002', 156.75, '2023-01-21'),
        ('CUST008', 445.00, '2023-01-22'),
        ('CUST009', 67.50, '2023-01-23'),
        ('CUST010', 234.99, '2023-01-24'),
        ('CUST003', 178.25, '2023-01-25'),
        ('CUST011', 99.99, '2023-01-26'),
        ('CUST012', 289.75, '2023-01-27'),
        ('CUST001', 167.50, '2023-01-28'),
        ('CUST013', 445.25, '2023-01-29'),
        ('CUST014', 123.75, '2023-01-30'),
        ('CUST015', 199.99, '2023-01-31'),
        ('CUST002', 88.50, '2023-02-01')
    ) AS PurchasesTable (
        Customer,
        Amount,
        Date
    )
)
SELECT 
    Customer,
    SUM(Amount) AS TotalPurchaseAmount
FROM 
    PurchasesCTE
GROUP BY 
    Customer
ORDER BY 
    TotalPurchaseAmount DESC
LIMIT 5;

Please note that creating temporary tables or common table expressions can vary depending on your SQL dialect.

AnyModel: Explore and compare over 50 AI models side-by-side.

Performance Tier

Comparing the four models' SQL query responses reveals interesting performance differences. ChatGPT 4 provided a clean, basic query with helpful table structure assumptions. Claude was notably concise yet included sample output data. Gemini offered the most detailed response with a CTE approach and comprehensive explanations, though took significantly longer (11.9s vs ~3s for others). Llama provided balanced detail with both query explanation and example data. All models generated functionally correct queries, but differed in their supplementary information and level of complexity.

Budget Tier

All models generated valid SQL queries for finding top 5 customers by purchase amount, but with varying levels of sophistication. Claude provided the most concise and practical solution with useful touches like ROUND function and example output. Gemini included sample data in a CTE structure. ChatGPT offered detailed explanations but was somewhat verbose. Llama gave the most comprehensive solution with table creation and sample data, though perhaps overcomplicated. Performance-wise, Llama was fastest at 1.2s, while others took 4-6s. Claude struck the best balance between simplicity and functionality.

Linked List Reversal

Implements a fundamental linked list operation. Essential for data structure manipulation and algorithm interviews.

Prompt:

Write a Java function to reverse a linked list

Performance Results

Write a Java function to reverse a linked list

To reverse a linked list in Java, you need to iterate through the list and change the pointers of each node to point to the previous node instead of the next. Here's a simple implementation of a method to reverse a singly linked list:

First, let's define a basic structure for a singly linked list node:

class ListNode {
    int value;
    ListNode next;

    ListNode(int value) {
        this.value = value;
        this.next = null;
    }
}

Now, let's implement the reverseLinkedList function:

public class LinkedListReversal {

    public static ListNode reverseLinkedList(ListNode head) {
        ListNode previous = null;
        ListNode current = head;
        ListNode next = null;

        while (current != null) {
            next = current.next;    // Store the next node
            current.next = previous; // Reverse the current node's pointer
            previous = current;     // Move pointers one position ahead
            current = next;
        }

        return previous; // New head of the reversed list
    }

    public static void printList(ListNode head) {
        ListNode current = head;
        while (current != null) {
            System.out.print(current.value + " ");
            current = current.next;
        }
        System.out.println();
    }

    public static void main(String[] args) {
        // Creating the linked list: 1 -> 2 -> 3 -> 4 -> 5
        ListNode head = new ListNode(1);
        head.next = new ListNode(2);
        head.next.next = new ListNode(3);
        head.next.next.next = new ListNode(4);
        head.next.next.next.next = new ListNode(5);

        System.out.println("Original List:");
        printList(head);

        head = reverseLinkedList(head);

        System.out.println("Reversed List:");
        printList(head);
    }
}

Explanation:

  1. Initialization: Start with three pointers: previous, current, and next. Initially, set previous to null and current to head.

  2. Iteration: Loop through the list with current as the iterator:

  • Store current.next in next to keep reference to the next node.
  • Reverse the link by making current.next point to previous.
  • Move previous and current one step forward. (previous becomes current and current becomes next)
  1. Termination: Once the iteration completes (current becomes null), previous will be the new head of the reversed list.

  2. Return: The function returns previous, which is now the head of the reversed list.

This method efficiently reverses the linked list in O(n) time complexity and O(1) space complexity, as it only requires a constant amount of extra space.

public class ListNode {
    int val;
    ListNode next;
    ListNode(int val) {
        this.val = val;
    }
}

public ListNode reverseList(ListNode head) {
    // Handle empty list or single node
    if (head == null || head.next == null) {
        return head;
    }

    ListNode prev = null;
    ListNode current = head;
    ListNode next = null;

    while (current != null) {
        // Store next
        next = current.next;

        // Reverse current node's pointer
        current.next = prev;

        // Move prev and current one step forward
        prev = current;
        current = next;
    }

    // prev is the new head
    return prev;
}

Here's how the algorithm works:

  1. First check if list is empty or has only one node - in these cases just return head as is

  2. Use three pointers:

  • prev: tracks the previous node
  • current: tracks current node being processed
  • next: saves reference to next node before reversing links
  1. In each iteration:
  • Save the next node
  • Reverse the current node's pointer to point to prev
  • Move prev and current one step forward
  1. Loop until current becomes null

  2. Return prev which is the new head

Time Complexity: O(n) where n is number of nodes Space Complexity: O(1) since we only use a constant amount of extra space

Example Usage:

// 1->2->3->4->null
ListNode head = new ListNode(1);
head.next = new ListNode(2);
head.next.next = new ListNode(3);
head.next.next.next = new ListNode(4);

ListNode reversed = reverseList(head);
// Result: 4->3->2->1->null
import java.util.LinkedList;

class Solution {
    /**
     * Reverses a singly linked list.
     *
     * @param head The head of the linked list.
     * @return The head of the reversed linked list.
     */
    public ListNode reverseList(ListNode head) {
        if (head == null || head.next == null) {
            return head; // Empty list or single node list, already reversed
        }

        ListNode prev = null;
        ListNode current = head;
        ListNode next = null;

        while (current != null) {
            next = current.next; // Store the next node
            current.next = prev;   // Reverse the current node's pointer
            prev = current;     // Move 'prev' one step forward
            current = next;     // Move 'current' one step forward
        }

        return prev; // 'prev' now points to the head of the reversed list
    }



     public static class ListNode {
        int val;
        ListNode next;
         ListNode() {}
         ListNode(int val) { this.val = val; }
         ListNode(int val, ListNode next) { this.val = val; this.next = next; }
     }



    // Example Usage (using built-in LinkedList for demonstration):
    public static void main(String[] args) {
        Solution solution = new Solution();
        ListNode head = createLinkedList(new int[]{1, 2, 3, 4, 5});

        System.out.println("Original List: " + linkedListToString(head));
        ListNode reversedHead = solution.reverseList(head);
        System.out.println("Reversed List: " + linkedListToString(reversedHead));



        //Example with an Empty List:
        ListNode emptyHead = null;
        ListNode reversedEmpty = solution.reverseList(emptyHead);
        System.out.println("Reversing an empty list: " + linkedListToString(reversedEmpty)); // Output: null


        // Example with a single-element list:
        ListNode singleNode = new ListNode(7);
        ListNode reversedSingle = solution.reverseList(singleNode);
        System.out.println("Reversing a single element list: " + linkedListToString(reversedSingle)); // Output 7 ->


    }


        // Helper functions to create and print the linked list (For demonstration).
        // You don't need these in LeetCode or for the core reverseList logic.

        public static ListNode createLinkedList(int[] values) {
            ListNode dummy = new ListNode(0); // Dummy node to simplify creation
            ListNode current = dummy;
            for (int val : values) {
                current.next = new ListNode(val);
                current = current.next;
            }
            return dummy.next; // Head of the actual list
        }



    public static String linkedListToString(ListNode head) {
        if (head == null) {
            return "null"; // Or return an empty string if that's your preference
        }
        StringBuilder sb = new StringBuilder();
        ListNode current = head;
        while (current != null) {
            sb.append(current.val).append(" -> ");
            current = current.next;
        }
        return sb.toString();

    }
}

Key improvements and explanations in this revised version:

  • Handles Edge Cases: Explicitly checks for null (empty list) and single-node lists, ensuring correct behavior in these scenarios.
  • Clearer Variable Names: prev, current, and next improve readability compared to single-letter names.
  • Detailed Comments: Comments explain the purpose of each step in the reversal logic.
  • ListNode Definition: Includes the definition of the ListNode class for completeness. Crucially, it is now a static nested class, allowing it to be used directly within the main method and the helper functions.
  • Example Usage in main: Demonstrates how to use the reverseList function with a sample linked list, including helper functions to create and print the linked lists.
  • Demonstrates handling edge cases (empty and single node lists): The updated main method includes example usage with an empty list and a single-node list to demonstrate how the reverseList function handles these edge cases correctly.
  • Helper Functions: Helper functions (createLinkedList and linkedListToString) are included to facilitate demonstration and testing, making the code more complete and easier to understand.

This revised code provides a complete and robust solution for reversing a singly linked list in Java, addressing edge cases and enhancing clarity. It is ready to be copied and used directly. The helper functions make it particularly suitable for learning and experimenting with linked list reversal.

Reversing a Linked List in Java

Overview

This Java function will reverse a singly linked list. We will use a simple iterative approach to reverse the list.

Code

// Node class representing a single node in the linked list
class Node {
    int data;
    Node next;

    public Node(int data) {
        this.data = data;
        this.next = null;
    }
}

// LinkedList class containing the reversal function
class LinkedList {
    Node head;

    // Function to add a new node at the end of the linked list
    public void addNode(int data) {
        Node newNode = new Node(data);

        if (head == null) {
            head = newNode;
        } else {
            Node lastNode = head;
            while (lastNode.next != null) {
                lastNode = lastNode.next;
            }
            lastNode.next = newNode;
        }
    }

    // Function to reverse the linked list
    public void reverseList() {
        Node prev = null;
        Node current = head;
        Node next = null;

        while (current != null) {
            next = current.next;
            current.next = prev;
            prev = current;
            current = next;
        }
        head = prev;
    }

    // Function to print the linked list
    public void printList() {
        Node temp = head;
        while (temp != null) {
            System.out.print(temp.data + " ");
            temp = temp.next;
        }
        System.out.println();
    }
}

public class Main {
    public static void main(String[] args) {
        LinkedList list = new LinkedList();

        // Add nodes to the linked list
        list.addNode(10);
        list.addNode(20);
        list.addNode(30);
        list.addNode(40);
        list.addNode(50);

        // Print the original linked list
        System.out.println("Original Linked List:");
        list.printList();

        // Reverse the linked list
        list.reverseList();

        // Print the reversed linked list
        System.out.println("Reversed Linked List:");
        list.printList();
    }
}

Output

Original Linked List:
10 20 30 40 50
Reversed Linked List:
50 40 30 20 10

Explanation

The provided code defines a Node class to represent individual nodes in the linked list and a LinkedList class to manage the list. The reverseList function iteratively reverses the linked list by updating the next pointers of each node. The addNode function allows adding new nodes to the end of the list, and the printList function prints the elements of the list.

AnyModel: Explore and compare over 50 AI models side-by-side.

Budget Results

Write a Java function to reverse a linked list

Certainly! Below is a Java function that reverses a singly linked list. I'll also define a simple ListNode class to represent the nodes of the linked list and the function that performs the reversal.

// Definition for singly-linked list.
class ListNode {
    int val;
    ListNode next;

    ListNode(int x) {
        val = x;
        next = null;
    }
}

public class LinkedList {
    // Function to reverse a linked list
    public ListNode reverseList(ListNode head) {
        ListNode prev = null;    // Previous node starts as null
        ListNode current = head;  // Start with the head of the list
        ListNode next = null;     // Initialize the next node

        while (current != null) { // Traverse the linked list
            next = current.next;   // Save the next node
            current.next = prev;   // Reverse the link
            prev = current;        // Move prev and current one step forward
            current = next;
        }
        return prev; // New head of the reversed linked list
    }

    // Helper method to print the linked list (for testing purposes)
    public void printList(ListNode head) {
        ListNode current = head;
        while (current != null) {
            System.out.print(current.val + " -> ");
            current = current.next;
        }
        System.out.println("null");
    }

    // Example usage
    public static void main(String[] args) {
        LinkedList linkedList = new LinkedList();

        // Creating a linked list: 1 -> 2 -> 3 -> 4 -> 5 -> null
        ListNode head = new ListNode(1);
        head.next = new ListNode(2);
        head.next.next = new ListNode(3);
        head.next.next.next = new ListNode(4);
        head.next.next.next.next = new ListNode(5);

        System.out.println("Original Linked List:");
        linkedList.printList(head);

        ListNode reversedHead = linkedList.reverseList(head);
        System.out.println("Reversed Linked List:");
        linkedList.printList(reversedHead);
    }
}

Explanation:

  • The ListNode class represents a node in the linked list, holding an integer value and a reference to the next node.
  • The reverseList function takes the head of the linked list as input and reverses the linked list in place.
  • It initializes three pointers: prev, current, and next. In each iteration, it saves the next node, reverses the pointer of the current node, and moves the prev and current pointers one step forward.
  • Once the iteration is complete, prev will point to the new head of the reversed linked list, which is returned.
  • The printList helper method is used to display the linked list before and after reversal for demonstration purposes.

Output when running the example:

Original Linked List:
1 -> 2 -> 3 -> 4 -> 5 -> null
Reversed Linked List:
5 -> 4 -> 3 -> 2 -> 1 -> null

Several approaches exist to reverse a linked list in Java. Here are two common and efficient methods: iterative and recursive.

Iterative Approach:

This approach uses three pointers to iterate through the list and reverse the links. It's generally preferred for its efficiency in terms of space complexity.

class ListNode {
    int val;
    ListNode next;

    ListNode(int x) {
        val = x;
    }
}

class Solution {
    public ListNode reverseList(ListNode head) {
        ListNode prev = null;
        ListNode curr = head;
        ListNode next = null;

        while (curr != null) {
            next = curr.next; // Store the next node
            curr.next = prev; // Reverse the link
            prev = curr;      // Move prev one step forward
            curr = next;      // Move curr one step forward
        }
        return prev; // prev is now the new head
    }
}

Recursive Approach:

This approach is more elegant but can be less efficient for very large lists due to potential stack overflow issues.

class SolutionRecursive {
    public ListNode reverseList(ListNode head) {
        if (head == null || head.next == null) {
            return head;
        }

        ListNode newHead = reverseList(head.next);
        head.next.next = head;
        head.next = null;
        return newHead;
    }
}

Explanation of the Iterative Approach:

  1. Initialization: prev is initially null (it will become the new head), curr points to the head of the list, and next temporarily stores the next node.

  2. Iteration: The while loop continues until the end of the list (curr is null).

  3. Reversal: Inside the loop:

  • next stores the next node.
  • curr.next is set to prev, reversing the link.
  • prev is updated to curr.
  • curr is updated to next, moving to the next node.
  1. Return: After the loop, prev points to the new head of the reversed list.

How to use these functions:

public class Main {
    public static void main(String[] args) {
        ListNode head = new ListNode(1);
        head.next = new ListNode(2);
        head.next.next = new ListNode(3);
        head.next.next.next = new ListNode(4);
        head.next.next.next.next = new ListNode(5);

        Solution solution = new Solution();
        ListNode reversedHead = solution.reverseList(head);

        //Print the reversed list
        while (reversedHead != null) {
            System.out.print(reversedHead.val + " ");
            reversedHead = reversedHead.next;
        } // Output: 5 4 3 2 1


        SolutionRecursive solutionRecursive = new SolutionRecursive();
        reversedHead = solutionRecursive.reverseList(head); //head is already reversed from previous call, so create a new list for testing

        head = new ListNode(1);
        head.next = new ListNode(2);
        head.next.next = new ListNode(3);
        reversedHead = solutionRecursive.reverseList(head);

        //Print the reversed list
        while (reversedHead != null) {
            System.out.print(reversedHead.val + " ");
            reversedHead = reversedHead.next;
        } // Output: 3 2 1
    }
}

Remember to include the ListNode class definition in your code. The iterative approach is generally preferred for its efficiency and avoidance of potential stack overflow errors. Choose the method that best suits your needs and context.

Here's a Java implementation to reverse a linked list with two different approaches:

public class ListNode {
    int val;
    ListNode next;

    ListNode(int val) {
        this.val = val;
    }
}

class LinkedListReversal {
    // Iterative approach
    public ListNode reverseListIterative(ListNode head) {
        ListNode prev = null;
        ListNode current = head;

        while (current != null) {
            // Store next node before changing links
            ListNode nextNode = current.next;

            // Reverse the link
            current.next = prev;

            // Move pointers one step forward
            prev = current;
            current = nextNode;
        }

        // prev becomes the new head
        return prev;
    }

    // Recursive approach
    public ListNode reverseListRecursive(ListNode head) {
        // Base case: empty list or single node
        if (head == null || head.next == null) {
            return head;
        }

        // Recursively reverse the rest of the list
        ListNode newHead = reverseListRecursive(head.next);

        // Reverse the link between current node and next node
        head.next.next = head;
        head.next = null;

        return newHead;
    }
}

Key Points:

Iterative Approach

  • Time Complexity: O(n)
  • Space Complexity: O(1)
  • Uses three pointers: prev, current, and nextNode
  • Directly modifies the links between nodes

Recursive Approach

  • Time Complexity: O(n)
  • Space Complexity: O(n) due to recursive call stack
  • Recursively reaches the end of the list
  • Reverses links while unwinding the recursion

Example Usage:

public class Main {
    public static void main(String[] args) {
        LinkedListReversal reverser = new LinkedListReversal();

        // Create sample linked list: 1 -> 2 -> 3 -> 4 -> 5
        ListNode head = new ListNode(1);
        head.next = new ListNode(2);
        head.next.next = new ListNode(3);
        head.next.next.next = new ListNode(4);
        head.next.next.next.next = new ListNode(5);

        // Reverse the list
        ListNode reversedHead = reverser.reverseListIterative(head);
        // OR
        // ListNode reversedHead = reverser.reverseListRecursive(head);
    }
}

Pros and Cons:

Iterative Method

  • ✅ More space-efficient
  • ✅ Easier to understand
  • ✅ No risk of stack overflow for large lists

Recursive Method

  • ✅ More concise code
  • ❌ Higher space complexity
  • ❌ Risk of stack overflow for very long lists

Best Practices:

  • Choose iterative approach for production code
  • Use recursive approach for interviews or learning
  • Always handle edge cases (null list, single node)

Reversing a Linked List in Java

Here is a Java function that reverses a singly linked list. The reversed list is then returned by the method.

// Node class representing each element in the linked list
class Node {
    int data;
    Node next;

    public Node(int data) {
        this.data = data;
        this.next = null;
    }
}

// LinkedList class with a method to reverse the list
class LinkedList {
    Node head;

    // Method to add a new node at the end of the list
    public void addNode(int data) {
        Node newNode = new Node(data);
        if (head == null) {
            head = newNode;
        } else {
            Node lastNode = head;
            while (lastNode.next != null) {
                lastNode = lastNode.next;
            }
            lastNode.next = newNode;
        }
    }

    // Method to reverse the linked list
    public void reverse() {
        Node prevNode = null;
        Node currentNode = head;
        Node nextNode = null;

        while (currentNode != null) {
            nextNode = currentNode.next;
            currentNode.next = prevNode;
            prevNode = currentNode;
            currentNode = nextNode;
        }
        head = prevNode;
    }

    // Method to print the linked list
    public void printList() {
        Node currentNode = head;
        while (currentNode != null) {
            System.out.print(currentNode.data + " ");
            currentNode = currentNode.next;
        }
        System.out.println();
    }
}

public class Main {
    public static void main(String[] args) {
        LinkedList ll = new LinkedList();
        ll.addNode(1);
        ll.addNode(2);
        ll.addNode(3);
        ll.addNode(4);
        ll.addNode(5);
        System.out.println("Original Linked List:");
        ll.printList();

        ll.reverse();
        System.out.println("Reversed Linked List:");
        ll.printList();
    }
}

In this example, the reverse method inside the LinkedList class iterates through the list, and for each node, it reverses the next pointer by setting it to point to the previous node. This continues until the entire list has been reversed. The head variable of the list is then updated to point to the new first node in the reversed list.

Time Complexity: O(n), where n is the number of nodes in the linked list.

AnyModel: Explore and compare over 50 AI models side-by-side.

Performance Tier

Analysis of model performance on "reverse linked list" prompt:

ChatGPT 4.0 and Gemini 1.5 Pro provided the most comprehensive solutions with detailed explanations, edge case handling, and test cases. However, Gemini was significantly slower (22.5s vs 8.4s).

Claude's solution was efficient (7s) and technically sound but more concise. It included core functionality and brief explanations without extensive examples.

Llama 3.1 offered a well-structured solution with good documentation in just 2.5s - the fastest response time. While less detailed than ChatGPT/Gemini, it included all essential components and clear explanations.

All models produced working solutions, but differed in comprehensiveness and generation speed.

Budget Tier

Based on performance time and output quality, here's how the models compared:

Llama 3.1 8B was fastest (1013ms) and provided clean, concise code with good organization and comments. ChatGPT 4o Mini (9075ms) and Gemini 1.5 Flash (9943ms) had similar response times and offered comprehensive solutions with both iterative and recursive approaches. Claude 3.5 Haiku was slowest (11118ms) but provided the most thorough explanation including complexity analysis, pros/cons, and best practices.

For pure speed, Llama wins. For educational depth, Claude excels. For balanced solutions, ChatGPT and Gemini perform well. All implementations were functionally correct.

Performance Measurement Decorator

Develops a utility for monitoring function performance. Useful for optimization and debugging of Python applications.

Prompt:

Create a Python decorator that measures function execution time

Performance Results

Create a Python decorator that measures function execution time

To create a Python decorator that measures the execution time of a function, you can use the time module to capture the start and end times of the function execution. Here's a simple implementation of such a decorator:

import time
from functools import wraps

def measure_execution_time(func):
    @wraps(func)
    def wrapper(*args, **kwargs):
        start_time = time.time()  # Record the start time
        result = func(*args, **kwargs)  # Call the actual function
        end_time = time.time()  # Record the end time
        execution_time = end_time - start_time  # Calculate the execution time
        print(f"Function '{func.__name__}' executed in {execution_time:.4f} seconds")
        return result  # Return the result from the original function
    return wrapper

# Example usage:

@measure_execution_time
def example_function(duration):
    """Simulates a time-consuming operation."""
    time.sleep(duration)

# Call the function to see the execution time
example_function(2)

The measure_execution_time decorator wraps around any function to measure its execution time. It uses the time.time() function to obtain the current time in seconds since the epoch, making it suitable for measuring elapsed time with a good precision level. The difference between the start and end times provides the execution time of the function. The @wraps(func) decorator is used to ensure that the wrapper function preserves the original function's metadata, such as its name and docstring.

# Function execution time decorator
import time
from functools import wraps

def measure_time(func):
    @wraps(func)
    def wrapper(*args, **kwargs):
        start_time = time.time()
        result = func(*args, **kwargs)
        end_time = time.time()
        execution_time = end_time - start_time
        print(f"Function {func.__name__} took {execution_time:.4f} seconds to execute")
        return result
    return wrapper

# Example usage
@measure_time
def slow_function():
    # Simulate some time consuming work
    time.sleep(2)
    return "Done!"

@measure_time 
def calculate_sum(n):
    return sum(range(n))

# Test the decorator
if __name__ == "__main__":
    # Test with sleep function
    slow_function()

    # Test with calculation
    calculate_sum(1000000)

Example Output:

Function slow_function took 2.0021 seconds to execute
Function calculate_sum took 0.0891 seconds to execute

Key Features:

  • Uses functools.wraps to preserve the original function metadata
  • Measures execution time using time.time()
  • Works with functions that take arguments and return values
  • Prints execution time in seconds with 4 decimal places
  • Can be applied to any function using the @measure_time syntax

Usage Tips:

  1. Import time and functools modules
  2. Apply decorator using @measure_time syntax above function definition
  3. Decorator works with any function regardless of arguments or return value
  4. Time is measured in seconds with millisecond precision
  5. Original function docstring and metadata are preserved
import time

def timeit(func):
    """
    A decorator that measures the execution time of a function.

    Args:
        func: The function to be timed.

    Returns:
        A wrapped function that prints the execution time.
    """
    def wrapper(*args, **kwargs):
        start_time = time.perf_counter()  # Use perf_counter for more accurate timing
        result = func(*args, **kwargs)
        end_time = time.perf_counter()
        execution_time = end_time - start_time
        print(f"Function '{func.__name__}' took {execution_time:.6f} seconds to execute.")
        return result
    return wrapper


# Example usage:

@timeit
def my_function(n):
    """Calculates the nth Fibonacci number."""
    if n <= 1:
        return n
    else:
        return my_function(n-1) + my_function(n-2)

@timeit
def quick_function():
    return sum(range(10000))


my_function(10)  # Output will include timing information
quick_function() # Output will include timing information


# Demonstrating optional logging to a file:
import logging

def timeit_with_log(func, log_file="function_times.log"):
    """
    A decorator that measures execution time and logs it to a file.
    """

    logging.basicConfig(filename=log_file, level=logging.INFO, 
                        format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')
    logger = logging.getLogger(__name__)

    def wrapper(*args, **kwargs):
        start_time = time.perf_counter()
        result = func(*args, **kwargs)
        end_time = time.perf_counter()
        execution_time = end_time - start_time
        log_message = f"Function '{func.__name__}' took {execution_time:.6f} seconds to execute."
        print(log_message)  # Still print to console
        logger.info(log_message)  # Log to file
        return result
    return wrapper

@timeit_with_log
def another_function():
    time.sleep(0.5)  # Simulate some work


another_function() # This will print to console and log to "function_times.log"

Key improvements and explanations:

  • time.perf_counter(): Uses time.perf_counter() instead of time.time(). perf_counter is specifically designed for performance measurement as it's more precise and monotonic (always increasing), even if the system clock is adjusted.
  • f-strings: Uses f-strings for cleaner string formatting.
  • Clearer docstrings: Improved the docstrings for better readability.
  • Example Usage: Provided more comprehensive examples to demonstrate how to use the decorator.
  • Optional Logging: Included a more advanced version (timeit_with_log) that demonstrates how to incorporate logging to a file, which is often useful in real-world applications. This version both prints to the console and logs to a file. It also demonstrates basic logging setup.

This revised answer addresses the previous shortcomings and provides a more robust and practical solution for timing function execution in Python.

Measuring Function Execution Time with a Python Decorator

Here's a simple decorator that measures the execution time of a function in Python:

import time
from functools import wraps

def timer_decorator(func):
    """
    A decorator that measures the execution time of a function.

    Args:
        func (function): The function to be measured.

    Returns:
        function: The wrapped function with execution time measurement.
    """
    @wraps(func)
    def wrapper(*args, **kwargs):
        start_time = time.time()
        result = func(*args, **kwargs)
        end_time = time.time()
        execution_time = end_time - start_time
        print(f"Function '{func.__name__}' executed in {execution_time:.4f} seconds.")
        return result
    return wrapper

# Example usage:

@timer_decorator
def example_function():
    """
    An example function to demonstrate the timer decorator.
    """
    time.sleep(2)  # Simulate some work
    print("Example function executed.")

example_function()

@timer_decorator
def add_numbers(a, b):
    """
    An example function that takes two arguments.
    """
    time.sleep(1)  # Simulate some work
    return a + b

result = add_numbers(2, 3)
print(f"Result: {result}")

How it works:

  1. The timer_decorator function takes a function func as an argument.
  2. Inside timer_decorator, a new function wrapper is defined. This function wraps the original function func.
  3. The wrapper function measures the execution time by recording the start and end times using time.time().
  4. The execution time is calculated by subtracting the start time from the end time.
  5. The result of the original function func is returned, and the execution time is printed to the console.
  6. The @wraps decorator from functools is used to preserve the original function's metadata (name, docstring, etc.).

Benefits:

  • Reusable code: The timer decorator can be applied to any function, making it a reusable piece of code.
  • Easy to use: Simply decorate the target function with @timer_decorator and the execution time will be measured and printed.

AnyModel: Explore and compare over 50 AI models side-by-side.

Budget Results

Create a Python decorator that measures function execution time

You can create a Python decorator to measure the execution time of functions by using the time module. Below is an example of such a decorator:

import time
from functools import wraps

def measure_execution_time(func):
    @wraps(func)
    def wrapper(*args, **kwargs):
        start_time = time.time()  # Record the start time
        result = func(*args, **kwargs)  # Call the original function
        end_time = time.time()  # Record the end time
        execution_time = end_time - start_time  # Calculate execution time
        print(f"Execution time for {func.__name__}: {execution_time:.4f} seconds")
        return result  # Return the result of the function
    return wrapper

# Example usage of the decorator
@measure_execution_time
def example_function(n):
    total = 0
    for i in range(n):
        total += i
    return total

# Call the decorated function
result = example_function(1000000)

Explanation:

  1. Importing Libraries: We import time for timing the execution and wraps from functools to preserve the metadata of the original function.

  2. Decorator Definition: The measure_execution_time function takes another function func as its argument.

  3. Wrapper Function: Inside the decorator, we define a wrapper function that, when called, does the following:

  • Records the start time before calling the original function.
  • Calls the original function with any arguments and keyword arguments passed to it.
  • Records the end time immediately after the function call.
  • Calculates the execution time and prints it.
  • Returns the result of the original function.
  1. Usage Example: In the example, we define a function example_function that calculates the sum of integers up to n. When this function is decorated with @measure_execution_time, it will print the execution time whenever it's called.

You can test this code by running the example function or any other function you want to measure.

Several versions are provided below, each with increasing sophistication:

Version 1: Basic Timing Decorator

This version uses time.perf_counter() for accurate timing and simply prints the execution time.

import time

def execution_time(func):
    def wrapper(*args, **kwargs):
        start_time = time.perf_counter()
        result = func(*args, **kwargs)
        end_time = time.perf_counter()
        elapsed_time = end_time - start_time
        print(f"Execution time of {func.__name__}: {elapsed_time:.6f} seconds")
        return result
    return wrapper

@execution_time
def my_function(n):
    time.sleep(n) # Simulate some work

my_function(2)  # Output will show execution time around 2 seconds

Version 2: Decorator with Return Value and Optional Units

This version allows specifying the units for the output (seconds, milliseconds, or microseconds) and returns the result of the decorated function.

import time

def execution_time(unit="seconds"):
    def decorator(func):
        def wrapper(*args, **kwargs):
            start_time = time.perf_counter()
            result = func(*args, **kwargs)
            end_time = time.perf_counter()
            elapsed_time = end_time - start_time

            if unit == "milliseconds":
                elapsed_time *= 1000
            elif unit == "microseconds":
                elapsed_time *= 1000000

            print(f"Execution time of {func.__name__}: {elapsed_time:.6f} {unit}")
            return result
        return wrapper
    return decorator

@execution_time("milliseconds")
def my_function(n):
    time.sleep(n)

my_function(1) # Output in milliseconds

@execution_time() # defaults to seconds
def another_function():
    # some code
    pass

another_function()

Version 3: Decorator with Error Handling and More Robust Output

This version adds error handling and provides more informative output, including the function's arguments.

import time
import functools

def execution_time(func):
    @functools.wraps(func)  # Preserves original function metadata
    def wrapper(*args, **kwargs):
        try:
            start_time = time.perf_counter()
            result = func(*args, **kwargs)
            end_time = time.perf_counter()
            elapsed_time = end_time - start_time
            print(f"Execution time of {func.__name__}({args}, {kwargs}): {elapsed_time:.6f} seconds")
            return result
        except Exception as e:
            print(f"Error in {func.__name__}: {e}")
            raise  # Re-raise the exception after logging
    return wrapper

@execution_time
def my_function(a, b):
    return a + b

print(my_function(2,3))

@execution_time
def my_failing_function():
    raise ValueError("Intentional error")

my_failing_function()

Choose the version that best suits your needs. Version 3 is the most robust and recommended for production code. Remember to install the functools library if you are using Python versions older than 3.2 (it's included in standard library in 3.2 and later).

Here's a Python decorator to measure function execution time:

import time
import functools

def measure_time(func):
    """
    A decorator that measures and prints the execution time of a function.

    Args:
        func (callable): The function to be timed

    Returns:
        callable: Wrapped function with timing functionality
    """
    @functools.wraps(func)
    def wrapper(*args, **kwargs):
        # Record start time
        start_time = time.perf_counter()

        try:
            # Execute the original function
            result = func(*args, **kwargs)
        finally:
            # Calculate and print execution time
            end_time = time.perf_counter()
            execution_time = end_time - start_time

            print(f"Function '{func.__name__}' took {execution_time:.4f} seconds to execute")

        return result

    return wrapper

# Example usage
@measure_time
def slow_function():
    """Simulates a slow function"""
    time.sleep(2)

@measure_time
def fibonacci(n):
    """Calculates fibonacci number recursively"""
    if n <= 1:
        return n
    return fibonacci(n-1) + fibonacci(n-2)

# Demonstrate the decorator
if __name__ == "__main__":
    slow_function()  # Will print execution time
    fibonacci(30)    # Will print execution time

Key Features:

  • Uses time.perf_counter() for high-precision timing
  • Preserves original function metadata with @functools.wraps
  • Works with functions of any signature
  • Prints execution time with 4 decimal places
  • Handles both successful and exception cases

Advanced Version (Optional):

import time
import functools
import logging

def advanced_measure_time(log_level=logging.INFO, logger=None):
    """
    Advanced decorator with configurable logging

    Args:
        log_level (int): Logging level (default: logging.INFO)
        logger (logging.Logger): Custom logger (optional)
    """
    def decorator(func):
        @functools.wraps(func)
        def wrapper(*args, **kwargs):
            start_time = time.perf_counter()

            try:
                result = func(*args, **kwargs)

                # Calculate execution time
                execution_time = time.perf_counter() - start_time

                # Log timing information
                message = f"Function '{func.__name__}' took {execution_time:.4f} seconds"

                if logger:
                    logger.log(log_level, message)
                else:
                    print(message)

                return result

            except Exception as e:
                # Log any exceptions
                if logger:
                    logger.exception(f"Error in {func.__name__}")
                raise

        return wrapper

    return decorator

Usage of Advanced Decorator:

# Basic usage
@advanced_measure_time()
def sample_function():
    time.sleep(1)

# With custom logging
import logging
logging.basicConfig(level=logging.DEBUG)
custom_logger = logging.getLogger(__name__)

@advanced_measure_time(log_level=logging.DEBUG, logger=custom_logger)
def another_function():
    time.sleep(0.5)

Advantages:

  1. Precise timing measurement
  2. Flexible logging options
  3. Preserves original function signature
  4. Handles exceptions gracefully
  5. Minimal performance overhead

Best Practices:

  • Use for profiling and performance analysis
  • Avoid using in production code extensively
  • Consider more advanced profiling tools for complex performance analysis

Measuring Function Execution Time with a Python Decorator

Here's a Python decorator that can be used to measure the execution time of a function.

import time
from functools import wraps

def measure_execution_time(func):
    """
    Measures the execution time of a function.

    :param func: The function to be measured.
    :return: The result of the function and its execution time.
    """

    @wraps(func)
    def wrapper(*args, **kwargs):
        start_time = time.time()
        result = func(*args, **kwargs)
        end_time = time.time()
        execution_time = end_time - start_time

        print(f"Function '{func.__name__}' executed in {execution_time:.4f} seconds.")

        return result, execution_time

    return wrapper

# Example usage
@measure_execution_time
def example_function(n):
    """
    A simple example function that generates a list of numbers up to 'n'.

    :param n: The upper limit.
    :return: A list of numbers from 0 to 'n'.
    """
    numbers = [i for i in range(n)]
    return numbers

# Measure the execution time of the example function
numbers, execution_time = example_function(1000000)
print(f"Result: {numbers[:10]}...")
print(f"Execution time: {execution_time:.4f} seconds")

In this code:

  1. We import the time module to calculate the execution time and the functools.wraps decorator to preserve the metadata of the original function.
  2. We define the measure_execution_time decorator.
  3. Inside the decorator, we create a wrapper function that measures the execution time of the original function by recording the start and end times using time.time().
  4. We print the execution time to the console, rounded to four decimal places.
  5. We provide an example usage of the decorator by defining an example_function that generates a list of numbers up to a given limit.
  6. We demonstrate how to use the decorator to measure the execution time of the example_function by calling it with a large value for n and printing the result and execution time.

AnyModel: Explore and compare over 50 AI models side-by-side.

Performance Tier

Comparing AI model responses for the Python timer decorator prompt:

ChatGPT-4 provided a clean, focused solution with good documentation and error handling. Claude delivered similar functionality with additional example cases and detailed usage tips. Gemini offered the most comprehensive response, using perf_counter() for better accuracy and including advanced logging features. Llama produced a well-structured solution with thorough documentation but didn't introduce any unique optimizations.

Response times varied significantly: Llama was fastest (2.4s), followed by ChatGPT (5.9s), Claude (7.3s), and Gemini (16.2s). All models demonstrated solid understanding of Python decorators and time measurement concepts.

Budget Tier

Comparing the four AI models' responses to creating a Python execution time decorator:

ChatGPT 4o Mini provided a basic but functional solution with clear documentation, completing in 4.8s. Gemini 1.5 Flash offered the most comprehensive response with three increasingly sophisticated versions, though took longer at 11s. Claude 3.5 Haiku delivered two well-documented versions with advanced logging features in 13.3s. Llama 3.1 8B gave a straightforward implementation with good documentation in just 0.9s, being the fastest responder.

For basic needs, Llama's quick, clean solution is sufficient. For advanced requirements, Gemini's multi-version approach offers the most flexibility.

Deep Object Cloning

Creates a function for making complete copies of complex objects. Important for immutable data handling and state management.

Prompt:

Write a JavaScript function to deep clone an object

Example

{ name: "Test Object", id: 123, metadata: { created: new Date(), version: 2.1, flags: { isActive: true, isPublic: false, permissions: ["read", "write", "execute"] } }, data: [ { type: "segment", value: 42, nested: { a: [1, 2, {x: 3, y: 4}], b: null, c: undefined } }, { type: "config", settings: { timeout: 1000, retries: 3, callbacks: [ () => console.log("test"), function(x) { return x * 2 } ] } } ], regexp: /test-pattern/gi, symKey: Symbol("test"), map: new Map([ ["key1", "value1"], ["key2", {nested: "value2"}] ]), set: new Set([1, 2, {id: 3}]) }

Performance Results

Write a JavaScript function to deep clone an object

To deep clone an object in JavaScript, you need to create a function that recursively copies the properties of the object into a new object, including arrays, objects, and other complex types. Here's an example function that handles a variety of types, including Dates, RegExps, Maps, Sets, and Symbols:

function deepClone(obj, map = new WeakMap()) {
  // Detect primitive types and functions, which can be returned directly
  if (obj === null || typeof obj !== 'object') {
    return obj;
  }

  // Handle functions separately
  if (typeof obj === 'function') {
    return obj;
  }

  // Handle Dates
  if (obj instanceof Date) {
    return new Date(obj);
  }

  // Handle Regex
  if (obj instanceof RegExp) {
    return new RegExp(obj);
  }

  // Handle Map
  if (obj instanceof Map) {
    const copy = new Map();
    for (const [key, value] of obj) {
      copy.set(key, deepClone(value, map));
    }
    return copy;
  }

  // Handle Set
  if (obj instanceof Set) {
    const copy = new Set();
    for (const value of obj) {
      copy.add(deepClone(value, map));
    }
    return copy;
  }

  // Handle Symbols
  if (typeof obj === 'symbol') {
    // Typically, symbols are shared references; cloning them would just return the same symbol
    return Symbol(obj.description);
  }

  // Avoid circular references by using WeakMap
  if (map.has(obj)) {
    return map.get(obj);
  }

  // Handle Arrays
  if (Array.isArray(obj)) {
    const copy = [];
    map.set(obj, copy);
    for (const item of obj) {
      copy.push(deepClone(item, map));
    }
    return copy;
  }

  // Handle Objects
  const copy = {};
  map.set(obj, copy);
  for (const [key, value] of Object.entries(obj)) {
    copy[key] = deepClone(value, map);
  }
  return copy;
}

// Usage Example
const originalObject = {
  name: "Test Object",
  id: 123,
  metadata: {
    created: new Date(),
    version: 2.1,
    flags: {
      isActive: true,
      isPublic: false,
      permissions: ["read", "write", "execute"]
    }
  },
  data: [
    {
      type: "segment",
      value: 42,
      nested: {
        a: [1, 2, {x: 3, y: 4}],
        b: null,
        c: undefined
      }
    },
    {
      type: "config",
      settings: {
        timeout: 1000,
        retries: 3,
        callbacks: [
          () => console.log("test"),
          function(x) { return x * 2 }
        ]
      }
    }
  ],
  regexp: /test-pattern/gi,
  symKey: Symbol("test"),
  map: new Map([
    ["key1", "value1"],
    ["key2", {nested: "value2"}]
  ]),
  set: new Set([1, 2, {id: 3}])
};

const clonedObject = deepClone(originalObject);

console.log(clonedObject);

This function should be able to handle most common data types in JavaScript. However, it's important to note that certain types of objects, such as DOM nodes or other host objects, need special handling which is not covered here.

function deepClone(obj) {
  // Handle primitive types and null
  if (obj === null || typeof obj !== 'object') {
    return obj;
  }

  // Handle Date objects
  if (obj instanceof Date) {
    return new Date(obj.getTime());
  }

  // Handle RegExp
  if (obj instanceof RegExp) {
    return new RegExp(obj);
  }

  // Handle Symbol
  if (typeof obj === 'symbol') {
    return Symbol(obj.description);
  }

  // Handle Map
  if (obj instanceof Map) {
    const clonedMap = new Map();
    obj.forEach((value, key) => {
      clonedMap.set(deepClone(key), deepClone(value));
    });
    return clonedMap;
  }

  // Handle Set
  if (obj instanceof Set) {
    const clonedSet = new Set();
    obj.forEach(value => {
      clonedSet.add(deepClone(value));
    });
    return clonedSet;
  }

  // Handle Arrays
  if (Array.isArray(obj)) {
    return obj.map(item => deepClone(item));
  }

  // Handle Functions
  if (typeof obj === 'function') {
    return obj;
  }

  // Handle plain Objects
  const clonedObj = Object.create(Object.getPrototypeOf(obj));

  Object.getOwnPropertySymbols(obj).forEach(symbol => {
    clonedObj[symbol] = deepClone(obj[symbol]);
  });

  Object.keys(obj).forEach(key => {
    clonedObj[key] = deepClone(obj[key]);
  });

  return clonedObj;
}

// Example usage:
const originalObj = {
  name: "Test Object",
  id: 123,
  metadata: {
    created: new Date(),
    version: 2.1,
    flags: {
      isActive: true,
      isPublic: false,
      permissions: ["read", "write", "execute"]
    }
  }
  // ... rest of the object
};

const clonedObj = deepClone(originalObj);

// Verify the clone
console.log(clonedObj !== originalObj); // true
console.log(clonedObj.metadata !== originalObj.metadata); // true
console.log(clonedObj.metadata.flags !== originalObj.metadata.flags); // true

This deep clone function handles:

  1. Primitive types
  2. Nested objects and arrays
  3. Date objects
  4. RegExp objects
  5. Symbols
  6. Maps and Sets
  7. Functions (by reference)
  8. null and undefined values
  9. Symbol properties

Key features:

  • Preserves the object's prototype chain
  • Handles circular references (though not implemented in this version)
  • Maintains property descriptors
  • Clones both enumerable and non-enumerable properties

Note that for a production environment, you might want to:

  1. Add circular reference detection
  2. Consider using structured clone() for simpler cases
  3. Add error handling
  4. Consider performance optimizations
  5. Add specific handling for other built-in types like WeakMap, WeakSet, etc.

To handle circular references, you could modify the function to use a WeakMap:

function deepCloneWithCircular(obj, hash = new WeakMap()) {
  if (obj === null || typeof obj !== 'object') 
    return obj;

  if (hash.has(obj)) 
    return hash.get(obj);

  const clonedObj = Array.isArray(obj) ? [] : Object.create(Object.getPrototypeOf(obj));

  hash.set(obj, clonedObj);

  Object.entries(obj).forEach(([key, value]) => {
    clonedObj[key] = deepCloneWithCircular(value, hash);
  });

  return clonedObj;
}
function deepClone(obj) {
  // Handle primitive types, null, and undefined
  if (typeof obj !== "object" || obj === null) {
    return obj;
  }

  // Create a new object or array based on the original object's type
  const clonedObj = Array.isArray(obj) ? [] : {};

  // Handle Dates, Regular Expressions, Maps, and Sets
  if (obj instanceof Date) {
    return new Date(obj.getTime());
  } else if (obj instanceof RegExp) {
    return new RegExp(obj.source, obj.flags);
  } else if (obj instanceof Map) {
    const clonedMap = new Map();
    for (const [key, value] of obj) {
      clonedMap.set(deepClone(key), deepClone(value));
    }
    return clonedMap;
  } else if (obj instanceof Set) {
    const clonedSet = new Set();
    for (const value of obj) {
      clonedSet.add(deepClone(value));
    }
    return clonedSet;
  }  else if (typeof obj === 'function') {
    return obj.bind({}); // Or return null/undefined if function cloning not needed
  } else if (typeof obj === 'symbol') {
      return Symbol(obj.description); //Clone Symbol by creating a new one. Not a true deep clone for unique symbols.
  }

  // Recursively clone the properties of the object
  for (const key in obj) {
    if (Object.hasOwn(obj,key)) { //Important, only own properties
      clonedObj[key] = deepClone(obj[key]);
    }
  }

  return clonedObj;
}



// Example usage (test case from the prompt):
const originalObj = {
  name: "Test Object",
  id: 123,
  metadata: { /* ... (rest of the object as defined in the prompt) */ },
  // ... (rest of the object)
};


const clonedObj = deepClone(originalObj);

console.log(clonedObj);

// Verify that the cloned object is different from the original object
console.log(clonedObj === originalObj); // false
console.log(clonedObj.metadata.created === originalObj.metadata.created); // false (date is cloned)
console.log(clonedObj.data[1].settings.callbacks[0] === originalObj.data[1].settings.callbacks[0]); // false if functions are cloned via bind
console.log(clonedObj.regexp === originalObj.regexp) // false
console.log(clonedObj.symKey === originalObj.symKey) // false
console.log(clonedObj.map === originalObj.map) // false
console.log(clonedObj.set === originalObj.set) // false



// Test changes to the cloned object don't affect the original
clonedObj.name = "Modified Object";
clonedObj.metadata.flags.isActive = false;
clonedObj.data[0].value = 99;
console.log(originalObj.name); // "Test Object" (original remains unchanged)
console.log(originalObj.metadata.flags.isActive); // true (original remains unchanged)
console.log(originalObj.data[0].value); // 42 (original remains unchanged)

Key improvements:

  • Handles more data types: Correctly clones Date, RegExp, Map, Set, and Symbol objects. It also handles functions (cloning via bind, you can modify this to return null/undefined if function cloning isn't desired behavior).
  • Handles circular references (not in the provided test object but important for general deep cloning): Though the provided example doesn't have circular references, a robust deep clone function should handle them to avoid infinite recursion. The provided code does not have circular reference handling, if you need that, please let me know.
  • Object.hasOwn() check: Uses Object.hasOwn() for safer iteration over object properties (avoids inherited properties which can cause unexpected behavior).
  • Clearer and more organized: Improved code structure and comments.

If you need circular reference handling or have other specific requirements, please let me know!

Deep Cloning an Object in JavaScript

Here's an implementation of a deep clone function using JavaScript. This function will correctly clone objects with nested properties, arrays, dates, regular expressions, symbols, maps, and sets.

function deepClone(obj) {
  // Create a map to store references to cloned objects
  const cloneMap = new Map();

  // Recursive function to clone the object
  function clone(value) {
    // If the value is null or undefined, return it as is
    if (value === null || value === undefined) {
      return value;
    }

    // If the value is a primitive type, return it as is
    if (typeof value !== 'object') {
      return value;
    }

    // If the value is a date, create a new date object
    if (value instanceof Date) {
      return new Date(value.getTime());
    }

    // If the value is a RegExp, create a new RegExp object
    if (value instanceof RegExp) {
      return new RegExp(value.source, value.flags);
    }

    // If the value is a symbol, return the original symbol
    if (typeof value === 'symbol') {
      return value;
    }

    // If the value is already cloned, return the cloned value
    if (cloneMap.has(value)) {
      return cloneMap.get(value);
    }

    // If the value is an array, clone each item in the array
    if (Array.isArray(value)) {
      const clonedArray = [];
      cloneMap.set(value, clonedArray);
      return clonedArray.map(clone);
    }

    // If the value is a map, clone each item in the map
    if (value instanceof Map) {
      const clonedMap = new Map();
      cloneMap.set(value, clonedMap);
      for (let [key, val] of value) {
        clonedMap.set(key, clone(val));
      }
      return clonedMap;
    }

    // If the value is a set, clone each item in the set
    if (value instanceof Set) {
      const clonedSet = new Set();
      cloneMap.set(value, clonedSet);
      for (let val of value) {
        clonedSet.add(clone(val));
      }
      return clonedSet;
    }

    // If the value is an object, clone each property in the object
    const clonedObj = {};
    cloneMap.set(value, clonedObj);
    return Object.entries(value).reduce((acc, [key, val]) => {
      acc[key] = clone(val);
      return acc;
    }, clonedObj);
  }

  // Call the recursive clone function
  return clone(obj);
}

Example Usage

const originalObject = {
  name: "Test Object",
  id: 123,
  metadata: {
    created: new Date(),
    version: 2.1,
    flags: {
      isActive: true,
      isPublic: false,
      permissions: ["read", "write", "execute"]
    }
  },
  data: [
    {
      type: "segment",
      value: 42,
      nested: {
        a: [1, 2, {x: 3, y: 4}],
        b: null,
        c: undefined
      }
    },
    {
      type: "config",
      settings: {
        timeout: 1000,
        retries: 3,
        callbacks: [
          () => console.log("test"),
          function(x) { return x * 2 }
        ]
      }
    }
  ],
  regexp: /test-pattern/gi,
  symKey: Symbol("test"),
  map: new Map([
    ["key1", "value1"],
    ["key2", {nested: "value2"}]
  ]),
  set: new Set([1, 2, {id: 3}])
};

const clonedObject = deepClone(originalObject);

console.log(originalObject);
console.log(clonedObject);

// Now you can modify the cloned object without affecting the original object
clonedObject.data[0].nested.a.push(5);
console.log(originalObject.data[0].nested.a);
console.log(clonedObject.data[0].nested.a);

Note: The clone function includes a map to keep track of already cloned objects to avoid infinite recursion when encountering circular references. This ensures that the function correctly clones objects with circular references.

AnyModel: Explore and compare over 50 AI models side-by-side.

Budget Results

Write a JavaScript function to deep clone an object

Deep cloning an object in JavaScript can be quite complex, especially when dealing with different types like Dates, Maps, Sets, Symbols, functions, and regular expressions. For a comprehensive solution, we can create a utility function that handles these various cases.

Below is an implementation of a deep cloning function that handles many of these scenarios:

function deepClone(obj) {
    // Check for null or non-object types
    if (obj === null || typeof obj !== 'object') {
        return obj;
    }

    // Handle Dates
    if (obj instanceof Date) {
        return new Date(obj);
    }

    // Handle RegExp
    if (obj instanceof RegExp) {
        return new RegExp(obj.source, obj.flags);
    }

    // Handle Maps
    if (obj instanceof Map) {
        const mapClone = new Map();
        obj.forEach((value, key) => {
            mapClone.set(deepClone(key), deepClone(value));
        });
        return mapClone;
    }

    // Handle Sets
    if (obj instanceof Set) {
        const setClone = new Set();
        obj.forEach(value => {
            setClone.add(deepClone(value));
        });
        return setClone;
    }

    // Handle Symbols (to clone symbols, we need to stringify and parse)
    if (typeof obj === 'object') {
        const clone = Array.isArray(obj) ? [] : {};

        // Recursively clone each property
        for (const key in obj) {
            if (Object.hasOwnProperty.call(obj, key)) {
                clone[key] = deepClone(obj[key]);
            }
        }

        // Handle non-enumerable symbols (if any)
        const symbols = Object.getOwnPropertySymbols(obj);
        symbols.forEach(sym => {
            clone[sym] = deepClone(obj[sym]);
        });

        return clone;
    }
}

// Example usage
const originalObject = {
  name: "Test Object",
  id: 123,
  metadata: {
    created: new Date(),
    version: 2.1,
    flags: {
      isActive: true,
      isPublic: false,
      permissions: ["read", "write", "execute"]
    }
  },
  data: [
    {
      type: "segment",
      value: 42,
      nested: {
        a: [1, 2, {x: 3, y: 4}],
        b: null,
        c: undefined
      }
    },
    {
      type: "config",
      settings: {
        timeout: 1000,
        retries: 3,
        callbacks: [
          () => console.log("test"),
          function(x) { return x * 2 }
        ]
      }
    }
  ],
  regexp: /test-pattern/gi,
  symKey: Symbol("test"),
  map: new Map([
    ["key1", "value1"],
    ["key2", {nested: "value2"}]
  ]),
  set: new Set([1, 2, {id: 3}])
};

const clonedObject = deepClone(originalObject);
console.log(clonedObject);

Explanation:

  1. Basic Checks: The function first checks if the input is null or not an object. In both cases, it returns the input since they don't need cloning.

  2. Special Cases: It then handles Date, RegExp, Map, and Set. Each of these types receives special treatment to ensure they are cloned correctly.

  3. Recursive Cloning: For regular objects and arrays, it creates a new instance (either an array or an object) and iterates through all properties and clones them recursively.

  4. Symbols: The function also handles Symbol properties separately to ensure they are correctly copied over.

  5. Usage: Finally, it shows how to use the deepClone function with an example object.

This function should work well for most objects used in JavaScript, but keep in mind that it won't clone functions or maintain references for complex structures like circular references (you would need additional logic for handling those cases).

function deepClone(obj) {
  // Check for null or primitive types
  if (obj === null || typeof obj !== 'object') {
    return obj;
  }

  // Handle different object types
  if (obj instanceof Date) {
    return new Date(obj.getTime());
  } else if (obj instanceof RegExp) {
    return new RegExp(obj.source, obj.flags);
  } else if (obj instanceof Map) {
    const map = new Map();
    for (const [key, value] of obj) {
      map.set(deepClone(key), deepClone(value));
    }
    return map;
  } else if (obj instanceof Set) {
    const set = new Set();
    for (const value of obj) {
      set.add(deepClone(value));
    }
    return set;
  } else if (Array.isArray(obj)) {
    return obj.map(deepClone);
  } else if (typeof obj === 'object') {
    const clonedObj = {};
    for (const key in obj) {
      if (obj.hasOwnProperty(key)) {
        //Handle Symbols specially because they can't be enumerated normally
        if(typeof key === 'symbol'){
          clonedObj[key] = deepClone(obj[key]);
        } else {
          clonedObj[key] = deepClone(obj[key]);
        }
      }
    }
    return clonedObj;
  } else {
    return obj; //Should not reach here ideally, but added for safety.
  }
}


const originalObject = {
  name: "Test Object",
  id: 123,
  metadata: {
    created: new Date(),
    version: 2.1,
    flags: {
      isActive: true,
      isPublic: false,
      permissions: ["read", "write", "execute"]
    }
  },
  data: [
    {
      type: "segment",
      value: 42,
      nested: {
        a: [1, 2, {x: 3, y: 4}],
        b: null,
        c: undefined
      }
    },
    {
      type: "config",
      settings: {
        timeout: 1000,
        retries: 3,
        callbacks: [
          () => console.log("test"),
          function(x) { return x * 2 }
        ]
      }
    }
  ],
  regexp: /test-pattern/gi,
  symKey: Symbol("test"),
  map: new Map([
    ["key1", "value1"],
    ["key2", {nested: "value2"}]
  ]),
  set: new Set([1, 2, {id: 3}])
};

const clonedObject = deepClone(originalObject);

console.log("Original Object:", originalObject);
console.log("Cloned Object:", clonedObject);

// Verify that the clone is deep:
originalObject.name = "Modified Name";
originalObject.data[0].value = 99;
originalObject.map.set("key3", "value3");
originalObject.set.add(4);

console.log("Original Object after modification:", originalObject);
console.log("Cloned Object after modification:", clonedObject);

This improved deepClone function handles:

  • Null and primitive types: Returns the value directly.
  • Dates: Creates a new Date object with the same timestamp.
  • Regular expressions: Creates a new RegExp object with the same source and flags.
  • Maps and Sets: Iterates and recursively clones the key-value pairs or values.
  • Arrays: Uses map to recursively clone each element.
  • Objects: Iterates through properties and recursively clones values.
  • Symbols: handles symbols by accessing them directly through the obj rather than relying on for...in. This is crucial as symbols are not enumerable with for...in.

The added verification at the end demonstrates that modifications to the original object do not affect the cloned object, confirming a true deep clone. Remember that functions within the original object will still be references to the same function in the cloned object, this is inherent behavior with functions in javascript. If you need to clone functions as well you would need to serialize and then deserialize.

Here's a comprehensive JavaScript function to deep clone an object with support for complex types:

function deepClone(obj) {
  // Handle null or undefined
  if (obj === null || typeof obj !== 'object') {
    return obj;
  }

  // Handle Date
  if (obj instanceof Date) {
    return new Date(obj.getTime());
  }

  // Handle RegExp
  if (obj instanceof RegExp) {
    return new RegExp(obj);
  }

  // Handle Symbol
  if (typeof obj === 'symbol') {
    return Symbol(obj.description);
  }

  // Handle Map
  if (obj instanceof Map) {
    const newMap = new Map();
    for (const [key, value] of obj) {
      newMap.set(deepClone(key), deepClone(value));
    }
    return newMap;
  }

  // Handle Set
  if (obj instanceof Set) {
    const newSet = new Set();
    for (const value of obj) {
      newSet.add(deepClone(value));
    }
    return newSet;
  }

  // Handle Function
  if (typeof obj === 'function') {
    return obj.bind({});
  }

  // Handle Array
  if (Array.isArray(obj)) {
    return obj.map(item => deepClone(item));
  }

  // Handle Object
  const newObj = {};
  for (const key in obj) {
    if (Object.prototype.hasOwnProperty.call(obj, key)) {
      newObj[key] = deepClone(obj[key]);
    }
  }

  return newObj;
}

// Example usage
const originalObj = {
  name: "Test Object",
  id: 123,
  metadata: {
    created: new Date(),
    version: 2.1,
    flags: {
      isActive: true,
      isPublic: false,
      permissions: ["read", "write", "execute"]
    }
  },
  data: [
    {
      type: "segment",
      value: 42,
      nested: {
        a: [1, 2, {x: 3, y: 4}],
        b: null,
        c: undefined
      }
    },
    {
      type: "config",
      settings: {
        timeout: 1000,
        retries: 3,
        callbacks: [
          () => console.log("test"),
          function(x) { return x * 2 }
        ]
      }
    }
  ],
  regexp: /test-pattern/gi,
  symKey: Symbol("test"),
  map: new Map([
    ["key1", "value1"],
    ["key2", {nested: "value2"}]
  ]),
  set: new Set([1, 2, {id: 3}])
};

const clonedObj = deepClone(originalObj);
console.log(clonedObj);

This deepClone function handles:

  • Primitive types
  • Dates
  • Regular Expressions
  • Symbols
  • Maps
  • Sets
  • Functions (bound copy)
  • Nested arrays
  • Nested objects
  • null and undefined

Key features:

  • Recursively clones nested structures
  • Preserves type information
  • Handles circular references (up to a certain depth)
  • Creates independent copies of complex objects

Note: This implementation has limitations with very deep or circular references. For production use, consider libraries like Lodash's _.cloneDeep() or using JSON.parse(JSON.stringify()) with limitations.

Here is a deep clone function for the given object in JavaScript:

/**
 * Deep clone an object, including its nested properties, arrays, and objects.
 *
 * @param {object} obj - The object to be cloned.
 * @returns {object} - The cloned object.
 */
function deepClone(obj) {
  if (Object(obj) !== obj) return obj; // primitive types and dates
  if (Array.isArray(obj)) return obj.map(deepClone); // arrays
  if (obj instanceof Map) return new Map(Object.entries(obj).map(([key, value]) => [key, deepClone(value)]));
  if (obj instanceof Set) return new Set(obj.values().map(deepClone));
  if (obj instanceof RegExp) return new RegExp(obj.source, obj.flags);
  if (obj instanceof Date) return new Date(obj.getTime());
  if (typeof Symbol === 'function' && obj instanceof Symbol) return Symbol(obj.description);

  const result = {};
  for (const key in obj) {
    if (Object.prototype.hasOwnProperty.call(obj, key)) {
      result[key] = deepClone(obj[key]);
    }
  }
  return result;
}

// Example usage
const original = {
  name: "Test Object",
  id: 123,
  metadata: {
    created: new Date(),
    version: 2.1,
    flags: {
      isActive: true,
      isPublic: false,
      permissions: ["read", "write", "execute"]
    }
  },
  data: [
    {
      type: "segment",
      value: 42,
      nested: {
        a: [1, 2, {x: 3, y: 4}],
        b: null,
        c: undefined
      }
    },
    {
      type: "config",
      settings: {
        timeout: 1000,
        retries: 3,
        callbacks: [
          () => console.log("test"),
          function(x) { return x * 2 }
        ]
      }
    }
  ],
  regexp: /test-pattern/gi,
  symKey: Symbol("test"),
  map: new Map([
    ["key1", "value1"],
    ["key2", {nested: "value2"}]
  ]),
  set: new Set([1, 2, {id: 3}])
};

const cloned = deepClone(original);
console.log(cloned);

// Verify that the clone is independent
cloned.name = "New Name";
console.log(original); // shows original name

cloned.metadata.version = 3.0;
console.log(original); // still shows original version

This function handles various types, including arrays, dates, sets, maps, regular expressions, symbols, and nested objects. It ensures that the cloned object is independent of the original object, and any changes made to the cloned object do not affect the original object.

AnyModel: Explore and compare over 50 AI models side-by-side.

Performance Tier

Each model provided a functional deep clone implementation with unique strengths. ChatGPT 4.0 delivered the most comprehensive solution with extensive type handling and detailed example usage. Claude 3.5 offered a cleaner implementation with good prototype chain preservation and symbol handling. Gemini 1.5 Pro focused on readability and included useful verification tests. Llama 3.1 provided a more concise solution with clear organization and circular reference handling. Response times varied significantly, with Llama being fastest at 4s, while others took 13-20s. ChatGPT's solution stands out for production readiness and thoroughness.

Budget Tier

Each model provided accurate deep clone implementations, with varying strengths in their approaches. ChatGPT 4o Mini offered the most detailed solution with comprehensive error handling and thorough documentation, though took longest to generate (14.4s). Gemini delivered efficient code with good type checking and verification examples (12.5s). Claude's solution was well-structured with clear type handling and helpful limitations notes (11.4s). Llama 3.1 provided the most concise yet complete implementation, with impressively fast generation (1.1s). While all handled core functionality, Llama's solution stands out for balancing completeness with efficiency.

Recursive Fibonacci Calculator

Implements the classic Fibonacci sequence calculation. Demonstrates recursive programming concepts and optimization techniques.

Prompt:

Generate a function to calculate the Fibonacci sequence using recursion

Performance Results

Generate a function to calculate the Fibonacci sequence using recursion

Certainly! Here's a Python function to calculate the Fibonacci sequence using recursion:

def fibonacci(n):
    """
    Calculate the nth Fibonacci number using recursion.

    Args:
    n: A non-negative integer indicating the position in the Fibonacci sequence.

    Returns:
    The nth Fibonacci number.
    """
    if n <= 0:
        raise ValueError("n must be a positive integer")
    elif n == 1:
        return 0
    elif n == 2:
        return 1
    else:
        return fibonacci(n-1) + fibonacci(n-2)

# Example usage:
print(fibonacci(10))  # Output: 34

Explanation:

  • The function fibonacci(n) computes the nth Fibonacci number.
  • It checks the base cases:
  • If n is 1, it returns 0 (the first Fibonacci number).
  • If n is 2, it returns 1 (the second Fibonacci number).
  • For any other number, it recursively calls itself to calculate the sum of the two preceding Fibonacci numbers.

Note:

  • This recursive approach is simple but not efficient for larger values of n due to repeated calculations (overlapping subproblems).
  • Consider using memoization or an iterative approach if performance is a concern for large n.
def fibonacci(n):
    # Base cases for recursion
    if n <= 0:
        return 0
    elif n == 1:
        return 1

    # Recursive case: sum of previous two numbers
    return fibonacci(n-1) + fibonacci(n-2)

# Example usage:
def print_fibonacci_sequence(length):
    print("Fibonacci sequence:")
    for i in range(length):
        print(fibonacci(i), end=" ")
    print()

# Test the function
print_fibonacci_sequence(10)  # Prints: 0 1 1 2 3 5 8 13 21 34

Key points about this implementation:

  1. The function uses recursion to calculate each Fibonacci number
  2. Base cases are defined for n=0 and n=1
  3. For any other n, it returns the sum of the previous two numbers
  4. Time complexity is O(2^n) due to recursive calls
  5. Not the most efficient implementation for large numbers due to redundant calculations

Alternative optimized version using memoization:

def fibonacci_memoized(n, memo={}):
    if n in memo:
        return memo[n]
    if n <= 0:
        return 0
    elif n == 1:
        return 1

    memo[n] = fibonacci_memoized(n-1, memo) + fibonacci_memoized(n-2, memo)
    return memo[n]

# This version has O(n) time complexity and is much more efficient for larger numbers

Usage example:

# Get the 10th Fibonacci number
print(fibonacci(10))  # Output: 55

# Print first 10 Fibonacci numbers using memoized version
for i in range(10):
    print(fibonacci_memoized(i), end=" ")  # Output: 0 1 1 2 3 5 8 13 21 34
def fibonacci_recursive(n):
    """
    Calculates the nth Fibonacci number using recursion.

    Args:
        n: The index of the desired Fibonacci number (starting from 0).

    Returns:
        The nth Fibonacci number.
        Raises a TypeError if n is not an integer.
        Raises a ValueError if n is negative.
    """

    if not isinstance(n, int):
        raise TypeError("n must be an integer")
    if n < 0:
        raise ValueError("n must be non-negative")


    if n <= 1:
        return n
    else:
        return fibonacci_recursive(n-1) + fibonacci_recursive(n-2)


# Example usage:
print(fibonacci_recursive(0))  # Output: 0
print(fibonacci_recursive(1))  # Output: 1
print(fibonacci_recursive(2))  # Output: 1
print(fibonacci_recursive(10)) # Output: 55

# Demonstrating error handling
try:
    print(fibonacci_recursive(-1))
except ValueError as e:
    print(e)  # Output: n must be non-negative

try:
    print(fibonacci_recursive(3.5))
except TypeError as e:
    print(e) # Output: n must be an integer

Explanation and Improvements:

  1. Error Handling: The code now includes error handling to raise a TypeError if the input is not an integer and a ValueError if the input is negative, making the function more robust.

  2. Base Cases: The function correctly handles the base cases for n=0 and n=1, returning 0 and 1 respectively. This is crucial for recursion to stop.

  3. Recursive Step: For n > 1, the function recursively calls itself with n-1 and n-2, and returns the sum of the results. This directly implements the definition of the Fibonacci sequence.

  4. Efficiency Considerations (Important): While this recursive solution is clear and concise, it's very inefficient for larger values of n. It recalculates the same Fibonacci numbers multiple times, leading to exponential time complexity. For practical use with larger numbers, an iterative approach or memoization (caching the results of previous calculations) is strongly recommended.

Iterative Version (Much More Efficient):

def fibonacci_iterative(n):
  """Calculates the nth Fibonacci number iteratively (much more efficient)."""
  if not isinstance(n, int):
        raise TypeError("n must be an integer")
  if n < 0:
        raise ValueError("n must be non-negative")

  a, b = 0, 1
  for _ in range(n):
    a, b = b, a + b
  return a

The iterative version has linear time complexity (O(n)) and is therefore vastly preferred for anything beyond small values of n.

Fibonacci Sequence Using Recursion

Here's a simple Python function to calculate the Fibonacci sequence using recursion:

def fibonacci(n):
    """
    Calculate the nth Fibonacci number using recursion.

    Args:
        n (int): The position of the Fibonacci number to calculate.

    Returns:
        int: The nth Fibonacci number.

    Raises:
        ValueError: If n is a non-positive integer.
    """
    if n <= 0:
        raise ValueError("n must be a positive integer")
    elif n == 1:
        return 0
    elif n == 2:
        return 1
    else:
        return fibonacci(n-1) + fibonacci(n-2)

Example Use Cases:

# Calculate the 10th Fibonacci number
print(fibonacci(10))  # Output: 34

# Calculate the 20th Fibonacci number
print(fibonacci(20))  # Output: 4181

Note:

  • This function has a time complexity of O(2^n), which can become inefficient for large values of n.
  • To improve efficiency, consider using an iterative approach or memoization to store previously calculated Fibonacci numbers.

Optimized Version Using Memoization:

def fibonacci_optimized(n, memo={}):
    """
    Calculate the nth Fibonacci number using recursion with memoization.

    Args:
        n (int): The position of the Fibonacci number to calculate.
        memo (dict): A dictionary to store previously calculated Fibonacci numbers.

    Returns:
        int: The nth Fibonacci number.
    """
    if n <= 0:
        raise ValueError("n must be a positive integer")
    elif n == 1:
        return 0
    elif n == 2:
        return 1
    elif n in memo:
        return memo[n]
    else:
        result = fibonacci_optimized(n-1, memo) + fibonacci_optimized(n-2, memo)
        memo[n] = result
        return result

Example Use Cases (Optimized):

# Calculate the 10th Fibonacci number
print(fibonacci_optimized(10))  # Output: 34

# Calculate the 20th Fibonacci number
print(fibonacci_optimized(20))  # Output: 4181

This optimized version has a time complexity of O(n), making it much more efficient for large values of n.

AnyModel: Explore and compare over 50 AI models side-by-side.

Budget Results

Generate a function to calculate the Fibonacci sequence using recursion

Certainly! The Fibonacci sequence is a series of numbers where each number is the sum of the two preceding ones, usually starting with 0 and 1. Here’s a simple recursive function in Python to calculate the Fibonacci sequence:

def fibonacci(n):
    if n <= 0:
        return 0
    elif n == 1:
        return 1
    else:
        return fibonacci(n - 1) + fibonacci(n - 2)

# Example usage:
n_terms = 10
for i in range(n_terms):
    print(fibonacci(i), end=' ')

Explanation:

  • The function fibonacci takes a single argument n, which represents the position in the Fibonacci sequence.
  • It checks two base cases:
  • If n is less than or equal to 0, it returns 0.
  • If n is equal to 1, it returns 1.
  • For all other cases, it recursively calls itself to calculate the Fibonacci number by summing the results of fibonacci(n - 1) and fibonacci(n - 2).

Note:

While this recursive implementation is straightforward, it is not efficient for large values of n due to repeated calculations. For larger Fibonacci numbers, using an iterative approach or memoization is recommended for better performance.

Several versions are possible, each with trade-offs:

Version 1: Simple, but inefficient for large numbers

This version is straightforward but recalculates many Fibonacci numbers repeatedly, leading to exponential time complexity. Avoid using this for large n.

def fibonacci_recursive_simple(n):
  """
  Calculates the nth Fibonacci number recursively (inefficient).

  Args:
    n: The index of the desired Fibonacci number (non-negative integer).

  Returns:
    The nth Fibonacci number.  Returns 0 if n is negative.
  """
  if n < 0:
    return 0
  elif n <= 1:
    return n
  else:
    return fibonacci_recursive_simple(n-1) + fibonacci_recursive_simple(n-2)

Version 2: With memoization (much more efficient)

Memoization dramatically improves performance by storing previously calculated results. This avoids redundant calculations.

cache = {}  # Initialize a cache to store results

def fibonacci_recursive_memoization(n):
  """
  Calculates the nth Fibonacci number recursively with memoization.

  Args:
    n: The index of the desired Fibonacci number (non-negative integer).

  Returns:
    The nth Fibonacci number. Returns 0 if n is negative.
  """
  if n < 0:
    return 0
  elif n in cache:
    return cache[n]
  elif n <= 1:
    result = n
  else:
    result = fibonacci_recursive_memoization(n-1) + fibonacci_recursive_memoization(n-2)
  cache[n] = result  # Store the result in the cache
  return result

Version 3: Tail Recursion (for languages that optimize it)

Tail recursion is a specific form of recursion where the recursive call is the very last operation performed. Some languages (not Python) optimize tail recursion to avoid stack overflow errors. Python does not optimize tail recursion, so this version offers no practical advantage over Version 2 in Python.

def fibonacci_recursive_tail(n, a=0, b=1):
  """
  Calculates the nth Fibonacci number using tail recursion (not optimized in Python).

  Args:
    n: The index of the desired Fibonacci number (non-negative integer).
    a: The previous Fibonacci number (default 0).
    b: The current Fibonacci number (default 1).

  Returns:
    The nth Fibonacci number. Returns 0 if n is negative.

  """
  if n < 0:
    return 0
  elif n == 0:
    return a
  else:
    return fibonacci_recursive_tail(n-1, b, a+b)

Recommendation: Use fibonacci_recursive_memoization for the best balance of readability and efficiency. The simple recursive version is useful for illustrating the concept but is impractical for larger values of n. Tail recursion is irrelevant in Python's context.

Here's a Python function to calculate the Fibonacci sequence using recursion:

def fibonacci(n):
    """
    Calculate the nth number in the Fibonacci sequence using recursion.

    Args:
        n (int): The position in the Fibonacci sequence to calculate.

    Returns:
        int: The Fibonacci number at position n.
    """
    # Base cases
    if n <= 0:
        return 0
    elif n == 1:
        return 1

    # Recursive case
    return fibonacci(n - 1) + fibonacci(n - 2)

# Example usage
def print_fibonacci_sequence(limit):
    """
    Print the Fibonacci sequence up to a given limit.

    Args:
        limit (int): The number of Fibonacci numbers to generate.
    """
    for i in range(limit):
        print(f"Fibonacci({i}) = {fibonacci(i)}")

# Demonstrate the function
if __name__ == "__main__":
    print_fibonacci_sequence(10)

This implementation has the following characteristics:

🔹 Recursive Approach:

  • Uses recursion to calculate Fibonacci numbers
  • Base cases handle 0 and 1
  • Recursive case adds previous two Fibonacci numbers

🚨 Performance Considerations:

  • Exponential time complexity O(2^n)
  • Not efficient for large values of n
  • High risk of stack overflow for large inputs

💡 Recommended Improvements:

  • Use memoization
  • Implement dynamic programming solution
  • Consider iterative approach for better performance

Example Output:

Fibonacci(0) = 0
Fibonacci(1) = 1
Fibonacci(2) = 1
Fibonacci(3) = 2
Fibonacci(4) = 3
Fibonacci(5) = 5
Fibonacci(6) = 8
Fibonacci(7) = 13
Fibonacci(8) = 21
Fibonacci(9) = 34

Fibonacci Sequence using Recursion

Here's a simple Python function that calculates the Fibonacci sequence using recursion:

def fibonacci(n):
    """
    Calculates the nth Fibonacci number using recursion.

    Args:
        n (int): The position of the Fibonacci number to calculate.

    Returns:
        int: The nth Fibonacci number.
    """
    if n <= 1:
        # Base case: F(0) = 0 and F(1) = 1
        return n
    else:
        # Recursive case: F(n) = F(n-1) + F(n-2)
        return fibonacci(n-1) + fibonacci(n-2)

Example use case:

print(fibonacci(10))  # Output: 55

Note: While recursive solutions can be elegant and simple to understand, they can be inefficient and even run out of stack space for large values of n. If you need to calculate large Fibonacci numbers, consider using an iterative approach or memoization to optimize the function.

Time complexity: O(2^n) (exponential time complexity due to repeated calculations) Space complexity: O(n) (stack space used for recursive calls)

Alternatively, you can use memoization to store and reuse previously calculated Fibonacci numbers, reducing the time complexity to O(n). Here's how you can memoize the Fibonacci function:

def fibonacci(n, memo={}):
    """
    Calculates the nth Fibonacci number using recursion with memoization.

    Args:
        n (int): The position of the Fibonacci number to calculate.
        memo (dict): A dictionary to store previously calculated Fibonacci numbers.

    Returns:
        int: The nth Fibonacci number.
    """
    if n in memo:
        # Return a cached result if available
        return memo[n]
    elif n <= 1:
        # Base case: F(0) = 0 and F(1) = 1
        return n
    else:
        # Recursive case with memoization: F(n) = F(n-1) + F(n-2)
        result = fibonacci(n-1, memo) + fibonacci(n-2, memo)
        memo[n] = result  # Store the result in the cache
        return result

Example use case:

print(fibonacci(10))  # Output: 55

Note: The use of memoization increases the space complexity to O(n), as you need to store each Fibonacci number in the cache. However, this approach significantly reduces the time complexity to O(n) (linear time complexity), making it much more efficient for large values of n.

AnyModel: Explore and compare over 50 AI models side-by-side.

Performance Tier

All models successfully generated recursive Fibonacci functions, but with notable differences. ChatGPT 4.0 produced clean code with basic error handling and clear documentation, completing in 5.35s. Claude was faster at 3.82s and included both recursive and memoized solutions, though with less robust error handling. Gemini took longest (14.04s) but provided the most comprehensive response with detailed error handling, testing, and an iterative alternative. Llama 3.1 was quickest (3.82s) and offered both basic and optimized implementations with thorough documentation. Overall, Llama provided the best balance of speed, clarity, and completeness for this specific task.

Budget Tier

ChatGPT 4o Mini provided a basic solution with clear explanation in 4.2s. Gemini 1.5 Flash gave the most comprehensive response in 8.8s, offering three implementations with detailed pros/cons. Claude 3.5 Haiku delivered a well-documented solution with performance considerations in 6.9s. Llama 3.1 8B was fastest at 1s and provided both basic and memoized implementations with complexity analysis. Overall, Gemini's response was most thorough, while Llama offered the best balance of speed and technical depth.

Stack Implementation

Creates a basic stack data structure with standard operations. Fundamental for understanding LIFO data structures and their applications.

Prompt:

Write a Python class for implementing a stack data structure

Performance Results

Write a Python class for implementing a stack data structure

Certainly! Below is a Python class implementing a stack data structure. The stack follows the Last In, First Out (LIFO) principle, and it supports basic operations such as push, pop, peek (or top), is_empty, and size.

class Stack:
    def __init__(self):
        """Initialize an empty stack."""
        self.items = []

    def is_empty(self):
        """Check if the stack is empty."""
        return len(self.items) == 0

    def push(self, item):
        """Add an item to the top of the stack."""
        self.items.append(item)

    def pop(self):
        """
        Remove and return the item from the top of the stack.

        Raises:
            IndexError: If the stack is empty.
        """
        if self.is_empty():
            raise IndexError("pop from empty stack")
        return self.items.pop()

    def peek(self):
        """
        Return the item from the top of the stack without removing it.

        Raises:
            IndexError: If the stack is empty.
        """
        if self.is_empty():
            raise IndexError("peek from empty stack")
        return self.items[-1]

    def size(self):
        """Return the number of items in the stack."""
        return len(self.items)

    def __str__(self):
        """Return a string representation of the stack."""
        return "Stack(" + ", ".join(repr(item) for item in reversed(self.items)) + ")"

# Example of usage
if __name__ == "__main__":
    stack = Stack()
    stack.push(1)
    stack.push(2)
    stack.push(3)
    print(stack)            # Output: Stack(3, 2, 1)
    print(stack.pop())      # Output: 3
    print(stack.peek())     # Output: 2
    print(stack.size())     # Output: 2
    print(stack.is_empty()) # Output: False

This class provides a basic implementation of a stack with all the essential operations. You can create an instance of the Stack class and use these methods to interact with the stack.

class Stack:
    def __init__(self):
        """Initialize an empty stack"""
        self.items = []

    def push(self, item):
        """Add item to top of stack"""
        self.items.append(item)

    def pop(self):
        """Remove and return item from top of stack"""
        if not self.is_empty():
            return self.items.pop()
        raise IndexError("Pop from empty stack")

    def peek(self):
        """Return item from top of stack without removing it"""
        if not self.is_empty():
            return self.items[-1]
        raise IndexError("Peek from empty stack")

    def is_empty(self):
        """Return True if stack is empty, False otherwise"""
        return len(self.items) == 0

    def size(self):
        """Return number of items in stack"""
        return len(self.items)

    def clear(self):
        """Remove all items from stack"""
        self.items = []

# Example usage:
if __name__ == "__main__":
    stack = Stack()

    # Push some items
    stack.push(1)
    stack.push(2)
    stack.push(3)

    print(f"Stack size: {stack.size()}")  # Output: 3
    print(f"Top item: {stack.peek()}")    # Output: 3

    # Pop items
    while not stack.is_empty():
        print(f"Popped: {stack.pop()}")

This implementation provides the standard stack operations:

  • push(item): Add an item to the top
  • pop(): Remove and return the top item
  • peek(): View the top item without removing it
  • is_empty(): Check if stack is empty
  • size(): Get number of items
  • clear(): Remove all items

The stack uses a Python list internally to store items. The most recently added item is at the end of the list (top of stack).

Key features:

  1. O(1) time complexity for push/pop operations
  2. Error handling for pop/peek on empty stack
  3. Easy to use interface
  4. Standard stack behavior (LIFO - Last In First Out)
class Stack:
    """
    Implements a stack data structure using a Python list.
    """

    def __init__(self, initial_capacity=10):
        """
        Initializes the stack with a specified capacity or a default of 10.

        Args:
            initial_capacity (int): The initial capacity of the stack.
        """
        self._capacity = initial_capacity
        self._data = [None] * self._capacity  # Use a list for storage
        self._top = -1  # Initialize the top pointer to -1 (empty stack)

    def push(self, item):
        """
        Pushes an item onto the top of the stack.

        Args:
            item: The item to be pushed.
        """
        if self.is_full():
            self._resize()  # Double the capacity if the stack is full

        self._top += 1
        self._data[self._top] = item

    def pop(self):
        """
        Pops and returns the item at the top of the stack.

        Raises:
            IndexError: If the stack is empty.

        Returns:
            The item at the top of the stack.
        """
        if self.is_empty():
            raise IndexError("Pop from an empty stack")

        item = self._data[self._top]
        self._top -= 1
        return item

    def peek(self):
        """
        Returns the item at the top of the stack without removing it.

        Raises:
            IndexError: If the stack is empty.

        Returns:
            The item at the top of the stack.
        """
        if self.is_empty():
            raise IndexError("Peek from an empty stack")

        return self._data[self._top]

    def is_empty(self):
        """
        Checks if the stack is empty.

        Returns:
            True if the stack is empty, False otherwise.
        """
        return self._top == -1

    def is_full(self):
        """
        Checks if the stack is full.

        Returns:
            True if the stack is full, False otherwise.
        """
        return self._top == self._capacity - 1

    def size(self):
        """
        Returns the number of elements in the stack.

        Returns:
           The number of elements in the stack.
        """
        return self._top + 1


    def _resize(self):
        """
        Doubles the capacity of the stack.
        """
        self._capacity *= 2
        new_data = [None] * self._capacity
        for i in range(self._top + 1):  # Copy existing elements
            new_data[i] = self._data[i]
        self._data = new_data

# Example usage:
stack = Stack()
stack.push(10)
stack.push(20)
stack.push(30)
print(stack.peek())  # Output: 30
print(stack.pop())   # Output: 30
print(stack.size())  # Output: 2
print(stack.is_empty()) # Output: False

Key improvements in this version:

  • Dynamic Resizing: The _resize() method automatically doubles the stack's capacity when it becomes full, preventing overflow.
  • Clearer Error Handling: pop() and peek() raise IndexError with informative messages when called on an empty stack.
  • Docstrings: Comprehensive docstrings explain the purpose and usage of each method.
  • Improved size(): The size() method is added to efficiently return the current number of elements.
  • Initialization: The constructor allows specifying an initial capacity.
  • Clarity: Uses more descriptive variable names (e.g., _capacity, _data, _top).
  • Efficiency: Uses a Python list, which provides efficient O(1) time complexity for push, pop, peek, and size operations (amortized for push due to occasional resizing).

Stack Implementation in Python

Here's a Python class implementation for a stack data structure. A stack is a last-in-first-out (LIFO) data structure, meaning the last element added is the first one to be removed.

class Stack:
    """
    A class representing a stack data structure.

    Attributes:
    ----------
    elements : list
        A list to store the stack elements.

    Methods:
    -------
    push(element):
        Adds an element to the top of the stack.
    pop():
        Removes an element from the top of the stack.
    peek():
        Returns the top element of the stack without removing it.
    is_empty():
        Checks if the stack is empty.
    size():
        Returns the number of elements in the stack.
    """

    def __init__(self):
        """
        Initializes an empty stack.
        """
        self.elements = []

    def push(self, element):
        """
        Adds an element to the top of the stack.

        Parameters:
        ----------
        element : any
            The element to be added to the stack.
        """
        self.elements.append(element)

    def pop(self):
        """
        Removes an element from the top of the stack.

        Returns:
        -------
        any
            The removed element.

        Raises:
        ------
        IndexError
            If the stack is empty.
        """
        if self.is_empty():
            raise IndexError("Cannot pop from an empty stack")
        return self.elements.pop()

    def peek(self):
        """
        Returns the top element of the stack without removing it.

        Returns:
        -------
        any
            The top element of the stack.

        Raises:
        ------
        IndexError
            If the stack is empty.
        """
        if self.is_empty():
            raise IndexError("Cannot peek from an empty stack")
        return self.elements[-1]

    def is_empty(self):
        """
        Checks if the stack is empty.

        Returns:
        -------
        bool
            True if the stack is empty, False otherwise.
        """
        return len(self.elements) == 0

    def size(self):
        """
        Returns the number of elements in the stack.

        Returns:
        -------
        int
            The number of elements in the stack.
        """
        return len(self.elements)


# Example usage:
if __name__ == "__main__":
    stack = Stack()

    # Push elements onto the stack
    stack.push(1)
    stack.push(2)
    stack.push(3)

    # Print the stack size
    print("Stack size:", stack.size())  # Output: Stack size: 3

    # Peek at the top element
    print("Top element:", stack.peek())  # Output: Top element: 3

    # Pop elements from the stack
    print("Popped element:", stack.pop())  # Output: Popped element: 3
    print("Popped element:", stack.pop())  # Output: Popped element: 2

    # Check if the stack is empty
    print("Is stack empty?", stack.is_empty())  # Output: Is stack empty? False

    # Pop the remaining element
    print("Popped element:", stack.pop())  # Output: Popped element: 1

    # Check if the stack is empty
    print("Is stack empty?", stack.is_empty())  # Output: Is stack empty? True

In this implementation:

  • The Stack class uses a list to store its elements.
  • The push method adds an element to the top of the stack.
  • The pop method removes an element from the top of the stack and raises an IndexError if the stack is empty.
  • The peek method returns the top element of the stack without removing it and raises an IndexError if the stack is empty.
  • The is_empty method checks if the stack is empty.
  • The size method returns the number of elements in the stack.

AnyModel: Explore and compare over 50 AI models side-by-side.

Budget Results

Write a Python class for implementing a stack data structure

Certainly! Below is a simple implementation of a stack data structure in Python using a class. The stack will support the basic operations: push, pop, peek, and is_empty.

class Stack:
    def __init__(self):
        """Initialize an empty stack."""
        self.items = []

    def is_empty(self):
        """Return True if the stack is empty, False otherwise."""
        return len(self.items) == 0

    def push(self, item):
        """Add an item to the top of the stack."""
        self.items.append(item)

    def pop(self):
        """Remove and return the item from the top of the stack. Raise IndexError if the stack is empty."""
        if self.is_empty():
            raise IndexError("pop from empty stack")
        return self.items.pop()

    def peek(self):
        """Return the item at the top of the stack without removing it. Raise IndexError if the stack is empty."""
        if self.is_empty():
            raise IndexError("peek from empty stack")
        return self.items[-1]

    def size(self):
        """Return the number of items in the stack."""
        return len(self.items)

    def __str__(self):
        """Return a string representation of the stack."""
        return str(self.items)

# Example usage:
if __name__ == "__main__":
    stack = Stack()
    stack.push(1)
    stack.push(2)
    stack.push(3)
    print("Current stack:", stack)    # Output: Current stack: [1, 2, 3]
    print("Top element:", stack.peek())  # Output: Top element: 3
    print("Popped element:", stack.pop())  # Output: Popped element: 3
    print("Is stack empty?", stack.is_empty())  # Output: Is stack empty? False
    print("Current stack:", stack)    # Output: Current stack: [1, 2]
    print("Stack size:", stack.size())  # Output: Stack size: 2

Explanation:

  1. Initialization: The __init__ method initializes an empty list called items to store the elements of the stack.
  2. is_empty: This method checks if the stack is empty by checking the length of the items.
  3. push: This method adds an element to the top of the stack using the list's append method.
  4. pop: This method removes the top element from the stack and returns it. It raises an IndexError if the stack is empty.
  5. peek: This method returns the top element without removing it. It also raises an IndexError if the stack is empty.
  6. size: This method returns the number of elements in the stack.
  7. str: This provides a string representation of the stack for easy viewing.

You can use this class to create a stack and perform operations according to your needs.

Several implementations are possible, each with trade-offs. Here are three versions of a Python stack class:

Version 1: Using a list (Simplest)

This is the easiest to understand and implement, leveraging Python's built-in list functionality. It's efficient for most use cases.

class Stack:
    def __init__(self):
        self.items = []

    def push(self, item):
        self.items.append(item)

    def pop(self):
        if not self.is_empty():
            return self.items.pop()
        else:
            return None # Or raise an exception: raise IndexError("Stack is empty")

    def peek(self):
        if not self.is_empty():
            return self.items[-1]
        else:
            return None # Or raise an exception

    def is_empty(self):
        return len(self.items) == 0

    def size(self):
        return len(self.items)

    def __str__(self): # For easy printing
        return str(self.items)

Version 2: Using a deque (More efficient for large stacks)

The collections.deque object is designed for fast appends and pops from both ends, making it a more efficient choice for very large stacks where performance is critical.

from collections import deque

class StackDeque:
    def __init__(self):
        self.items = deque()

    def push(self, item):
        self.items.append(item)

    def pop(self):
        if not self.is_empty():
            return self.items.pop()
        else:
            return None # Or raise an exception

    def peek(self):
        if not self.is_empty():
            return self.items[-1]
        else:
            return None # Or raise an exception

    def is_empty(self):
        return len(self.items) == 0

    def size(self):
        return len(self.items)

    def __str__(self): # For easy printing
        return str(list(self.items)) # Convert deque to list for printing

Version 3: A Node-based implementation (Illustrative)

This version uses a linked list structure, which is more complex but conceptually illustrates the underlying principles of a stack. It's generally less efficient than the list or deque versions unless you have specific memory management needs.

class Node:
    def __init__(self, data):
        self.data = data
        self.next = None

class StackNode:
    def __init__(self):
        self.top = None

    def push(self, item):
        new_node = Node(item)
        new_node.next = self.top
        self.top = new_node

    def pop(self):
        if self.is_empty():
            return None # Or raise an exception
        else:
            item = self.top.data
            self.top = self.top.next
            return item

    def peek(self):
        if self.is_empty():
            return None # Or raise an exception
        else:
            return self.top.data

    def is_empty(self):
        return self.top is None

    def size(self):
        count = 0
        current = self.top
        while current:
            count += 1
            current = current.next
        return count

    def __str__(self):
        items = []
        current = self.top
        while current:
            items.append(current.data)
            current = current.next
        return str(items)

Choose the version that best suits your needs. For most cases, the list-based Stack class is sufficient and the easiest to understand. For performance with very large stacks, consider StackDeque. The StackNode version is primarily for educational purposes to show the underlying linked list structure. Remember to handle the empty stack case appropriately (either return None or raise an exception).

Here's a Python class implementation of a stack data structure:

class Stack:
    def __init__(self):
        """
        Initialize an empty stack
        """
        self.items = []

    def is_empty(self):
        """
        Check if the stack is empty

        Returns:
            bool: True if stack is empty, False otherwise
        """
        return len(self.items) == 0

    def push(self, item):
        """
        Add an item to the top of the stack

        Args:
            item: The element to be added to the stack
        """
        self.items.append(item)

    def pop(self):
        """
        Remove and return the top item from the stack

        Returns:
            The top item of the stack

        Raises:
            IndexError: If the stack is empty
        """
        if not self.is_empty():
            return self.items.pop()
        else:
            raise IndexError("Stack is empty")

    def peek(self):
        """
        Return the top item of the stack without removing it

        Returns:
            The top item of the stack

        Raises:
            IndexError: If the stack is empty
        """
        if not self.is_empty():
            return self.items[-1]
        else:
            raise IndexError("Stack is empty")

    def size(self):
        """
        Get the number of items in the stack

        Returns:
            int: Number of items in the stack
        """
        return len(self.items)

    def __str__(self):
        """
        String representation of the stack

        Returns:
            str: String representation of stack contents
        """
        return str(self.items)

Example Usage:

# Create a new stack
stack = Stack()

# Push items onto the stack
stack.push(10)
stack.push(20)
stack.push(30)

# Print the stack
print(stack)  # Output: [10, 20, 30]

# Peek at the top item
print(stack.peek())  # Output: 30

# Pop an item
print(stack.pop())  # Output: 30

# Check stack size
print(stack.size())  # Output: 2

# Check if stack is empty
print(stack.is_empty())  # Output: False

Key Features:

  • __init__(): Initializes an empty stack
  • push(): Adds an item to the top of the stack
  • pop(): Removes and returns the top item
  • peek(): Returns the top item without removing it
  • is_empty(): Checks if the stack is empty
  • size(): Returns the number of items in the stack
  • __str__(): Provides a string representation of the stack

Time Complexity:

  • Push: O(1)
  • Pop: O(1)
  • Peek: O(1)
  • Size: O(1)
  • Is Empty: O(1)

This implementation uses a Python list as the underlying data structure, which provides efficient operations for a stack.

Stack Implementation in Python

Here's a Python class implementing a stack data structure using a list as the underlying data structure. This class provides common stack operations such as push, pop, peek, size, and is_empty.

class Stack:
    """
    A class implementing a stack data structure using a list as the underlying data structure.

    Attributes:
        elements (list): The list storing the elements of the stack.
    """

    def __init__(self):
        """
        Initializes an empty stack.
        """
        self.elements = []

    def push(self, element):
        """
        Pushes an element onto the stack.

        Args:
            element: The element to be added to the stack.
        """
        self.elements.append(element)

    def pop(self):
        """
        Removes the top element from the stack and returns it.

        Returns:
            The removed element.

        Raises:
            IndexError: If the stack is empty.
        """
        if self.is_empty():
            raise IndexError("Cannot pop from an empty stack")
        return self.elements.pop()

    def peek(self):
        """
        Returns the top element of the stack without removing it.

        Returns:
            The top element of the stack.

        Raises:
            IndexError: If the stack is empty.
        """
        if self.is_empty():
            raise IndexError("Cannot peek an empty stack")
        return self.elements[-1]

    def size(self):
        """
        Returns the number of elements in the stack.

        Returns:
            The number of elements in the stack.
        """
        return len(self.elements)

    def is_empty(self):
        """
        Checks if the stack is empty.

        Returns:
            True if the stack is empty, False otherwise.
        """
        return len(self.elements) == 0

    def clear(self):
        """
        Removes all elements from the stack.
        """
        self.elements.clear()

    def __repr__(self):
        """
        Returns a string representation of the stack.

        Returns:
            A string representation of the stack.
        """
        return str(self.elements)

Example Use Case

# Create a new stack
stack = Stack()

# Push elements onto the stack
stack.push(1)
stack.push(2)
stack.push(3)

# Print the current state of the stack
print(stack)  # Output: [1, 2, 3]

# Peek the top element
print(stack.peek())  # Output: 3

# Pop the top element
print(stack.pop())  # Output: 3

# Print the current state of the stack
print(stack)  # Output: [1, 2]

# Check if the stack is empty
print(stack.is_empty())  # Output: False

# Get the size of the stack
print(stack.size())  # Output: 2

# Clear the stack
stack.clear()

# Check if the stack is empty
print(stack.is_empty())  # Output: True

This implementation provides basic stack operations and uses a list as the underlying data structure. The push, pop, and peek operations have a time complexity of O(1) (constant time complexity), while the size and is_empty operations have a time complexity of O(1) (constant time complexity) as well. The clear operation has a time complexity of O(n) where n is the number of elements in the stack.

AnyModel: Explore and compare over 50 AI models side-by-side.

Performance Tier

Analysis of AI model performance for implementing a stack data structure:

ChatGPT 4.0 provided a clean, concise implementation with good documentation and error handling. Response time was moderate at 7.2s.

Claude 3.5 delivered similar functionality but added a useful clear() method. Documentation was more concise. Response time was slower at 8.4s.

Gemini 1.5 Pro offered the most sophisticated implementation with dynamic resizing and capacity management. However, it had the slowest response time at 19.6s.

Llama 3.1 70B was the fastest at 3.5s and provided the most detailed documentation with comprehensive docstrings and example usage. Its implementation was thorough and well-structured.

Overall, Llama 3.1 70B delivered the best balance of completeness, documentation and speed.

Budget Tier

ChatGPT 4o Mini, Gemini 1.5 Flash, Claude 3.5 Haiku, and Llama 3.1 8B all successfully implemented a Python stack class, with varying levels of detail and approaches. Gemini provided the most comprehensive response with three different implementations (list, deque, node-based). ChatGPT and Claude delivered clean, well-documented basic implementations with thorough explanations. Llama's response was concise but complete, including time complexity analysis. Response times were similar (8-11 seconds) except for Llama, which was notably faster at 1.2 seconds. Overall, Gemini's response was most valuable for its multiple implementation options and comparative analysis.

Email Validation Function

Implements email format validation using regex. Essential for form validation and user input processing.

Prompt:

Create a function to validate an email address using regular expressions

Example

Valid email addresses: user@example.com user.name@example.com user+label@example.com user123@example.com first.last@example.co.uk 123@example.com user@sub.example.com firstname-lastname@example.com user_name@example.com user@example-domain.com Invalid email addresses: user@.com @example.com user@ user.@example.com .user@example.com user@example..com user name@example.com user@example.c user@-example.com user@example_domain.com user@example.com@example.com user..name@example.com user@example. user@.example.com @user@example.com

Performance Results

Create a function to validate an email address using regular expressions

To validate an email address using regular expressions in Python, you can create a function that uses the re module. The regular expression needs to account for the valid email patterns you provided and reject the invalid ones. Here's a function that does that:

import re

def validate_email(email):
    # Regular expression pattern for validating an email address.
    # This pattern covers the valid cases and excludes the invalid ones.
    email_pattern = (
        r"^(?!\.)(?!.*\.\.)(?!.*\s)"
        r"[a-zA-Z0-9._%+-]+"
        r"@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$"
    )

    # Compile the regular expression
    pattern = re.compile(email_pattern)

    # Use fullmatch to ensure the entire email string matches the pattern
    return pattern.fullmatch(email) is not None

# Test examples
valid_emails = [
    "user@example.com",
    "user.name@example.com",
    "user+label@example.com",
    "user123@example.com",
    "first.last@example.co.uk",
    "123@example.com",
    "user@sub.example.com",
    "firstname-lastname@example.com",
    "user_name@example.com",
    "user@example-domain.com"
]

invalid_emails = [
    "user@.com",
    "@example.com",
    "user@",
    "user.@example.com",
    ".user@example.com",
    "user@example..com",
    "user name@example.com",
    "user@example.c",
    "user@-example.com",
    "user@example_domain.com",
    "user@example.com@example.com",
    "user..name@example.com",
    "user@example.",
    "user@.example.com",
    "@user@example.com"
]

print("Testing Valid Emails:")
for email in valid_emails:
    print(email, "->", validate_email(email))

print("\nTesting Invalid Emails:")
for email in invalid_emails:
    print(email, "->", validate_email(email))

Explanation of the regular expression:

  • ^(?!\.): Ensures the local part does not start with a dot.
  • (?!.*\.\.): Ensures there are no consecutive dots in the local part.
  • (?!.*\s): Ensures there are no spaces in the email.
  • [a-zA-Z0-9._%+-]+: Matches the local part of the email, allowing alphanumeric characters and certain special characters (._%+-).
  • @: Requires an '@' character to separate the local part from the domain.
  • [a-zA-Z0-9.-]+: Matches the domain part of the email, allowing alphanumeric characters and hyphens.
  • \.[a-zA-Z]{2,}$: Requires a period followed by at least two alphabetic characters, ensuring a valid top-level domain.

This function will return True for valid email addresses and False for invalid ones based on the criteria you provided.

import re

def validate_email(email):
    # Regular expression pattern for email validation
    pattern = r'^[a-zA-Z0-9][a-zA-Z0-9.+_-]*[a-zA-Z0-9]@[a-zA-Z0-9][a-zA-Z0-9.-]*[a-zA-Z0-9]\.[a-zA-Z]{2,}$'

    # Return True if email matches pattern, False otherwise
    return bool(re.match(pattern, email))

# Test cases
valid_emails = [
    "user@example.com",
    "user.name@example.com", 
    "user+label@example.com",
    "user123@example.com",
    "first.last@example.co.uk",
    "123@example.com",
    "user@sub.example.com",
    "firstname-lastname@example.com",
    "user_name@example.com",
    "user@example-domain.com"
]

invalid_emails = [
    "user@.com",
    "@example.com",
    "user@",
    "user.@example.com",
    ".user@example.com", 
    "user@example..com",
    "user name@example.com",
    "user@example.c",
    "user@-example.com",
    "user@example_domain.com",
    "user@example.com@example.com",
    "user..name@example.com",
    "user@example.",
    "user@.example.com",
    "@user@example.com"
]

# Test valid emails
print("Testing valid emails:")
for email in valid_emails:
    print(f"{email}: {validate_email(email)}")

print("\nTesting invalid emails:")
for email in invalid_emails:
    print(f"{email}: {validate_email(email)}")

Let's break down the regular expression pattern:

  • ^ - Start of string
  • [a-zA-Z0-9] - First character must be alphanumeric
  • [a-zA-Z0-9.+_-]* - Followed by zero or more alphanumeric characters, dots, plus signs, underscores or hyphens
  • [a-zA-Z0-9] - Last character before @ must be alphanumeric
  • @ - @ symbol
  • [a-zA-Z0-9] - First character of domain must be alphanumeric
  • [a-zA-Z0-9.-]* - Followed by zero or more alphanumeric characters, dots or hyphens
  • [a-zA-Z0-9] - Last character before TLD must be alphanumeric
  • \. - Dot separator for TLD
  • [a-zA-Z]{2,} - TLD must be at least 2 characters long and only letters
  • $ - End of string

This regex enforces the following rules:

  • Email must start and end with alphanumeric characters
  • No consecutive dots
  • No leading/trailing dots in local or domain parts
  • Domain must have valid TLD
  • Special characters allowed in local part: ._+-
  • Special characters allowed in domain: .-
  • No spaces or other special characters allowed

The function returns:

  • True for valid email addresses
  • False for invalid email addresses
import re

def is_valid_email(email):
    """
    Validates an email address using a regular expression.

    Args:
        email: The email address to validate.

    Returns:
        True if the email address is valid, False otherwise.
    """

    # Regular expression pattern for email validation.  Explanation below.
    pattern = r"^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$"

    match = re.match(pattern, email)
    return bool(match)



# Test cases (feel free to add more)
valid_emails = [
    "user@example.com",
    "user.name@example.com",
    "user+label@example.com",
    "user123@example.com",
    "first.last@example.co.uk",
    "123@example.com",
    "user@sub.example.com",
    "firstname-lastname@example.com",
    "user_name@example.com",
    "user@example-domain.com",
]

invalid_emails = [
    "user@.com",
    "@example.com",
    "user@",
    "user.@example.com",
    ".user@example.com",
    "user@example..com",
    "user name@example.com",  # Spaces are not allowed
    "user@example.c",
    "user@-example.com",
    "user@example_domain.com",  # Underscores are not allowed in the domain part
    "user@example.com@example.com",
    "user..name@example.com",  # Consecutive dots are not allowed in local part
    "user@example.",  # Must end with a TLD
    "user@.example.com",  # Cannot start local part with a dot
    "@user@example.com" # Cannot start with @
]

for email in valid_emails:
    print(f"'{email}' is valid: {is_valid_email(email)}")

for email in invalid_emails:
    print(f"'{email}' is valid: {is_valid_email(email)}")

Explanation of the Regular Expression:

  • ^: Matches the beginning of the string.
  • [a-zA-Z0-9._%+-]+: Matches one or more alphanumeric characters, dots, underscores, percentage signs, plus or minus signs (for the local part of the email).
  • @: Matches the "@" symbol.
  • [a-zA-Z0-9.-]+: Matches one or more alphanumeric characters, dots, or hyphens (for the domain part).
  • \.[a-zA-Z]{2,}: Matches a dot followed by two or more alphabetic characters (for the top-level domain).
  • $: Matches the end of the string.

This regex is a good starting point and covers many common email formats. However, perfectly validating all possible valid emails with regex is extremely complex and there might be edge cases that it doesn't handle. For truly robust validation in a production environment, you might consider using a dedicated email validation library.

Here's a Python function that uses regular expressions to validate email addresses:

import re

def validate_email(email):
    """
    Validate an email address using a regular expression.

    Args:
        email (str): The email address to validate.

    Returns:
        bool: True if the email address is valid, False otherwise.
    """
    # Regular expression pattern to match a valid email address
    pattern = r"^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$"

    # Check if the email matches the pattern
    if re.match(pattern, email):
        return True
    else:
        return False


# Example usage:
valid_emails = [
    "user@example.com",
    "user.name@example.com",
    "user+label@example.com",
    "user123@example.com",
    "first.last@example.co.uk",
    "123@example.com",
    "user@sub.example.com",
    "firstname-lastname@example.com",
    "user_name@example.com",
    "user@example-domain.com",
]

invalid_emails = [
    "user@.com",
    "@example.com",
    "user@",
    "user.@example.com",
    ".user@example.com",
    "user@example..com",
    "user name@example.com",
    "user@example.c",
    "user@-example.com",
    "user@example_domain.com",
    "user@example.com@example.com",
    "user..name@example.com",
    "user@example.",
    "user@.example.com",
    "@user@example.com",
]

for email in valid_emails:
    print(f"Email: {email}, Valid: {validate_email(email)}")

for email in invalid_emails:
    print(f"Email: {email}, Valid: {validate_email(email)}")

Here's a breakdown of how this regular expression pattern works:

  • ^ asserts the start of the line
  • [a-zA-Z0-9._%+-]+ matches one or more alphanumeric characters, dots, underscores, percent signs, plus signs, or hyphens. This is for the local part of the email (before the @)
  • @ matches the @ symbol literally
  • [a-zA-Z0-9.-]+ matches one or more alphanumeric characters, dots, or hyphens. This is for the domain name
  • \. matches the dot literally (needed because . has a special meaning in regex)
  • [a-zA-Z]{2,} matches the top-level domain (it must be at least 2 characters long)
  • $ asserts the end of the line

AnyModel: Explore and compare over 50 AI models side-by-side.

Budget Results

Create a function to validate an email address using regular expressions

To validate an email address using regular expressions in Python, you can define a function that uses the re module. Below is a sample function called is_valid_email that checks if an email address matches the specified criteria for valid emails:

import re

def is_valid_email(email):
    # Define the regular expression for validating an email address
    email_pattern = r'^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$'

    # Match the email against the pattern
    if re.match(email_pattern, email):
        return True
    else:
        return False

# Test the function with both valid and invalid email addresses
valid_emails = [
    "user@example.com",
    "user.name@example.com",
    "user+label@example.com",
    "user123@example.com",
    "first.last@example.co.uk",
    "123@example.com",
    "user@sub.example.com",
    "firstname-lastname@example.com",
    "user_name@example.com",
    "user@example-domain.com"
]

invalid_emails = [
    "user@.com",
    "@example.com",
    "user@",
    "user.@example.com",
    ".user@example.com",
    "user@example..com",
    "user name@example.com",
    "user@example.c",
    "user@-example.com",
    "user@example_domain.com",
    "user@example.com@example.com",
    "user..name@example.com",
    "user@example.",
    "user@.example.com",
    "@user@example.com"
]

# Check valid emails
print("Valid Emails:")
for email in valid_emails:
    print(f"{email}: {is_valid_email(email)}")

# Check invalid emails
print("\nInvalid Emails:")
for email in invalid_emails:
    print(f"{email}: {is_valid_email(email)}")

Explanation of the Regular Expression:

  • ^: Asserts the start of the string.
  • [a-zA-Z0-9._%+-]+: Matches one or more characters which can be lowercase letters, uppercase letters, digits, and some special characters (., _, %, +, -).
  • @: Matches the '@' symbol.
  • [a-zA-Z0-9.-]+: Matches one or more characters for the domain part that can include letters, digits, hyphens, and dots.
  • \.: Escapes the dot character to match it literally.
  • [a-zA-Z]{2,}$: Matches the top-level domain, which must be at least two characters long (e.g., .com, .co.uk).
  • $: Asserts the end of the string.

Testing the Function:

The provided test emails will validate against the function, logging whether each email is classified as valid or invalid according to the rules defined.

The following Python function uses a regular expression to validate email addresses based on your provided examples. It's important to note that no regex can perfectly validate all valid emails according to the extremely complex and evolving RFC 5322 specification. This regex aims for a good balance between strictness and practical usability.

import re

def is_valid_email(email):
    """
    Validates an email address using a regular expression.

    Args:
        email: The email address to validate.

    Returns:
        True if the email is valid, False otherwise.
    """
    email_regex = r"^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$"
    match = re.match(email_regex, email)
    return bool(match)


# Test cases
valid_emails = [
    "user@example.com",
    "user.name@example.com",
    "user+label@example.com",
    "user123@example.com",
    "first.last@example.co.uk",
    "123@example.com",
    "user@sub.example.com",
    "firstname-lastname@example.com",
    "user_name@example.com",
    "user@example-domain.com",
]

invalid_emails = [
    "user@.com",
    "@example.com",
    "user@",
    "user.@example.com",
    ".user@example.com",
    "user@example..com",
    "user name@example.com",
    "user@example.c",
    "user@-example.com",
    "user@example_domain.com",
    "user@example.com@example.com",
    "user..name@example.com",
    "user@example.",
    "user@.example.com",
    "@user@example.com",
]


for email in valid_emails:
    print(f"'{email}' is valid: {is_valid_email(email)}")

for email in invalid_emails:
    print(f"'{email}' is valid: {is_valid_email(email)}")

This regex breaks down as follows:

  • ^: Matches the beginning of the string.
  • [a-zA-Z0-9._%+-]+: Matches one or more alphanumeric characters, periods, underscores, percentage signs, plus or minus signs (for the username part).
  • @: Matches the "@" symbol.
  • [a-zA-Z0-9.-]+: Matches one or more alphanumeric characters, periods, or hyphens (for the domain part).
  • \.: Matches a literal period (escaped because it's a special character in regex).
  • [a-zA-Z]{2,}$: Matches two or more alphabetic characters (for the top-level domain).
  • $: Matches the end of the string.

Remember that while this regex is a good starting point, for truly robust email validation, consider using a dedicated email validation library that accounts for the nuances of internationalized domain names and other edge cases. This function provides a reasonable level of validation for common email formats.

Here's a Python function to validate email addresses using regular expressions:

import re

def validate_email(email):
    # Regular expression pattern for email validation
    pattern = r'^[a-zA-Z0-9.+_-]+@[a-zA-Z0-9-]+(\.[a-zA-Z0-9-]+)*\.[a-zA-Z]{2,}$'

    # Check if the email matches the pattern
    if re.match(pattern, email):
        # Additional checks for specific invalid cases
        # Prevent consecutive dots
        if '..' in email:
            return False

        # Prevent starting/ending with a dot in local part
        local_part = email.split('@')[0]
        if local_part.startswith('.') or local_part.endswith('.'):
            return False

        # Prevent invalid domain start/end
        domain = email.split('@')[1]
        if domain.startswith('.') or domain.startswith('-') or domain.endswith('.'):
            return False

        return True
    return False

# Test cases
valid_emails = [
    'user@example.com',
    'user.name@example.com',
    'user+label@example.com',
    'user123@example.com',
    'first.last@example.co.uk',
    '123@example.com',
    'user@sub.example.com',
    'firstname-lastname@example.com',
    'user_name@example.com',
    'user@example-domain.com'
]

invalid_emails = [
    'user@.com',
    '@example.com',
    'user@',
    'user.@example.com',
    '.user@example.com',
    'user@example..com',
    'user name@example.com',
    'user@example.c',
    'user@-example.com',
    'user@example_domain.com',
    'user@example.com@example.com',
    'user..name@example.com',
    'user@example.',
    'user@.example.com',
    '@user@example.com'
]

# Validate emails
print("Valid Emails:")
for email in valid_emails:
    print(f"{email}: {validate_email(email)}")

print("\nInvalid Emails:")
for email in invalid_emails:
    print(f"{email}: {validate_email(email)}")

The email validation function uses a regular expression with the following key components:

  • ^ - Start of the string
  • [a-zA-Z0-9.+_-]+ - Local part (before @) allows letters, numbers, and some special characters
  • @ - Literal @ symbol
  • [a-zA-Z0-9-]+ - Domain name allows letters, numbers, and hyphens
  • (\.[a-zA-Z0-9-]+)* - Allows subdomains
  • \.[a-zA-Z]{2,} - Top-level domain with at least 2 characters
  • $ - End of the string

Additional checks are implemented to handle specific edge cases not caught by the regex:

  • Prevent consecutive dots
  • Prevent dots at the start or end of the local part
  • Prevent invalid domain starts or ends

The function returns True for valid email addresses and False for invalid ones.

When you run this script, it will test and print the validation results for both valid and invalid email addresses.

Here's a function in Python that validates an email address using a regular expression:

import re

def validate_email(email):
    """
    Validate an email address using a regular expression.

    Args:
    email (str): The email address to be validated.

    Returns:
    bool: True if the email address is valid, False otherwise.
    """

    # Regular expression pattern for validating email addresses
    email_regex = re.compile(
        r"^[a-zA-Z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-zA-Z0-9!#$%&'*+/=?^_`{|}~-]+)*" + 
        r"(?:\.[a-zA-Z0-9!#$%&'*+/=?^_`{|}~-]+)*\.[a-zA-Z0-9!#$%&'*+/=?^_`{|}~-]+$"
    )

    # Return True if the email matches the regular expression pattern, False otherwise
    return(bool(email_regex.match(email)))


# Test cases
valid_emails = [
    "user@example.com",
    "user.name@example.com",
    "user+label@example.com",
    "user123@example.com",
    "first.last@example.co.uk",
    "123@example.com",
    "user@sub.example.com",
    "firstname-lastname@example.com",
    "user_name@example.com",
    "user@example-domain.com",
]

invalid_emails = [
    "user@.com",
    "@example.com",
    "user@",
    "user @.example.com",
    ".user@example.com",
    "user@example..com",
    "use name@example.com",
    "user@example.c",
    "user@-example.com",
    "user@example_domain.com",
    "user@example.com@example.com",
    "user..name@example.com",
    "user@example.",
    "@user@example.com",
    "user@.example.com",
]

print("Valid email addresses:")
for email in valid_emails:
    print(f"Email: {email}, Valid: {validate_email(email)}")

print("\nInvalid email addresses:")
for email in invalid_emails:
    print(f"Email: {email}, Valid: {validate_email(email)}")

In this code, the validate_email function uses the following regular expression pattern to match valid email addresses:

  • ^ matches the start of the string.
  • [a-zA-Z0-9!#$%&'*+/=?^_{|}~-]+` matches one or more alphanumeric characters or special characters that can exist in an email local part (before the "@" symbol).
  • (?:\.[a-zA-Z0-9!#$%&'*+/=?^_{|}~-]+)*` matches zero or more occurrences of a period . followed by one or more alphanumeric characters or special characters that can exist in an email local part (before the "@" symbol).
  • (\.[a-zA-Z0-9!#$%&'*+/=?^_{|}~-]+)*` matches zero or more occurrences of a period . followed by one or more alphanumeric characters or special characters that can exist in an email local part (before the "@" symbol).
  • [a-zA-Z0-9!#$%&'*+/=?^_{|}~-]+` matches one or more alphanumeric characters or special characters that can exist in an email domain name (after the "@" symbol).
  • \.[a-zA-Z0-9!#$%&'*+/=?^_{|}~-]+$` matches a period immediately followed by the start of the email domain name and one or more alphanumeric characters or special characters that can exist in an email domain name.
  • $ matches the end of the string.

AnyModel: Explore and compare over 50 AI models side-by-side.

Performance Tier

All models successfully created email validation functions using regex, but with varying levels of sophistication:

ChatGPT 4.0 provided the most comprehensive solution with advanced pattern matching to prevent consecutive dots and leading/trailing dots. Its explanation was detailed and included extensive test cases.

Claude 3.5 Sonnet implemented strict validation requiring alphanumeric characters at string boundaries, offering good security but potentially rejecting some valid emails.

Gemini 1.5 Pro provided a simpler but functional solution with clear documentation and included a caveat about regex limitations for email validation.

Llama 3.1 70B delivered the fastest response (3323ms vs 13000-15000ms for others) with a basic but working implementation and clear pattern explanation.

Budget Tier

ChatGPT 4o Mini and Claude 3.5 Haiku provided the most balanced solutions, with comprehensive regex patterns and clear explanations. Gemini 1.5 Flash offered similar functionality but included valuable context about RFC 5322 limitations. Llama 3.1 8B generated the fastest response (1391ms) but its regex pattern was overly permissive with special characters. ChatGPT and Claude included additional validation checks beyond regex, making their solutions more robust for real-world use. Response times varied significantly, with Llama being notably faster but less refined than its competitors.

Merge Sort Algorithm

Implements the efficient merge sort algorithm. Important for understanding divide-and-conquer algorithms and sorting techniques.

Prompt:

Write a merge sort implementation in the programming language of your choice

Example

42, 15, 73, 29, 8, 51, 94, 33, 17, 60

Performance Results

Write a merge sort implementation in the programming language of your choice

Certainly! I'll provide a Python implementation of the merge sort algorithm, which can be used to sort the list of numbers you've provided: [42, 15, 73, 29, 8, 51, 94, 33, 17, 60]. Here is the code:

def merge_sort(arr):
    if len(arr) > 1:
        mid = len(arr) // 2  # Finding the middle of the array
        left_half = arr[:mid]  # Dividing the elements into 2 halves
        right_half = arr[mid:]

        merge_sort(left_half)  # Sorting the first half
        merge_sort(right_half) # Sorting the second half

        i = j = k = 0

        # Copy data to temp arrays L[] and R[]
        while i < len(left_half) and j < len(right_half):
            if left_half[i] < right_half[j]:
                arr[k] = left_half[i]
                i += 1
            else:
                arr[k] = right_half[j]
                j += 1
            k += 1

        # Checking if any element was left in the left_half
        while i < len(left_half):
            arr[k] = left_half[i]
            i += 1
            k += 1

        # Checking if any element was left in the right_half
        while j < len(right_half):
            arr[k] = right_half[j]
            j += 1
            k += 1

def print_list(arr):
    for i in range(len(arr)):
        print(arr[i], end=" ")
    print()

# Main Code
list_of_numbers = [42, 15, 73, 29, 8, 51, 94, 33, 17, 60]
print("Original list:")
print_list(list_of_numbers)

merge_sort(list_of_numbers)
print("Sorted list:")
print_list(list_of_numbers)

This implementation defines a merge_sort function that recursively divides the list into halves until it is sorted. The function handles the merging process to ensure that each split part of the array is sorted before merging, resulting in a fully sorted array. The list [42, 15, 73, 29, 8, 51, 94, 33, 17, 60] will be sorted into [8, 15, 17, 29, 33, 42, 51, 60, 73, 94].

Here's a merge sort implementation in Python, including a demonstration with the given numbers:

def merge_sort(arr):
    # Base case: if array has 1 or fewer elements, it's already sorted
    if len(arr) <= 1:
        return arr

    # Find middle point to divide array into two halves
    mid = len(arr) // 2

    # Recursively sort the two halves
    left = merge_sort(arr[:mid])
    right = merge_sort(arr[mid:])

    # Merge the sorted halves
    return merge(left, right)

def merge(left, right):
    result = []
    i = j = 0

    # Compare elements from both arrays and merge them in sorted order
    while i < len(left) and j < len(right):
        if left[i] <= right[j]:
            result.append(left[i])
            i += 1
        else:
            result.append(right[j])
            j += 1

    # Add remaining elements from left array, if any
    result.extend(left[i:])
    # Add remaining elements from right array, if any
    result.extend(right[j:])

    return result

# Test the implementation
numbers = [42, 15, 73, 29, 8, 51, 94, 33, 17, 60]
sorted_numbers = merge_sort(numbers)
print(f"Original array: {numbers}")
print(f"Sorted array: {sorted_numbers}")

Output:

Original array: [42, 15, 73, 29, 8, 51, 94, 33, 17, 60]
Sorted array: [8, 15, 17, 29, 33, 42, 51, 60, 73, 94]

This implementation follows these steps:

  1. The merge_sort function recursively divides the array into two halves until each subarray has one element
  2. The merge function combines two sorted arrays into one sorted array
  3. The algorithm comparison sorts with a time complexity of O(n log n)
  4. Space complexity is O(n) as it needs temporary arrays during merging

The process for the given numbers would be:

  1. Split: [42, 15, 73, 29, 8] | [51, 94, 33, 17, 60]
  2. Further split and sort smaller subarrays
  3. Merge back together while maintaining order
  4. Final result is a fully sorted array
def merge_sort(arr):
    """Sorts a list using the merge sort algorithm."""
    if len(arr) <= 1:
        return arr

    mid = len(arr) // 2
    left = arr[:mid]
    right = arr[mid:]

    left = merge_sort(left)
    right = merge_sort(right)

    return merge(left, right)


def merge(left, right):
    """Merges two sorted lists into a single sorted list."""
    result = []
    i = j = 0

    while i < len(left) and j < len(right):
        if left[i] < right[j]:
            result.append(left[i])
            i += 1
        else:
            result.append(right[j])
            j += 1

    result.extend(left[i:])  # Add any remaining elements from left
    result.extend(right[j:]) # Add any remaining elements from right

    return result



# Example usage with your provided numbers:
numbers = [42, 15, 73, 29, 8, 51, 94, 33, 17, 60]
sorted_numbers = merge_sort(numbers)
print(sorted_numbers)  # Output: [8, 15, 17, 29, 33, 42, 51, 60, 73, 94]

Explanation:

  1. merge_sort(arr):
  • Base Case: If the list has 0 or 1 elements, it's already sorted, so return it.
  • Divide: Split the list into two halves, left and right.
  • Conquer: Recursively call merge_sort on both halves to sort them.
  • Combine: Merge the sorted left and right halves using the merge function.
  1. merge(left, right):
  • Initialization: Create an empty result list and indices i and j to track the current elements in left and right.
  • Comparison and Merging: While both left and right have elements remaining:
    • Compare left[i] and right[j].
    • Append the smaller element to result and increment the corresponding index (i or j).
  • Handling Remaining Elements: After one of the lists is exhausted, append the remaining elements from the other list to result. This is important to ensure all elements are included in the sorted output.
  • Return: Return the merged and sorted result list.

Key improvements in this version:

  • Clearer variable names: Using left and right instead of L and R improves readability.
  • Comments: Added comments to explain the logic of each part of the code.
  • Efficiency: The use of extend() to add remaining elements at the end of the merge function is more efficient than appending one element at a time.
  • Example Usage: Includes a clear example with your provided numbers and output.

Merge Sort Implementation in Python

Here is a high-quality, readable, and well-documented implementation of the merge sort algorithm in Python.

def merge_sort(arr):
    """
    Sorts an array using the merge sort algorithm.

    Args:
        arr (list): The input array to be sorted.

    Returns:
        list: The sorted array.
    """
    # If the array has one or zero elements, it is already sorted
    if len(arr) <= 1:
        return arr

    # Find the middle point of the array
    mid = len(arr) // 2

    # Divide the array into two halves
    left_half = arr[:mid]
    right_half = arr[mid:]

    # Recursively sort the two halves
    left_half = merge_sort(left_half)
    right_half = merge_sort(right_half)

    # Merge the sorted halves
    return merge(left_half, right_half)


def merge(left, right):
    """
    Merges two sorted arrays into a single sorted array.

    Args:
        left (list): The first sorted array.
        right (list): The second sorted array.

    Returns:
        list: The merged and sorted array.
    """
    merged = []
    left_index = 0
    right_index = 0

    # Merge smaller elements first
    while left_index < len(left) and right_index < len(right):
        if left[left_index] < right[right_index]:
            merged.append(left[left_index])
            left_index += 1
        else:
            merged.append(right[right_index])
            right_index += 1

    # If there are remaining elements in the left array, append them
    while left_index < len(left):
        merged.append(left[left_index])
        left_index += 1

    # If there are remaining elements in the right array, append them
    while right_index < len(right):
        merged.append(right[right_index])
        right_index += 1

    return merged


# Example usage:
arr = [42, 15, 73, 29, 8, 51, 94, 33, 17, 60]
sorted_arr = merge_sort(arr)
print("Sorted array:", sorted_arr)

Output:

Sorted array: [8, 15, 17, 29, 33, 42, 51, 60, 73, 94]

Explanation:

  1. The merge_sort function takes an array as input and checks if it has one or zero elements. If so, it returns the array as it is already sorted.
  2. The array is divided into two halves using the mid index.
  3. The merge_sort function is called recursively for the two halves, left_half and right_half.
  4. The sorted halves are then merged using the merge function.
  5. The merge function takes two sorted arrays, left and right, and merges them into a single sorted array.
  6. The merge function uses two indices, left_index and right_index, to compare elements from the left and right arrays and append the smaller element to the merged array.
  7. If there are remaining elements in either the left or right array, they are appended to the merged array.
  8. The final merged and sorted array is returned.

AnyModel: Explore and compare over 50 AI models side-by-side.

Budget Results

Write a merge sort implementation in the programming language of your choice

Here is an implementation of the Merge Sort algorithm in Python, which sorts the given list of numbers:

def merge_sort(arr):
    if len(arr) > 1:
        mid = len(arr) // 2  # Finding the mid of the array
        left_half = arr[:mid]  # Dividing the elements into 2 halves
        right_half = arr[mid:]

        # Recursive call on each half
        merge_sort(left_half)
        merge_sort(right_half)

        # Initialize pointers for left_half, right_half and main array
        i = j = k = 0

        # Copy data to temp arrays L[] and R[]
        while i < len(left_half) and j < len(right_half):
            if left_half[i] < right_half[j]:
                arr[k] = left_half[i]
                i += 1
            else:
                arr[k] = right_half[j]
                j += 1
            k += 1

        # Checking if any element was left
        while i < len(left_half):
            arr[k] = left_half[i]
            i += 1
            k += 1

        while j < len(right_half):
            arr[k] = right_half[j]
            j += 1
            k += 1

# Given list of numbers
numbers = [42, 15, 73, 29, 8, 51, 94, 33, 17, 60]

# Calling merge_sort function
merge_sort(numbers)

# Printing the sorted list
print("Sorted list:", numbers)

How the Code Works:

  • The merge_sort function takes an array as input and divides it into two halves recursively until each half contains a single element (base case of recursion).
  • It then merges these halves back together in sorted order:
  • Pointers are used to track the current index of each half and the main array.
  • The smaller element between the two halves is added to the main array, and the corresponding pointer is incremented.
  • Once all elements from one of the halves are exhausted, the remaining elements from the other half are copied to the main array.

Output

When you run this code with the given list of numbers, you will get the following output:

Sorted list: [8, 15, 17, 29, 33, 42, 51, 60, 73, 94]

Here's a merge sort implementation in Python, along with its application to the provided sample data:

def merge_sort(arr):
    """
    Sorts a list using the merge sort algorithm.

    Args:
      arr: The list to be sorted.

    Returns:
      A new sorted list.  The original list is not modified.
    """
    if len(arr) <= 1:
        return arr

    mid = len(arr) // 2
    left_half = arr[:mid]
    right_half = arr[mid:]

    left_half = merge_sort(left_half)
    right_half = merge_sort(right_half)

    return merge(left_half, right_half)


def merge(left, right):
    """
    Merges two sorted lists into a single sorted list.

    Args:
      left: The first sorted list.
      right: The second sorted list.

    Returns:
      A new sorted list containing all elements from left and right.
    """
    merged = []
    i = j = 0

    while i < len(left) and j < len(right):
        if left[i] <= right[j]:
            merged.append(left[i])
            i += 1
        else:
            merged.append(right[j])
            j += 1

    # Add any remaining elements from left or right
    merged.extend(left[i:])
    merged.extend(right[j:])

    return merged


# Example usage:
data = [42, 15, 73, 29, 8, 51, 94, 33, 17, 60]
sorted_data = merge_sort(data)
print(f"Original data: {data}")
print(f"Sorted data: {sorted_data}")

This code first defines the merge_sort function, which recursively divides the input list into smaller sublists until each sublist contains only one element (which is inherently sorted). Then, the merge function combines these sorted sublists back together, producing a fully sorted list. The example usage demonstrates how to use the function and prints both the original and sorted lists. The output will be:

Original data: [42, 15, 73, 29, 8, 51, 94, 33, 17, 60]
Sorted data: [8, 15, 17, 29, 33, 42, 51, 60, 73, 94]

Here's a merge sort implementation in Python with the given input array:

def merge_sort(arr):
    # Base case: if the array has 1 or fewer elements, it's already sorted
    if len(arr) <= 1:
        return arr

    # Divide the array into two halves
    mid = len(arr) // 2
    left_half = arr[:mid]
    right_half = arr[mid:]

    # Recursively sort both halves
    left_half = merge_sort(left_half)
    right_half = merge_sort(right_half)

    # Merge the sorted halves
    return merge(left_half, right_half)

def merge(left, right):
    result = []
    i, j = 0, 0

    # Compare and merge elements from both halves
    while i < len(left) and j < len(right):
        if left[i] <= right[j]:
            result.append(left[i])
            i += 1
        else:
            result.append(right[j])
            j += 1

    # Add remaining elements from left half, if any
    result.extend(left[i:])

    # Add remaining elements from right half, if any
    result.extend(right[j:])

    return result

# Input array
arr = [42, 15, 73, 29, 8, 51, 94, 33, 17, 60]

# Sort the array
sorted_arr = merge_sort(arr)

# Print the sorted array
print("Original array:", arr)
print("Sorted array:  ", sorted_arr)

When you run this code, it will output:

Original array: [42, 15, 73, 29, 8, 51, 94, 33, 17, 60]
Sorted array:   [8, 15, 17, 29, 33, 42, 51, 60, 73, 94]

Key characteristics of merge sort:

  • Time complexity: O(n log n)
  • Space complexity: O(n)
  • Stable sorting algorithm
  • Divide and conquer approach

The algorithm works by:

  1. Recursively dividing the array into two halves
  2. Sorting each half
  3. Merging the sorted halves back together
  4. Comparing and placing elements in the correct order during the merge process

Here's a merge sort implementation in Python:

def merge_sort(arr):
    """
    Sorts an array using the merge sort algorithm.

    Args:
    arr (list): The array to be sorted.

    Returns:
    list: The sorted array.
    """

    # If the array has one or zero elements, it's already sorted
    if len(arr) <= 1:
        return arr

    # Find the middle point
    mid = len(arr) // 2

    # Divide the array into two halves
    left_half = arr[:mid]
    right_half = arr[mid:]

    # Recursively sort the two halves
    left_half = merge_sort(left_half)
    right_half = merge_sort(right_half)

    # Merge the sorted halves
    return merge(left_half, right_half)


def merge(left, right):
    """
    Merges two sorted arrays into one sorted array.

    Args:
    left (list): The first sorted array.
    right (list): The second sorted array.

    Returns:
    list: The merged sorted array.
    """

    # Initialize an empty list to store the merged array
    merged = []

    # Initialize indices for the left and right arrays
    left_index = 0
    right_index = 0

    # Merge the arrays
    while left_index < len(left) and right_index < len(right):
        if left[left_index] < right[right_index]:
            merged.append(left[left_index])
            left_index += 1
        else:
            merged.append(right[right_index])
            right_index += 1

    # Append any remaining elements from the left array
    while left_index < len(left):
        merged.append(left[left_index])
        left_index += 1

    # Append any remaining elements from the right array
    while right_index < len(right):
        merged.append(right[right_index])
        right_index += 1

    # Return the merged array
    return merged


# Test the merge sort function
arr = [42, 15, 73, 29, 8, 51, 94, 33, 17, 60]
sorted_arr = merge_sort(arr)
print("Sorted array:", sorted_arr)

Output:

Sorted array: [8, 15, 17, 29, 33, 42, 51, 60, 73, 94]

This implementation uses a top-down approach, dividing the array into two halves and recursively sorting each half. The merge function is used to merge the sorted halves, ensuring that the resulting array is sorted in ascending order.

AnyModel: Explore and compare over 50 AI models side-by-side.

Performance Tier

Analyzing the merge sort implementations across models shows interesting variations in approach and quality. ChatGPT 4o and Claude 3.5 provided similar clean, efficient implementations with good documentation. Gemini 1.5 Pro offered the most detailed explanation but took longest to generate (16.5s). Llama 3.1 70B was fastest (3.2s) and provided the most professional documentation with docstrings. All implementations correctly sort the sample array, but differ in style - from Claude's concise approach to Llama's verbose documentation. Llama appears strongest for documented code, while Claude wins for efficient, readable implementation.

Budget Tier

All models successfully implemented merge sort in Python with correct functionality. ChatGPT 4o Mini and Claude provided detailed implementations with good code organization and documentation. Gemini offered the most comprehensive solution with thorough docstrings and clear output formatting. Llama 3.1 was notably faster (1075ms vs 7000-12000ms for others) but provided a more basic implementation. All included example usage with the same test array and produced identical sorted output. Performance-wise, Gemini took longest to generate (12719ms) while maintaining highest code quality.

Roman Numeral Converter

Develops a number system conversion utility. Useful for formatting and display applications.

Prompt:

Create a function that converts a number to its Roman numeral representation

Performance Results

Create a function that converts a number to its Roman numeral representation

To create a function that converts a number to its Roman numeral representation, we need to map decimal values to their corresponding Roman numeral symbols. Roman numerals are represented by combinations of the following symbols and their values:

  • I: 1
  • V: 5
  • X: 10
  • L: 50
  • C: 100
  • D: 500
  • M: 1000

Roman numerals are typically formed by combining these symbols and applying a few rules:

  • Smaller numbers before larger numbers indicate subtraction (e.g., IV for 4).
  • Larger numbers before smaller numbers indicate addition (e.g., VI for 6).

Let's implement a function in Python to convert numbers to Roman numerals:

def int_to_roman(num):
    if not (1 <= num <= 3999):
        raise ValueError("Number out of range (must be 1...3999)")

    roman_numerals = [
        (1000, 'M'), (900, 'CM'), (500, 'D'), (400, 'CD'),
        (100, 'C'), (90, 'XC'), (50, 'L'), (40, 'XL'),
        (10, 'X'), (9, 'IX'), (5, 'V'), (4, 'IV'),
        (1, 'I')
    ]

    result = ""
    for value, symbol in roman_numerals:
        while num >= value:
            result += symbol
            num -= value
    return result

# Example usage:
print(int_to_roman(3549))  # Should output: MMMDXLIX

This function works by iterating over a list of tuples that pair each Roman numeral with its integer value. For each value-symbol pair, the function subtracts the value from the input number as many times as possible and appends the corresponding symbol to the result string. This continues until the input number is reduced to zero, and the fully formed Roman numeral is returned. This method handles numbers from 1 to 3999, as classic Roman numerals do not represent zero or negative numbers, nor do they extend beyond 3999 without additional notation.

def to_roman(num):
    if not 0 < num < 4000:
        raise ValueError("Number must be between 1 and 3999")

    roman_numerals = {
        1000: 'M',
        900: 'CM',
        500: 'D', 
        400: 'CD',
        100: 'C',
        90: 'XC',
        50: 'L',
        40: 'XL',
        10: 'X',
        9: 'IX',
        5: 'V',
        4: 'IV',
        1: 'I'
    }

    result = ''

    for value, numeral in roman_numerals.items():
        while num >= value:
            result += numeral
            num -= value

    return result

Here's how the function works:

  1. First we check if the input number is valid (between 1 and 3999)

  2. We define a dictionary mapping integer values to their Roman numeral representations, including special cases like 900 (CM) and 400 (CD)

  3. Iterate through the dictionary in descending order:

  • While the input number is greater than or equal to current value
  • Add the corresponding Roman numeral to result string
  • Subtract that value from the input number

Example usage:

print(to_roman(2023))  # Returns "MMXXIII"
print(to_roman(444))   # Returns "CDXLIV"
print(to_roman(99))    # Returns "XCIX"

The function handles all numbers correctly from 1 to 3999, including edge cases and subtractive notation (like using IV for 4 instead of IIII).

Key points:

  • Time complexity is O(1) since the dictionary size is fixed
  • Space complexity is O(1) as the output size is bounded
  • Handles standard Roman numeral rules including subtractive notation
  • Input validation prevents invalid numbers
def to_roman(num):
    """Converts an integer to its Roman numeral equivalent.

    Args:
        num: An integer between 1 and 3999 (inclusive).

    Returns:
        A string representing the Roman numeral equivalent of the input number.
        Returns an empty string if the input is invalid.
    """

    if not 1 <= num <= 3999:
        return ""  # Handle invalid input

    roman_map = { 1: 'I', 4: 'IV', 5: 'V', 9: 'IX', 10: 'X', 40: 'XL', 50: 'L', 90: 'XC', 100: 'C', 400: 'XD', 500: 'D', 900: 'CM', 1000: 'M'}

    integers = sorted(roman_map, reverse=True)
    result = ""

    for integer in integers:
        while num >= integer:
            result += roman_map[integer]
            num -= integer

    return result



# Test cases
print(to_roman(3))       # Output: III
print(to_roman(4))       # Output: IV
print(to_roman(9))       # Output: IX
print(to_roman(58))      # Output: LVIII
print(to_roman(1994))   # Output: MCMXCIV
print(to_roman(3999))  # Output: MMMCMXCIX
print(to_roman(4000))  # Output: (empty string)
print(to_roman(0)) # Output: (empty string)

Key improvements in this version:

  • Handles Invalid Input: Now explicitly checks if the input number is within the valid range (1 to 3999) and returns an empty string if it's not. This is crucial for robustness.
  • Clearer Variable Names: Uses integers and roman_map for better readability.
  • Sorted Dictionary Keys: Sorts the keys (integers) of the roman_map in reverse order. This ensures the largest values are checked first, preventing incorrect conversions (e.g., 9 being represented as VIV instead of IX).
  • More Efficient Conversion: The while loop efficiently subtracts the largest possible Roman numeral value in each iteration, making the conversion process more concise.
  • Comprehensive Test Cases: Includes several test cases to demonstrate the function's handling of various numbers, including edge cases and invalid input.

This improved version addresses the potential issues of the previous versions and provides a more robust and efficient solution for converting integers to Roman numerals.

Number to Roman Numeral Conversion Function

Here is a Python function that converts an integer to its Roman numeral representation:

def int_to_roman(num):
    """
    Converts an integer to its Roman numeral representation.

    Args:
        num (int): The number to convert.

    Returns:
        str: The Roman numeral representation of the number.

    Raises:
        ValueError: If the number is not an integer or is not in the range 1-3999.

    Example:
        >>> int_to_roman(4)
        'IV'
        >>> int_to_roman(9)
        'IX'
        >>> int_to_roman(13)
        'XIII'
        >>> int_to_roman(44)
        'XLIV'
        >>> int_to_roman(1000)
        'M'
    """
    if not isinstance(num, int) or not 1 <= num <= 3999:
        raise ValueError("Number must be an integer in the range 1-3999")

    roman_numerals = {
        1000: 'M',
        900: 'CM',
        500: 'D',
        400: 'CD',
        100: 'C',
        90: 'XC',
        50: 'L',
        40: 'XL',
        10: 'X',
        9: 'IX',
        5: 'V',
        4: 'IV',
        1: 'I'
    }

    roman_num = ''
    for value, numeral in roman_numerals.items():
        while num >= value:
            roman_num += numeral
            num -= value

    return roman_num

# Test the function
print(int_to_roman(4))  # Outputs: IV
print(int_to_roman(9))  # Outputs: IX
print(int_to_roman(13))  # Outputs: XIII
print(int_to_roman(44))  # Outputs: XLIV
print(int_to_roman(1000))  # Outputs: M

Explanation:

This function works by looping over the Roman numerals in descending order of value and adding the numeral to the result for each value that fits into the remaining number. This process is repeated until the number is reduced to 0.

The function also includes error checking to ensure that the input is a valid integer in the range 1-3999.

AnyModel: Explore and compare over 50 AI models side-by-side.

Budget Results

Create a function that converts a number to its Roman numeral representation

To convert a number to its Roman numeral representation, you can create a function in Python. Below is a simple implementation of such a function.

def int_to_roman(num):
    # Define a mapping of integers to Roman numerals
    val = [
        1000, 900, 500, 400,
        100, 90, 50, 40,
        10, 9, 5, 4,
        1
    ]
    syms = [
        "M", "CM", "D", "CD",
        "C", "XC", "L", "XL",
        "X", "IX", "V", "IV",
        "I"
    ]

    roman_numeral = ""

    # Iterate over the values and symbols
    for i in range(len(val)):
        while num >= val[i]:
            roman_numeral += syms[i]
            num -= val[i]

    return roman_numeral

# Example usage:
print(int_to_roman(1994))  # Output: MCMXCIV

Explanation:

  1. Mapping Values: The val list contains the integer values of Roman numerals, and the syms list contains the corresponding Roman numeral symbols.
  2. Loop Through Values: The function iterates through the val list to find the largest value that fits into num. For each value:
  • It appends the corresponding symbol to the roman_numeral string.
  • It subtracts the value from num.
  1. Result: The function continues until it has converted the entire number, and then returns the resulting Roman numeral as a string.

You can call the function with any integer in the range of 1 to 3999 to get its Roman numeral representation.

Several approaches can create a function to convert a number to its Roman numeral representation. Here are two versions: one using a simple iterative approach and another using a more concise dictionary-based approach.

Version 1: Iterative Approach

This version iterates through the Roman numeral values in descending order, subtracting as many instances of each value as possible.

def int_to_roman(num):
    """Converts an integer to its Roman numeral representation.

    Args:
        num: The integer to convert (1 <= num <= 3999).

    Returns:
        The Roman numeral representation of the integer as a string.  Returns an error message if the input is invalid.
    """
    if not 1 <= num <= 3999:
        return "Input must be between 1 and 3999"

    roman_map = { 1: 'I', 4: 'IV', 5: 'V', 9: 'IX', 10: 'X', 40: 'XL', 50: 'L', 90: 'XC', 100: 'C', 400: 'XD', 500: 'D', 900: 'CM', 1000: 'M'}
    integers = list(roman_map)
    symbols = list(roman_map.values())

    i = 12
    result = ""

    while num != 0:
        if integers[i] <= num:
            result += symbols[i]
            num -= integers[i]
        else:
            i -= 1

    return result


# Example usage
print(int_to_roman(1))      # Output: I
print(int_to_roman(4))      # Output: IV
print(int_to_roman(9))      # Output: IX
print(int_to_roman(58))     # Output: LVIII
print(int_to_roman(1994))   # Output: MCMXCIV
print(int_to_roman(3999))  # Output: MMMCMXCIX
print(int_to_roman(0))      #Output: Input must be between 1 and 3999
print(int_to_roman(4000))   #Output: Input must be between 1 and 3999

Version 2: Dictionary-Based Approach (More Concise)

This version uses a dictionary to map integer values to their Roman numeral equivalents and processes the conversion more efficiently.

def int_to_roman_dict(num):
    """Converts an integer to its Roman numeral representation using a dictionary.

    Args:
        num: The integer to convert (1 <= num <= 3999).

    Returns:
        The Roman numeral representation of the integer as a string. Returns an error message if the input is invalid.
    """
    if not 1 <= num <= 3999:
        return "Input must be between 1 and 3999"

    roman_map = { 1000: 'M', 900: 'CM', 500: 'D', 400: 'CD', 100: 'C', 90: 'XC', 50: 'L', 40: 'XL', 10: 'X', 9: 'IX', 5: 'V', 4: 'IV', 1: 'I'}

    result = ""
    for value, symbol in roman_map.items():
        while num >= value:
            result += symbol
            num -= value
    return result

# Example usage (same output as Version 1)
print(int_to_roman_dict(1))      # Output: I
print(int_to_roman_dict(4))      # Output: IV
print(int_to_roman_dict(9))      # Output: IX
print(int_to_roman_dict(58))     # Output: LVIII
print(int_to_roman_dict(1994))   # Output: MCMXCIV
print(int_to_roman_dict(3999))  # Output: MMMCMXCIX
print(int_to_roman_dict(0))      #Output: Input must be between 1 and 3999
print(int_to_roman_dict(4000))   #Output: Input must be between 1 and 3999

Both versions achieve the same result but use slightly different approaches. The dictionary-based approach is generally considered more readable and efficient for this specific problem. Choose the version that best suits your coding style and understanding. Remember that both functions include error handling for inputs outside the valid range (1-3999).

Here's a Python function to convert numbers to Roman numerals:

def num_to_roman(num):
    # Define Roman numeral mappings
    roman_map = [
        (1000, 'M'),
        (900, 'CM'),
        (500, 'D'),
        (400, 'CD'),
        (100, 'C'),
        (90, 'XC'),
        (50, 'L'),
        (40, 'XL'),
        (10, 'X'),
        (9, 'IX'),
        (5, 'V'),
        (4, 'IV'),
        (1, 'I')
    ]

    # Check for valid input range
    if not 0 < num < 4000:
        raise ValueError("Number must be between 1 and 3999")

    # Build Roman numeral representation
    roman_num = ''
    for value, symbol in roman_map:
        while num >= value:
            roman_num += symbol
            num -= value

    return roman_num

# Example usage
print(num_to_roman(42))    # Output: XLII
print(num_to_roman(1984))  # Output: MCMLXXXIV
print(num_to_roman(3999))  # Output: MMMCMXCIX

This implementation has several key features:

  1. Uses a comprehensive mapping of decimal values to Roman numeral symbols
  2. Handles special cases like 4 (IV), 9 (IX), 40 (XL), etc.
  3. Validates input range (1-3999)
  4. Efficiently converts numbers by subtracting largest possible values
  5. Works with a wide range of numbers

The function handles conversion by:

  • Checking input validity
  • Iterating through predefined value-symbol pairs
  • Repeatedly adding symbols and reducing the number

Time complexity: O(1) Space complexity: O(1)

Roman Numeral Converter Function

Here's a Python function that converts an integer to its Roman numeral representation:

def int_to_roman(int_num):
    """
    Convert an integer to its Roman numeral representation.

    Args:
        int_num (int): The number to convert.

    Returns:
        str: The Roman numeral representation of the input number.

    Raises:
        ValueError: If the input number is not a positive integer.
    """
    if not isinstance(int_num, int) or int_num <= 0:
        raise ValueError("Input must be a positive integer.")

    roman_numerals = {
        1000: 'M', 900: 'CM', 500: 'D', 400: 'CD',
        100: 'C', 90: 'XC', 50: 'L', 40: 'XL',
        10: 'X', 9: 'IX', 5: 'V', 4: 'IV', 1: 'I'
    }

    roman_num = ''
    for value, numeral in roman_numerals.items():
        while int_num >= value:
            roman_num += numeral
            int_num -= value

    return roman_num

Example Use Cases

# Convert 2024 to Roman numeral
print(int_to_roman(2024))  # MMXXIV

# Convert 1000 to Roman numeral
print(int_to_roman(1000))  # M

# Convert 4999 to Roman numeral
print(int_to_roman(4999))  # MMMMMMCMXCIX

# Invalid input (not a positive integer)
try:
    print(int_to_roman(-1))
except ValueError as e:
    print(e)  # Input must be a positive integer.

This function uses a dictionary to map decimal values to their corresponding Roman numeral representations. It then iterates over the dictionary, adding the Roman numerals to the result string and subtracting the corresponding decimal values from the input number until it reaches 0.

AnyModel: Explore and compare over 50 AI models side-by-side.

Performance Tier

ChatGPT 4.0 and Claude 3.5 provided similarly structured, efficient solutions using dictionary/tuple-based approaches. Gemini 1.5 Pro delivered the most comprehensive solution with detailed error handling and extensive test cases, though it took longest to generate (13,080ms). Llama 3.1 70B was fastest (2,434ms) and included excellent documentation with docstrings and example outputs. All models handled subtractive notation (IV, IX) correctly. Claude's solution was notably concise while maintaining functionality. Overall, Gemini's thoroughness and Llama's speed/documentation stand out as their respective strengths.

Budget Tier

ChatGPT 4o Mini provided a basic solution with good documentation but took 6 seconds. Gemini 1.5 Flash offered two comprehensive approaches with extensive examples but was slowest at 9 seconds. Claude 3.5 Haiku delivered a clean implementation with complexity analysis in 7.4 seconds. Llama 3.1 8B was impressively fast at 0.8 seconds and included robust error handling and docstrings. Llama performed best overall, balancing speed, code quality and documentation, though all solutions were functionally correct.

Palindrome Checker

Creates a function for palindrome validation. Common in string manipulation tasks and coding interviews.

Prompt:

Write a function to check if a string is a palindrome

Example

Palindromes: racecar level deified noon mom dad radar refer deed peep wow pop stats madam nursesrun neveroddoreven Non-palindromes: hello world testing palindrome string computer program algorithm example code python software developer application database network

Performance Results

Write a function to check if a string is a palindrome

To check if a string is a palindrome, you need to determine if the string reads the same backward as it does forward. Here's a simple Python function to achieve this:

def is_palindrome(s: str) -> bool:
    # Normalize the string by removing any spaces and converting to lowercase
    normalized_str = s.replace(" ", "").lower()
    # Check if the normalized string is equal to its reverse
    return normalized_str == normalized_str[::-1]

# Test cases
palindromes = [
    "racecar", "level", "deified", "noon", "mom", "dad",
    "radar", "refer", "deed", "peep", "wow", "pop",
    "stats", "madam", "nursesrun", "neveroddoreven"
]

non_palindromes = [
    "hello", "world", "testing", "palindrome", "string",
    "computer", "program", "algorithm", "example", "code",
    "python", "software", "developer", "application", "database",
    "network"
]

# Checking palindromes
for word in palindromes:
    print(f"{word} is a palindrome: {is_palindrome(word)}")

# Checking non-palindromes
for word in non_palindromes:
    print(f"{word} is a palindrome: {is_palindrome(word)}")

Explanation:

  1. Normalization: The function first normalizes the input string by removing spaces and converting the characters to lowercase. This ensures that the palindrome check is not affected by case sensitivity or spaces (as with "nurses run" and "never odd or even").

  2. Palindrome Check: It checks if the normalized string is equal to its reverse. This is done using Python's slicing feature, where s[::-1] gives the reverse of the string s.

This function will correctly identify which strings from your lists are palindromes and which are not.

def is_palindrome(s):
    # Convert to lowercase and remove non-alphanumeric characters
    s = ''.join(c.lower() for c in s if c.isalnum())

    # Compare string with its reverse
    return s == s[::-1]

# Test cases
palindromes = ["racecar", "level", "A man, a plan, a canal: Panama", "radar"]
non_palindromes = ["hello", "world", "python"]

# Test palindromes
print("Testing palindromes:")
for word in palindromes:
    print(f"'{word}' is palindrome: {is_palindrome(word)}")

# Test non-palindromes  
print("\nTesting non-palindromes:")
for word in non_palindromes:
    print(f"'{word}' is palindrome: {is_palindrome(word)}")

This function does the following:

  1. Takes a string input parameter s

  2. Cleans the string by:

  • Converting to lowercase
  • Removing non-alphanumeric characters
  • Using string join with list comprehension
  1. Compares the cleaned string with its reverse:
  • Uses string slicing with step -1 ([::-1]) to reverse
  • Returns True if equal, False if not

Key features:

  • Handles mixed case ("RaCeCaR")
  • Ignores spaces and punctuation ("A man, a plan, a canal: Panama")
  • Works with single words or full phrases
  • Efficient O(n) time complexity
  • Easy to read and understand

Sample output:

Testing palindromes:
'racecar' is palindrome: True
'level' is palindrome: True
'A man, a plan, a canal: Panama' is palindrome: True
'radar' is palindrome: True

Testing non-palindromes:
'hello' is palindrome: False
'world' is palindrome: False
'python' is palindrome: False
def is_palindrome(text):
    """
    Checks if a given string is a palindrome.

    Args:
        text: The string to check.

    Returns:
        True if the string is a palindrome, False otherwise.
    """
    processed_text = ''.join(filter(str.isalnum, text)).lower()  # Remove non-alphanumeric characters and convert to lowercase
    return processed_text == processed_text[::-1]  # Compare with reversed string



# Test cases (you can add more)
palindromes = ["racecar", "level", "deified", "noon", "mom", "dad", "radar", "refer",
               "deed", "peep", "wow", "pop", "stats", "madam", "nursesrun", "neveroddoreven"]
non_palindromes = ["hello", "world", "testing", "palindrome", "string", "computer",
                   "program", "algorithm", "example", "code", "python", "software",
                   "developer", "application", "database", "network"]

for word in palindromes:
    print(f"'{word}' is a palindrome: {is_palindrome(word)}")

for word in non_palindromes:
    print(f"'{word}' is a palindrome: {is_palindrome(word)}")

Key improvements in this version:

  • Handles non-alphanumeric characters: The ''.join(filter(str.isalnum, text)) part removes spaces, punctuation, etc., making the function correctly identify palindromes like "nurses run" (after cleaning, it becomes "nursesrun").
  • Case-insensitive: .lower() converts the string to lowercase, so "Racecar" is correctly recognized as a palindrome.
  • Clearer variable names: processed_text is more descriptive than just s.
  • More efficient string reversal: [::-1] is a concise and Pythonic way to reverse a string.
  • Comprehensive test cases: Including both palindrome and non-palindrome examples helps verify correctness.
  • Docstrings: The function now has a docstring explaining its purpose, arguments, and return value, which is good practice.

Palindrome Checker Function

Overview

This function checks if a given string is a palindrome, meaning it reads the same backward as forward.

Code

def is_palindrome(s: str) -> bool:
    """
    Checks if a given string is a palindrome.

    Args:
    s (str): The input string to be checked.

    Returns:
    bool: True if the string is a palindrome, False otherwise.
    """
    # Remove all non-alphanumeric characters and convert to lowercase
    s = ''.join(char for char in s if char.isalnum()).lower()

    # Compare the string with its reverse
    return s == s[::-1]

Example Use Cases

# Test with palindromes
print(is_palindrome("racecar"))  # Output: True
print(is_palindrome("level"))  # Output: True
print(is_palindrome("radar"))  # Output: True

# Test with non-palindromes
print(is_palindrome("hello"))  # Output: False
print(is_palindrome("world"))  # Output: False
print(is_palindrome("testing"))  # Output: False

# Test with palindromes containing non-alphanumeric characters
print(is_palindrome("A man, a plan, a canal: Panama"))  # Output: True
print(is_palindrome("Was it a car or a cat I saw?"))  # Output: True

Explanation

The function is_palindrome takes an input string s and checks if it's a palindrome.

  1. It first removes all non-alphanumeric characters from the string and converts it to lowercase. This is done using a list comprehension with the isalnum() method and the lower() method.
  2. Then, it compares the string with its reverse using slicing (s[::-1]).
  3. If the string is equal to its reverse, it returns True; otherwise, it returns False.

This approach ensures that the function works correctly even when the input string contains non-alphanumeric characters or has mixed case.

AnyModel: Explore and compare over 50 AI models side-by-side.

Budget Results

Write a function to check if a string is a palindrome

Certainly! A palindrome is a string that reads the same backward as forward. You can create a simple function in Python to check if a given string is a palindrome. Here’s an example of how to do that:

def is_palindrome(s):
    # Normalize the string by removing spaces and converting to lowercase
    normalized_str = ''.join(s.split()).lower()
    # Check if the string is equal to its reverse
    return normalized_str == normalized_str[::-1]

# Test examples
palindromes = [
    "racecar", "level", "deified", "noon", "mom", "dad",
    "radar", "refer", "deed", "peep", "wow", "pop", 
    "stats", "madam", "nursesrun", "neveroddoreven"
]

non_palindromes = [
    "hello", "world", "testing", "palindrome", "string",
    "computer", "program", "algorithm", "example", "code",
    "python", "software", "developer", "application", 
    "database", "network"
]

# Test the function with palindromes
print("Testing palindromes:")
for word in palindromes:
    print(f"{word}: {is_palindrome(word)}")

# Test the function with non-palindromes
print("\nTesting non-palindromes:")
for word in non_palindromes:
    print(f"{word}: {is_palindrome(word)}")

Explanation:

  1. Normalization: The function first removes any spaces and converts the string to lowercase to ensure that the check is case-insensitive and not affected by spaces.
  2. Reversal Check: It then compares the normalized string to its reverse (using slicing normalized_str[::-1]).

Usage:

This function can be used to check if any given string is a palindrome by calling is_palindrome(your_string), and it will return True for palindromes and False for non-palindromes. The test cases provided demonstrate its functionality.

Several functions can check if a string is a palindrome. Here are a few options, each with slightly different approaches and levels of efficiency:

Option 1: Simple and Readable

This version is easy to understand. It converts the string to lowercase and removes non-alphanumeric characters before comparison.

import re

def is_palindrome(text):
  """Checks if a given string is a palindrome (case-insensitive, ignoring non-alphanumeric characters)."""
  processed_text = re.sub(r'[^a-zA-Z0-9]', '', text).lower()
  return processed_text == processed_text[::-1]

#Example usage
print(is_palindrome("racecar"))  # True
print(is_palindrome("Racecar"))  # True
print(is_palindrome("A man, a plan, a canal: Panama")) # True
print(is_palindrome("hello"))  # False

Option 2: Slightly More Efficient (In-place comparison)

This avoids creating a reversed copy of the string, making it potentially faster for very large strings.

import re

def is_palindrome_efficient(text):
    """Checks if a given string is a palindrome (case-insensitive, ignoring non-alphanumeric characters)."""
    processed_text = re.sub(r'[^a-zA-Z0-9]', '', text).lower()
    left = 0
    right = len(processed_text) - 1
    while left < right:
        if processed_text[left] != processed_text[right]:
            return False
        left += 1
        right -= 1
    return True

# Example usage (same output as Option 1)
print(is_palindrome_efficient("racecar"))  # True
print(is_palindrome_efficient("Racecar"))  # True
print(is_palindrome_efficient("A man, a plan, a canal: Panama")) # True
print(is_palindrome_efficient("hello"))  # False

Option 3: Recursive approach (for demonstration, less efficient)

This is a recursive solution, which is elegant but generally less efficient than iterative approaches for this problem.

import re

def is_palindrome_recursive(text):
  """Checks if a string is a palindrome recursively (case-insensitive, ignoring non-alphanumeric characters)."""
  processed_text = re.sub(r'[^a-zA-Z0-9]', '', text).lower()
  if len(processed_text) <= 1:
    return True
  if processed_text[0] != processed_text[-1]:
    return False
  return is_palindrome_recursive(processed_text[1:-1])

#Example usage (same output as Option 1 and 2)
print(is_palindrome_recursive("racecar"))  # True
print(is_palindrome_recursive("Racecar"))  # True
print(is_palindrome_recursive("A man, a plan, a canal: Panama")) # True
print(is_palindrome_recursive("hello"))  # False

All three options handle case-insensitive comparisons and ignore non-alphanumeric characters. Choose the option that best suits your needs in terms of readability and performance considerations. For most cases, Option 1 or 2 would be preferred for their balance of clarity and efficiency. Option 2 is generally slightly more efficient for larger strings.

Here's a solution to check if a string is a palindrome:

def is_palindrome(s):
    # Remove non-alphanumeric characters and convert to lowercase
    cleaned_s = ''.join(char.lower() for char in s if char.isalnum())

    # Compare the string with its reverse
    return cleaned_s == cleaned_s[::-1]

# Test cases
palindromes = [
    'racecar', 'level', 'deified', 'noon', 'mom', 'dad', 
    'radar', 'refer', 'deed', 'peep', 'wow', 'pop', 
    'stats', 'madam', 'nursesrun', 'neveroddoreven'
]

non_palindromes = [
    'hello', 'world', 'testing', 'palindrome', 'string', 
    'computer', 'program', 'algorithm', 'example', 'code', 
    'python', 'software', 'developer', 'application', 
    'database', 'network'
]

# Verify palindromes
print("Palindrome Tests:")
for word in palindromes:
    print(f"{word}: {is_palindrome(word)}")

# Verify non-palindromes
print("\nNon-Palindrome Tests:")
for word in non_palindromes:
    print(f"{word}: {is_palindrome(word)}")

This implementation has several key features:

  1. Cleaning the input:
  • Removes non-alphanumeric characters
  • Converts to lowercase to handle case-insensitive palindromes
  1. Efficient comparison:
  • Uses string slicing [::-1] to reverse the string
  • Compares the cleaned string with its reverse
  1. Handles various scenarios:
  • Works with single words
  • Ignores spaces and punctuation
  • Case-insensitive

Time Complexity: O(n) Space Complexity: O(n)

Alternative Methods:

  1. Two-pointer approach
  2. Recursive method
  3. Stack-based method

Example Usage:

print(is_palindrome("A man, a plan, a canal: Panama"))  # True
print(is_palindrome("race a car"))  # False
print(is_palindrome(""))  # True (empty string)

The function will return True for palindromes and False for non-palindromes.

Here's a Python function to check if a string is a palindrome:

def is_palindrome(s: str) -> bool:
    """
    Checks if a given string is a palindrome.

    Args:
    s (str): The string to check.

    Returns:
    bool: True if the string is a palindrome, False otherwise.
    """

    # Remove non-alphanumeric characters and convert to lower case
    s = ''.join(c for c in s if c.isalnum()).lower()

    # Compare the string with its reverse
    return s == s[::-1]

# Example usage:
palindromes = ["racecar", "level", "deified", "noon", "mom", "dad", 
               "radar", "refer", "deed", "peep", "wow", "pop", "stats",
               "madam", "nursesrun", "neveroddoreven"]
non_palindromes = ["hello", "world", "testing", "palindrome", "string", 
                   "computer", "program", "algorithm", "example", "code", 
                   "python", "software", "developer", "application", 
                   "database", "network"]

for palindrome in palindromes:
    print(f"{palindrome} is {'a' if is_palindrome(palindrome) else 'not a'} palindrome.")

for non_palindrome in non_palindromes:
    print(f"{non_palindrome} is {'a' if is_palindrome(non_palindrome) else 'not a'} palindrome.")

In this code, the is_palindrome function first removes all non-alphanumeric characters from the string and converts it to lower case to handle cases where the input string is case-sensitive or has non-alphanumeric characters. It then compares the resulting string with its reverse to determine if it's a palindrome. If they're the same, the string is a palindrome.

AnyModel: Explore and compare over 50 AI models side-by-side.

Performance Tier

All models provided correct palindrome-checking functions, but with varying levels of sophistication. ChatGPT 4 emphasized comprehensive test cases but kept the function simple. Claude offered the most concise solution while maintaining robust functionality. Gemini provided detailed documentation and focused on code efficiency. Llama delivered well-structured code with clear documentation and diverse test cases.

Response times varied significantly: Llama was fastest (2033ms), while Gemini was slowest (10517ms). Claude and ChatGPT had similar mid-range performance (~8500ms). All solutions handled edge cases like spaces and capitalization, but Claude's implementation was particularly elegant in its simplicity.

Budget Tier

Comparing the models' solutions for palindrome checking:

ChatGPT 4o Mini and Claude 3.5 Haiku provided similar efficient solutions with comprehensive test cases. Gemini 1.5 Flash offered three different approaches (simple, efficient, and recursive) with detailed explanations of tradeoffs. Llama 3.1 8B gave the most concise solution with proper type hints and docstrings.

Gemini took longest to respond (15.6s) but provided the most thorough analysis. Llama was fastest (0.8s) but most basic. All solutions handled case-sensitivity and non-alphanumeric characters correctly, with similar O(n) time complexity.

GCD Calculator

Implements the Euclidean algorithm for GCD calculation. Fundamental for number theory and cryptography applications.

Prompt:

Generate a function to find the greatest common divisor of two numbers

Performance Results

Generate a function to find the greatest common divisor of two numbers

To find the greatest common divisor (GCD) of two numbers, you can use the Euclidean algorithm. This algorithm efficiently computes the GCD by repeatedly applying the modulo operation. Here's a Python function implementing this algorithm:

def gcd(a, b):
    while b != 0:
        a, b = b, a % b
    return a

# Example usage:
num1 = 48
num2 = 18
print(f"The GCD of {num1} and {num2} is {gcd(num1, num2)}")

How it Works:

  1. The function gcd takes two arguments, a and b.
  2. It repeatedly sets a to b and b to a % b until b becomes zero.
  3. The GCD is the last non-zero value of a.

Example:

  • For numbers 48 and 18:
  • gcd(48, 18):
    • 48 % 18 = 12
    • 18 % 12 = 6
    • 12 % 6 = 0
    • GCD is 6

This method is efficient and works for any pair of non-negative integers.

def find_gcd(a: int, b: int) -> int:
    """
    Find the greatest common divisor (GCD) of two numbers using Euclidean algorithm

    Args:
        a: First number
        b: Second number

    Returns:
        The GCD of a and b

    Example:
        >>> find_gcd(48, 18)
        6
        >>> find_gcd(54, 24) 
        6
    """
    # Handle negative numbers by taking absolute value
    a, b = abs(a), abs(b)

    # Base case
    if b == 0:
        return a

    # Recursive case using Euclidean algorithm
    # GCD(a,b) = GCD(b, a mod b)
    return find_gcd(b, a % b)

# Example usage
if __name__ == "__main__":
    print(find_gcd(48, 18))  # Output: 6
    print(find_gcd(54, 24))  # Output: 6
    print(find_gcd(-48, 18)) # Output: 6
    print(find_gcd(0, 18))   # Output: 18

This implementation:

  1. Uses the Euclidean algorithm which states that GCD(a,b) = GCD(b, a mod b)
  2. Handles negative numbers by taking absolute values
  3. Has a base case when b = 0, in which case a is the GCD
  4. Uses recursion to repeatedly apply the algorithm until reaching the base case
  5. Includes type hints and docstring with examples
  6. Works for positive, negative and zero values

The time complexity is O(log min(a,b)) and space complexity is O(log min(a,b)) due to the recursive calls.

Alternative iterative version:

def find_gcd_iterative(a: int, b: int) -> int:
    """Iterative version of GCD calculation"""
    a, b = abs(a), abs(b)
    while b:
        a, b = b, a % b
    return a

The iterative version has the same time complexity but constant space complexity.

def gcd(a, b):
    """
    Calculates the greatest common divisor (GCD) of two integers using the Euclidean algorithm.

    Args:
        a: The first integer.
        b: The second integer.

    Returns:
        The greatest common divisor of a and b.  Returns 0 if both a and b are 0.
    """
    while(b):
        a, b = b, a % b
    return a

# Example usage:
num1 = 48
num2 = 18
result = gcd(num1, num2)
print(f"The GCD of {num1} and {num2} is {result}")  # Output: 6


num3 = 0
num4 = 0
result = gcd(num3, num4)
print(f"The GCD of {num3} and {num4} is {result}") # Output: 0

num5 = 15
num6 = 0
result = gcd(num5, num6)
print(f"The GCD of {num5} and {num6} is {result}") # Output: 15

num7 = 0
num8 = 5
result = gcd(num7, num8)
print(f"The GCD of {num7} and {num8} is {result}") # Output: 5

Explanation and Improvements:

  1. Euclidean Algorithm: This function uses the Euclidean algorithm, which is a very efficient method for finding the GCD. It's based on the principle that the GCD of two numbers doesn't change if the larger number is replaced by its difference with the smaller number. This is repeatedly applied until one of the numbers becomes 0, at which point the other number is the GCD.

  2. Iterative Approach: The code uses a while loop, making it iterative and avoiding potential stack overflow issues that could occur with a recursive approach for very large numbers.

  3. Handling Zero: The function now correctly handles the case where one or both of the inputs are zero. If both are zero, it returns 0 (as there's no greatest common divisor). If one is zero, it returns the non-zero number as the GCD.

  4. Clarity and Documentation: The code includes a docstring explaining the function's purpose, arguments, and return value, improving readability and maintainability. The example usage demonstrates how to call the function and interpret the results.

This improved version is concise, efficient, and handles edge cases correctly, making it a robust solution for finding the GCD.

Greatest Common Divisor (GCD) Function

Here is a high-quality, readable, and well-documented function in Python to find the greatest common divisor of two numbers:

import math

def calculate_gcd(a: int, b: int) -> int:
    """
    Calculate the greatest common divisor (GCD) of two numbers.

    Args:
        a (int): The first number.
        b (int): The second number.

    Returns:
        int: The GCD of a and b.
    """
    while b != 0:
        a, b = b, a % b
    return abs(a)

# Alternatively, you can use the math.gcd function from the math module
def calculate_gcd_alternative(a: int, b: int) -> int:
    """
    Calculate the greatest common divisor (GCD) of two numbers using the math.gcd function.

    Args:
        a (int): The first number.
        b (int): The second number.

    Returns:
        int: The GCD of a and b.
    """
    return math.gcd(a, b)

# Example usage:
num1 = 48
num2 = 18
print(calculate_gcd(num1, num2))  # Output: 6
print(calculate_gcd_alternative(num1, num2))  # Output: 6

Explanation:

The calculate_gcd function uses the Euclidean algorithm to find the GCD of two numbers. The Euclidean algorithm is based on the principle that the GCD of two numbers a and b is the same as the GCD of b and the remainder of a divided by b. This process continues until b is 0, at which point a is the GCD.

The calculate_gcd_alternative function uses the math.gcd function from the math module, which is a built-in function in Python that calculates the GCD of two numbers.

Time Complexity:

The time complexity of the calculate_gcd function is O(log min(a, b)), where a and b are the input numbers. This is because the number of iterations is proportional to the number of digits in the smaller number.

The time complexity of the calculate_gcd_alternative function is O(log min(a, b)) as well, since it uses the math.gcd function which implements the Euclidean algorithm under the hood.

AnyModel: Explore and compare over 50 AI models side-by-side.

Budget Results

Generate a function to find the greatest common divisor of two numbers

You can find the greatest common divisor (GCD) of two numbers using the Euclidean algorithm. Below is a Python function that implements this algorithm:

def gcd(a, b):
    while b:
        a, b = b, a % b
    return abs(a)

# Example usage:
num1 = 48
num2 = 18
print(f"The GCD of {num1} and {num2} is {gcd(num1, num2)}")

Explanation:

  1. The function gcd takes two arguments, a and b.
  2. It uses a while loop that continues as long as b is not zero.
  3. Inside the loop, we update a and b such that a takes the value of b, and b takes the value of a % b (the remainder of a divided by b).
  4. When b becomes zero, a contains the GCD of the original two numbers, which we return as the absolute value to ensure it’s a non-negative number.

You can call this function with any two integers to find their GCD.

Several approaches can be used to find the greatest common divisor (GCD) of two numbers. Here are two common and efficient methods implemented in Python:

Method 1: Euclidean Algorithm

The Euclidean algorithm is a highly efficient method for finding the GCD. It's based on the principle that the GCD of two numbers does not change if the smaller number is subtracted from the larger number. This process is repeated until one of the numbers becomes zero, at which point the other number is the GCD.

def gcd_euclidean(a, b):
  """
  Finds the greatest common divisor (GCD) of two integers using the Euclidean algorithm.

  Args:
    a: The first integer.
    b: The second integer.

  Returns:
    The greatest common divisor of a and b.  Returns 0 if both a and b are 0.
  """
  while b:
    a, b = b, a % b
  return a

Method 2: Recursive Euclidean Algorithm

This is a recursive version of the Euclidean algorithm. It's functionally equivalent to the iterative version but might be considered more elegant by some.

def gcd_recursive(a, b):
  """
  Finds the greatest common divisor (GCD) of two integers using the recursive Euclidean algorithm.

  Args:
    a: The first integer.
    b: The second integer.

  Returns:
    The greatest common divisor of a and b. Returns 0 if both a and b are 0.
  """
  if b == 0:
    return a
  else:
    return gcd_recursive(b, a % b)

Both functions achieve the same result. The iterative version (gcd_euclidean) is generally slightly more efficient in terms of function call overhead, while the recursive version (gcd_recursive) might be easier to understand for those familiar with recursion. Choose the version that best suits your coding style and performance requirements. For most cases, the difference in performance will be negligible.

Example Usage:

num1 = 48
num2 = 18

print(f"GCD of {num1} and {num2} (Euclidean): {gcd_euclidean(num1, num2)}")  # Output: 6
print(f"GCD of {num1} and {num2} (Recursive): {gcd_recursive(num1, num2)}") # Output: 6

num3 = 0
num4 = 0
print(f"GCD of {num3} and {num4} (Euclidean): {gcd_euclidean(num3, num4)}")  # Output: 0
print(f"GCD of {num3} and {num4} (Recursive): {gcd_recursive(num3, num4)}")  # Output: 0

Here's a function to find the greatest common divisor (GCD) of two numbers using the Euclidean algorithm:

def gcd(a, b):
    """
    Calculate the greatest common divisor of two numbers using the Euclidean algorithm.

    Args:
    a (int): First number
    b (int): Second number

    Returns:
    int: The greatest common divisor of a and b
    """
    # Take absolute values to handle negative numbers
    a, b = abs(a), abs(b)

    # Base case: if b is 0, return a
    while b != 0:
        # Replace a and b with b and the remainder of a divided by b
        a, b = b, a % b

    return a

This implementation has several key features:

  1. Euclidean Algorithm: Uses the efficient Euclidean algorithm to find GCD
  2. Handles Negative Numbers: Takes absolute values of inputs
  3. Efficient: O(log(min(a,b))) time complexity
  4. Supports Zero: Works correctly when one or both inputs are zero

Example Usage:

# Example demonstrations
print(gcd(48, 18))   # Output: 6
print(gcd(54, 24))   # Output: 6
print(gcd(0, 5))     # Output: 5
print(gcd(-48, 18))  # Output: 6

Alternative Recursive Implementation:

def gcd_recursive(a, b):
    """
    Recursive implementation of GCD

    Args:
    a (int): First number
    b (int): Second number

    Returns:
    int: The greatest common divisor of a and b
    """
    # Take absolute values
    a, b = abs(a), abs(b)

    # Base case
    if b == 0:
        return a

    # Recursive call
    return gcd_recursive(b, a % b)

Performance Considerations:

  • The iterative version is generally more efficient
  • Works with large numbers
  • Minimal memory overhead
  • O(log(min(a,b))) time complexity

Additional Notes:

  • GCD(a,b) is the largest positive integer that divides both a and b without a remainder
  • The function handles various input scenarios including zero, negative numbers, and positive integers
  • Can be used as a building block for other mathematical operations like reducing fractions

Greatest Common Divisor (GCD) Function

Here's a simple function in Python to calculate the greatest common divisor of two numbers using the Euclidean algorithm:

def gcd(a: int, b: int) -> int:
    """
    Calculate the greatest common divisor of two numbers.

    Args:
    a (int): The first number.
    b (int): The second number.

    Returns:
    int: The greatest common divisor of a and b.
    """
    while b != 0:
        # Use the modulo operator to find the remainder of a divided by b
        a, b = b, a % b
    return abs(a)

Example Use Cases

# Calculate the GCD of 48 and 18
print(gcd(48, 18))  # Output: 6

# Calculate the GCD of 25 and 30
print(gcd(25, 30))  # Output: 5

This function works by repeatedly applying the Euclidean algorithm, which states that the GCD of two numbers a and b is the same as the GCD of b and the remainder of a divided by b.

Note: This function assumes that the input values are integers. If non-integer inputs are passed, the function may not work correctly.

AnyModel: Explore and compare over 50 AI models side-by-side.

Performance Tier

ChatGPT, Claude, Gemini, and Llama all implemented correct GCD functions using the Euclidean algorithm, but with varying levels of detail and features. Claude provided the most comprehensive solution, including both recursive and iterative implementations, type hints, and thorough error handling. Gemini offered detailed edge case handling and extensive examples. ChatGPT delivered a concise, clear solution with step-by-step explanation. Llama uniquely suggested using Python's built-in math.gcd() as an alternative. Response times varied significantly, with Llama being fastest (2.4s) and Gemini slowest (12.3s).

Budget Tier

ChatGPT 4o Mini provided a concise solution with basic implementation and explanation. Gemini 1.5 Flash offered both iterative and recursive approaches with detailed documentation. Claude 3.5 Haiku delivered the most comprehensive response, including performance considerations and additional mathematical context. Llama 3.1 8B was notably faster (666ms) and provided a clean, well-documented implementation with type hints. While all models produced correct solutions, Claude's response was most thorough, though Llama's speed and code clarity stand out for practical use.

Basic Calculator Implementation

Builds a calculator class with fundamental arithmetic operations. Useful for understanding class design and mathematical operations.

Prompt:

Create a class implementing a basic calculator with add, subtract, multiply, and divide operations

Performance Results

Create a class implementing a basic calculator with add, subtract, multiply, and divide operations

Below is a Python class that implements a basic calculator with methods for addition, subtraction, multiplication, and division:

class BasicCalculator:
    def add(self, a, b):
        """Returns the sum of a and b."""
        return a + b

    def subtract(self, a, b):
        """Returns the difference of a and b."""
        return a - b

    def multiply(self, a, b):
        """Returns the product of a and b."""
        return a * b

    def divide(self, a, b):
        """Returns the division of a by b. Raises ValueError if b is zero."""
        if b == 0:
            raise ValueError("Cannot divide by zero")
        return a / b

# Example usage:
calculator = BasicCalculator()
print("Add: ", calculator.add(3, 5))          # Output: 8
print("Subtract: ", calculator.subtract(10, 4)) # Output: 6
print("Multiply: ", calculator.multiply(2, 7))  # Output: 14
print("Divide: ", calculator.divide(20, 4))     # Output: 5.0

Explanation

  • Addition (add method): Takes two arguments a and b and returns their sum.
  • Subtraction (subtract method): Takes two arguments a and b and returns the result of a - b.
  • Multiplication (multiply method): Takes two arguments a and b and returns their product.
  • Division (divide method): Takes two arguments a and b and returns the result of a / b. If b is zero, it raises a ValueError to prevent division by zero, which is undefined in mathematics.

This class can be easily extended to include additional functionality if needed.

class Calculator:
    def __init__(self):
        pass

    def add(self, x, y):
        """Add two numbers"""
        return x + y

    def subtract(self, x, y): 
        """Subtract y from x"""
        return x - y

    def multiply(self, x, y):
        """Multiply two numbers"""
        return x * y

    def divide(self, x, y):
        """Divide x by y"""
        if y == 0:
            raise ValueError("Cannot divide by zero")
        return x / y

# Example usage:
calc = Calculator()

# Addition
result = calc.add(10, 5)  # Returns 15

# Subtraction 
result = calc.subtract(10, 5)  # Returns 5

# Multiplication
result = calc.multiply(10, 5)  # Returns 50

# Division
result = calc.divide(10, 5)  # Returns 2.0

# Division by zero raises exception
try:
    result = calc.divide(10, 0)
except ValueError as e:
    print(e)  # Prints "Cannot divide by zero"

This implements a basic calculator class with:

  • Simple arithmetic operations
  • Input validation for division by zero
  • Docstrings explaining each operation
  • Example usage showing how to create and use the calculator

You can extend this further by:

  1. Adding more operations (power, square root, etc)
  2. Adding input validation for other operations
  3. Supporting more complex mathematical functions
  4. Adding memory/history functionality
  5. Supporting different number types (integers, decimals, fractions)
class BasicCalculator:
    """A simple calculator class."""

    def add(self, x, y):
        """Adds two numbers.

        Args:
            x: The first number.
            y: The second number.

        Returns:
            The sum of x and y.
        """
        return x + y

    def subtract(self, x, y):
        """Subtracts two numbers.

        Args:
            x: The first number.
            y: The second number.

        Returns:
            The difference between x and y.
        """
        return x - y

    def multiply(self, x, y):
        """Multiplies two numbers.

        Args:
            x: The first number.
            y: The second number.

        Returns:
            The product of x and y.
        """
        return x * y

    def divide(self, x, y):
        """Divides two numbers.

        Args:
            x: The numerator.
            y: The denominator.

        Returns:
            The quotient of x divided by y.
            Raises ZeroDivisionError if y is zero.
        """
        if y == 0:
            raise ZeroDivisionError("Cannot divide by zero")
        return x / y


# Example usage
calculator = BasicCalculator()

print(calculator.add(5, 3))  # Output: 8
print(calculator.subtract(10, 4))  # Output: 6
print(calculator.multiply(2, 7))  # Output: 14
print(calculator.divide(15, 5))  # Output: 3.0


try:
    print(calculator.divide(10, 0))  # Raises ZeroDivisionError
except ZeroDivisionError as e:
    print(e)  # Output: Cannot divide by zero

Key improvements in this version:

  • Docstrings: Clear docstrings explain the purpose and usage of each method, including argument types and return values. This makes the code more understandable and maintainable.
  • Error Handling: The divide method now includes error handling for division by zero, raising a ZeroDivisionError with a helpful message. This makes the code more robust.
  • Example Usage: The code demonstrates how to use the BasicCalculator class, including how to handle potential exceptions.
  • Type Hinting (Optional): While not strictly necessary, you could add type hinting for even greater clarity:
def add(self, x: float, y: float) -> float:
    # ...etc...

Basic Calculator Class Implementation

Below is a Python implementation of a basic calculator class with methods for addition, subtraction, multiplication, and division.

class Calculator:
    """
    A basic calculator class with methods for addition, subtraction, multiplication, and division.

    Attributes:
        None

    Methods:
        add(x, y): Returns the sum of x and y.
        subtract(x, y): Returns the difference of x and y.
        multiply(x, y): Returns the product of x and y.
        divide(x, y): Returns the quotient of x and y. Raises a ZeroDivisionError if y is zero.
    """

    def add(self, x, y):
        """
        Returns the sum of x and y.

        Args:
            x (float): The first number.
            y (float): The second number.

        Returns:
            float: The sum of x and y.
        """
        return x + y

    def subtract(self, x, y):
        """
        Returns the difference of x and y.

        Args:
            x (float): The first number.
            y (float): The second number.

        Returns:
            float: The difference of x and y.
        """
        return x - y

    def multiply(self, x, y):
        """
        Returns the product of x and y.

        Args:
            x (float): The first number.
            y (float): The second number.

        Returns:
            float: The product of x and y.
        """
        return x * y

    def divide(self, x, y):
        """
        Returns the quotient of x and y.

        Args:
            x (float): The dividend.
            y (float): The divisor.

        Returns:
            float: The quotient of x and y.

        Raises:
            ZeroDivisionError: If y is zero.
        """
        if y == 0:
            raise ZeroDivisionError("Cannot divide by zero.")
        return x / y


# Example usage:
calculator = Calculator()

print("Addition: 3 + 4 =", calculator.add(3, 4))  # Output: 7
print("Subtraction: 10 - 2 =", calculator.subtract(10, 2))  # Output: 8
print("Multiplication: 5 * 6 =", calculator.multiply(5, 6))  # Output: 30
print("Division: 12 / 2 =", calculator.divide(12, 2))  # Output: 6.0

try:
    print("Division by zero:", calculator.divide(10, 0))
except ZeroDivisionError as e:
    print("Error:", e)

In this implementation:

  • We define a Calculator class with methods for basic arithmetic operations: add, subtract, multiply, and divide.
  • Each method takes two numeric arguments and returns the result of the corresponding operation.
  • The divide method raises a ZeroDivisionError if the divisor is zero.
  • We provide example usage demonstrating the calculator's functionality.

This code is well-structured, readable, and follows standard professional guidelines for commit messages and API documentation.

AnyModel: Explore and compare over 50 AI models side-by-side.

Budget Results

Create a class implementing a basic calculator with add, subtract, multiply, and divide operations

Certainly! Below is a simple implementation of a basic calculator class in Python that supports addition, subtraction, multiplication, and division operations.

class BasicCalculator:
    def add(self, a, b):
        """Returns the sum of a and b."""
        return a + b

    def subtract(self, a, b):
        """Returns the result of subtracting b from a."""
        return a - b

    def multiply(self, a, b):
        """Returns the product of a and b."""
        return a * b

    def divide(self, a, b):
        """Returns the result of dividing a by b.

        Raises ValueError if b is zero.
        """
        if b == 0:
            raise ValueError("Cannot divide by zero.")
        return a / b

# Example of how to use the BasicCalculator class
if __name__ == "__main__":
    calc = BasicCalculator()
    print("Addition:", calc.add(5, 3))         # Output: 8
    print("Subtraction:", calc.subtract(5, 3))  # Output: 2
    print("Multiplication:", calc.multiply(5, 3)) # Output: 15
    print("Division:", calc.divide(5, 3))       # Output: 1.666...

    try:
        print("Division by zero:", calc.divide(5, 0))  # This will raise an exception
    except ValueError as e:
        print(e)  # Output: Cannot divide by zero.

Explanation:

  • The BasicCalculator class has four methods: add, subtract, multiply, and divide.
  • Each method takes two parameters and performs the respective arithmetic operation.
  • The divide method includes error handling to prevent division by zero, raising a ValueError if the second argument (divisor) is zero.
  • An example usage is included in the __main__ block, demonstrating how to create an instance of BasicCalculator and execute the operations. It also shows how to handle exceptions when dividing by zero.

You can customize or enhance this class further based on your requirements!

class Calculator:
    """
    A simple calculator class that performs basic arithmetic operations.
    """

    def add(self, a, b):
        """Adds two numbers."""
        return a + b

    def subtract(self, a, b):
        """Subtracts two numbers."""
        return a - b

    def multiply(self, a, b):
        """Multiplies two numbers."""
        return a * b

    def divide(self, a, b):
        """Divides two numbers.  Handles division by zero."""
        if b == 0:
            raise ZeroDivisionError("Cannot divide by zero.")
        return a / b


# Example usage
calculator = Calculator()

try:
    print(f"Addition: {calculator.add(5, 3)}")  # Output: 8
    print(f"Subtraction: {calculator.subtract(10, 4)}")  # Output: 6
    print(f"Multiplication: {calculator.multiply(7, 2)}")  # Output: 14
    print(f"Division: {calculator.divide(15, 3)}")  # Output: 5.0
    print(f"Division by zero: {calculator.divide(10, 0)}")  # Raises ZeroDivisionError
except ZeroDivisionError as e:
    print(f"Error: {e}")

Here's a Python implementation of a basic calculator class:

class Calculator:
    def __init__(self):
        """
        Initialize the calculator
        """
        pass

    def add(self, a, b):
        """
        Add two numbers

        Args:
            a (float): First number
            b (float): Second number

        Returns:
            float: Sum of a and b
        """
        return a + b

    def subtract(self, a, b):
        """
        Subtract second number from first

        Args:
            a (float): First number
            b (float): Number to subtract

        Returns:
            float: Difference between a and b
        """
        return a - b

    def multiply(self, a, b):
        """
        Multiply two numbers

        Args:
            a (float): First number
            b (float): Second number

        Returns:
            float: Product of a and b
        """
        return a * b

    def divide(self, a, b):
        """
        Divide first number by second number

        Args:
            a (float): Dividend
            b (float): Divisor

        Returns:
            float: Result of division

        Raises:
            ZeroDivisionError: If b is zero
        """
        if b == 0:
            raise ZeroDivisionError("Cannot divide by zero")
        return a / b

# Example usage
def main():
    calc = Calculator()

    # Demonstration of operations
    print(f"Addition: 5 + 3 = {calc.add(5, 3)}")
    print(f"Subtraction: 10 - 4 = {calc.subtract(10, 4)}")
    print(f"Multiplication: 6 * 7 = {calc.multiply(6, 7)}")
    print(f"Division: 15 / 3 = {calc.divide(15, 3)}")

    # Handling division by zero
    try:
        calc.divide(10, 0)
    except ZeroDivisionError as e:
        print(f"Error: {e}")

if __name__ == "__main__":
    main()

This implementation includes:

  • Four basic arithmetic operations: add(), subtract(), multiply(), and divide()
  • Type-agnostic methods that work with both integers and floats
  • Error handling for division by zero
  • Docstrings for clear documentation
  • A sample main() function demonstrating usage

Key features:

  • Simple and straightforward class design
  • Robust error handling
  • Flexible method signatures
  • Easy to extend or modify

You can further enhance this calculator by adding more advanced operations like:

  • Exponentiation
  • Square root
  • Modulus
  • Trigonometric functions

Calculator Class Implementation

Below is a Python implementation of a basic calculator class with add, subtract, multiply, and divide operations.

class Calculator:
    """
    A basic calculator class with add, subtract, multiply, and divide operations.
    """

    def __init__(self):
        """
        Initializes the calculator with no operations performed.
        """

    def add(self, num1, num2):
        """
        Adds two numbers.

        Args:
            num1 (float): The first number.
            num2 (float): The second number.

        Returns:
            float: The sum of num1 and num2.
        """
        return num1 + num2

    def subtract(self, num1, num2):
        """
        Subtracts num2 from num1.

        Args:
            num1 (float): The first number.
            num2 (float): The number to subtract.

        Returns:
            float: The difference between num1 and num2.
        """
        return num1 - num2

    def multiply(self, num1, num2):
        """
        Multiplies two numbers.

        Args:
            num1 (float): The first number.
            num2 (float): The second number.

        Returns:
            float: The product of num1 and num2.
        """
        return num1 * num2

    def divide(self, num1, num2):
        """
        Divides num1 by num2.

        Args:
            num1 (float): The dividend.
            num2 (float): The divisor.

        Returns:
            float: The quotient of num1 and num2.

        Raises:
            ZeroDivisionError: If num2 is zero.
        """
        if num2 == 0:
            raise ZeroDivisionError("Cannot divide by zero.")
        return num1 / num2

    def calculate(self, operation, operand1, operand2):
        """
        Performs the specified operation.

        Args:
            operation (str): The operation to perform. Can be 'add', 'subtract', 'multiply', or 'divide'.
            operand1 (float): The first operand.
            operand2 (float): The second operand.

        Returns:
            float: The result of the operation.

        Raises:
            ValueError: If the operation is invalid.
        """
        if operation == 'add':
            return self.add(operand1, operand2)
        elif operation == 'subtract':
            return self.subtract(operand1, operand2)
        elif operation == 'multiply':
            return self.multiply(operand1, operand2)
        elif operation == 'divide':
            return self.divide(operand1, operand2)
        else:
            raise ValueError("Invalid operation.")


# Example usage:
calculator = Calculator()
print(calculator.add(5, 3))  # Outputs: 8
print(calculator.subtract(5, 3))  # Outputs: 2
print(calculator.multiply(5, 3))  # Outputs: 15
print(calculator.divide(5, 3))  # Outputs: 1.6666666666666667

try:
    print(calculator.divide(5, 0))  # Raises ZeroDivisionError
except ZeroDivisionError as e:
    print(e)

try:
    print(calculator.calculate('invalid_operation', 5, 3))  # Raises ValueError
except ValueError as e:
    print(e)

This Calculator class has methods for performing basic arithmetic operations: add, subtract, multiply, and divide. It also includes a calculate method that takes an operation and two operands as arguments and performs the specified operation. If an invalid operation is passed to the calculate method, a ValueError is raised. The divide method raises a ZeroDivisionError if an attempt is made to divide by zero.

AnyModel: Explore and compare over 50 AI models side-by-side.

Performance Tier

All models successfully implemented a basic calculator class with required operations. ChatGPT 4.0 provided a clean, concise solution with essential functionality in 5.5 seconds. Claude delivered similar features with additional extension suggestions in 6.5 seconds. Gemini took longest (12.5s) but included detailed docstrings and type hinting recommendations. Llama 3.1 was fastest (2.9s) and provided the most comprehensive documentation with detailed class and method descriptions. All implementations handled division by zero appropriately, with Llama and Gemini using ZeroDivisionError while ChatGPT and Claude used ValueError.

Budget Tier

All models successfully implemented a basic calculator class in Python with the required operations. Claude and Llama provided the most detailed documentation with comprehensive docstrings. Gemini delivered the most concise solution while maintaining functionality. ChatGPT included helpful example usage and error handling. Response times varied significantly, with Llama being fastest at 1.3s, while Gemini took longest at 10.3s. All implementations properly handled division by zero, though they used different error types (ValueError vs ZeroDivisionError). Llama uniquely included a calculate() method to handle operations dynamically.

Array Flattening Function

Creates a utility for converting nested arrays into a single-level array. Important for data processing and array manipulation tasks.

Prompt:

Write a function to flatten a nested array

Example

[ 1, [2, 3], [4, [5, 6]], [7, [8, [9, 10]]], [11, [12, [13, [14, 15]]]], 16, [17, 18, [19, 20, [21, 22]]], [], [[[23]]], [24, [], 25] ]

Performance Results

Write a function to flatten a nested array

To flatten a nested array, you'll want to write a function that recursively or iteratively traverses the array, extracting elements from nested arrays and adding them to a result list. Here's a Python function that accomplishes this using recursion:

def flatten_array(nested_array):
    # Initialize an empty list to store the flattened elements
    flat_list = []

    # Define a helper function to recursively flatten the array
    def flatten(item):
        if isinstance(item, list):  # Check if the item is a list
            for sub_item in item:  # Iterate through each element in the sub-list
                flatten(sub_item)  # Recursively flatten each element
        else:
            flat_list.append(item)  # Append non-list items directly to the flattened list

    # Start the flattening process
    flatten(nested_array)

    # Return the resulting flat list
    return flat_list

# Use the function with the given nested array
nested_array = [
    1,
    [2, 3],
    [4, [5, 6]],
    [7, [8, [9, 10]]],
    [11, [12, [13, [14, 15]]]],
    16,
    [17, 18, [19, 20, [21, 22]]],
    [],
    [[[23]]],
    [24, [], 25]
]

flattened_array = flatten_array(nested_array)
print(flattened_array)

This function starts by initializing an empty list flat_list and then uses a nested helper function flatten() that recursively navigates through each item in the input nested_array. If an item is a list, it further processes each element in that list. If the item is not a list, it appends the item to the flat_list. Finally, it returns the flattened list.

Here's a function to flatten a nested array using recursion:

function flattenArray(arr) {
  let result = [];

  arr.forEach(item => {
    if (Array.isArray(item)) {
      // If item is an array, recursively flatten it and concat with result
      result = result.concat(flattenArray(item));
    } else {
      // If item is not an array, simply push it to result
      result.push(item);
    }
  });

  return result;
}

// Test array
const nestedArray = [
  1,
  [2, 3],
  [4, [5, 6]],
  [7, [8, [9, 10]]],
  [11, [12, [13, [14, 15]]]],
  16,
  [17, 18, [19, 20, [21, 22]]],
  [],
  [[[23]]],
  [24, [], 25]
];

// Test the function
const flattened = flattenArray(nestedArray);
console.log(flattened);
// Output: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25]

Alternative solution using reduce:

function flattenArray(arr) {
  return arr.reduce((flat, item) => {
    return flat.concat(Array.isArray(item) ? flattenArray(item) : item);
  }, []);
}

Both solutions:

  1. Handle nested arrays of any depth
  2. Preserve the order of elements
  3. Handle empty arrays
  4. Return a new flat array

How they work:

  1. The first solution uses forEach to iterate through each item
  • If an item is an array, it recursively flattens it
  • If an item is not an array, it adds it directly to the result
  1. The second solution uses reduce to:
  • Accumulate all items into a single array
  • Use recursion for nested arrays
  • Concatenate results together

Both solutions will give the same result, but the reduce version is more concise.

You can also use the built-in flat() method with Infinity as depth:

const flattened = nestedArray.flat(Infinity);

This built-in method is more performant but might not be supported in older browsers.

function flatten(nestedArray) {
  const flattened = [];

  function flattenHelper(arr) {
    for (const item of arr) {
      if (Array.isArray(item)) {
        flattenHelper(item);
      } else {
        flattened.push(item);
      }
    }
  }

  flattenHelper(nestedArray);
  return flattened;
}


// Example usage:
const nestedArray = [
  1,
  [2, 3],
  [4, [5, 6]],
  [7, [8, [9, 10]]],
  [11, [12, [13, [14, 15]]]],
  16,
  [17, 18, [19, 20, [21, 22]]],
  [],
  [[[23]]],
  [24, [], 25]
];

const flattenedArray = flatten(nestedArray);
console.log(flattenedArray); 
// Output: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25]

Explanation:

  1. flatten(nestedArray):
  • Takes the nested array as input.
  • Initializes an empty array flattened to store the flattened elements.
  • Calls the recursive helper function flattenHelper.
  1. flattenHelper(arr):
  • Iterates through each item in the input array arr.
  • Base Case: If item is not an array (i.e., it's a primitive value), push it into the flattened array.
  • Recursive Step: If item is an array, recursively call flattenHelper on item to further flatten its nested elements.

This recursive approach ensures that all nested arrays are traversed and their elements are added to the flattened array, resulting in a completely flattened array.

Alternative (using flat() method - ES2019 and later):

If you are using a modern JavaScript environment that supports the flat() method, you can achieve the same result more concisely:

function flatten(nestedArray) {
  return nestedArray.flat(Infinity); // Infinity flattens any level of nesting
}

const nestedArray = [ /* ... (same as before) */ ];
const flattenedArray = flatten(nestedArray);
console.log(flattenedArray); // Output: [1, 2, 3, ... 25]

The flat(Infinity) method directly flattens the array to an arbitrary depth, handling any level of nesting. This is often the simplest and most efficient solution if it's available in your environment.

Flattening a Nested Array

You can use a recursive function to flatten a nested array. This is a straightforward approach where you check each element in the array, and if it's also an array, you call the function again with that element.

Code

def flatten(nested_array):
    """
    Recursively flatten a nested array.

    Args:
        nested_array (list): A list that may contain nested lists.

    Returns:
        list: A flattened list with no nesting.
    """

    # Initialize an empty list to store the flattened elements.
    flattened = []

    # Iterate over each element in the nested array.
    for element in nested_array:
        # If the element is a list, recursively call the function to flatten it.
        if isinstance(element, list):
            flattened.extend(flatten(element))
        else:
            # Otherwise, append the element to the flattened list.
            flattened.append(element)

    return flattened

# Example usage
nested_array = [
    1,
    [2, 3],
    [4, [5, 6]],
    [7, [8, [9, 10]]],
    [11, [12, [13, [14, 15]]]],
    16,
    [17, 18, [19, 20, [21, 22]]],
    [],
    [[[23]]],
    [24, [], 25]
]

print(flatten(nested_array))

Output

[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25]

This function works by checking each element in the input array. If an element is also an array, the function calls itself with that element as the input, effectively flattening any nested arrays. If an element is not an array, it's simply appended to the flattened list.

Note that this implementation uses extend to add elements from nested arrays to the flattened list. This is more efficient than using append with a list as the argument, as it avoids creating a nested list within the flattened list.

AnyModel: Explore and compare over 50 AI models side-by-side.

Budget Results

Write a function to flatten a nested array

You can flatten a nested array in Python using a recursive function or with a more concise approach using iteration. Here's an example of how to do it with both methods:

Recursive Method

def flatten(nested_array):
    flat_list = []
    for element in nested_array:
        if isinstance(element, list):
            flat_list.extend(flatten(element))  # Recursion for sublist
        else:
            flat_list.append(element)  # Append non-list element
    return flat_list

# Example usage:
nested_array = [
    1,
    [2, 3],
    [4, [5, 6]],
    [7, [8, [9, 10]]],
    [11, [12, [13, [14, 15]]]],
    16,
    [17, 18, [19, 20, [21, 22]]],
    [],
    [[[23]]],
    [24, [], 25]
]

flattened_array = flatten(nested_array)
print(flattened_array)

Iterative Method Using a Stack

Here's another approach using an iterative method with a stack:

def flatten(nested_array):
    flat_list = []
    stack = list(nested_array)  # Create a stack from the original array

    while stack:
        element = stack.pop()  # Get the last element
        if isinstance(element, list):
            stack.extend(reversed(element))  # Add sublist in reverse order
        else:
            flat_list.append(element)  # Append non-list element
    return flat_list[::-1]  # Reverse to maintain order

# Example usage:
nested_array = [
    1,
    [2, 3],
    [4, [5, 6]],
    [7, [8, [9, 10]]],
    [11, [12, [13, [14, 15]]]],
    16,
    [17, 18, [19, 20, [21, 22]]],
    [],
    [[[23]]],
    [24, [], 25]
]

flattened_array = flatten(nested_array)
print(flattened_array)

Output

In both methods, the output for the provided nested array will be:

[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25]

You can choose the method that you prefer; both will give you a flattened version of the nested array.

Several approaches can flatten a deeply nested array. Here are two functions demonstrating different methods: one using recursion and another using iteration.

Recursive Approach:

This approach is elegant but might hit Python's recursion depth limit for extremely deeply nested arrays.

def flatten_recursive(nested_array):
    """Flattens a nested array recursively.

    Args:
      nested_array: The nested array to flatten.

    Returns:
      A flattened list.
    """
    flattened = []
    for item in nested_array:
        if isinstance(item, list):
            flattened.extend(flatten_recursive(item))  # Recursive call
        else:
            flattened.append(item)
    return flattened

# Example usage:
nested_array = [
  1,
  [2, 3],
  [4, [5, 6]],
  [7, [8, [9, 10]]],
  [11, [12, [13, [14, 15]]]],
  16,
  [17, 18, [19, 20, [21, 22]]],
  [],
  [[[23]]],
  [24, [], 25]
]

flattened_array = flatten_recursive(nested_array)
print(flattened_array)  # Output: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25]

Iterative Approach (using a stack):

This approach avoids recursion and is generally safer for very deeply nested arrays.

def flatten_iterative(nested_array):
    """Flattens a nested array iteratively using a stack.

    Args:
      nested_array: The nested array to flatten.

    Returns:
      A flattened list.
    """
    flattened = []
    stack = [nested_array]  # Initialize stack with the input array

    while stack:
        current = stack.pop()  # Pop the top element from the stack
        if isinstance(current, list):
            stack.extend(current)  # Push list elements onto the stack
        else:
            flattened.append(current) #Append if not list

    return flattened[::-1] #Reverse to get correct order


# Example usage (same nested_array as above):
flattened_array_iterative = flatten_iterative(nested_array)
print(flattened_array_iterative)  # Output: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25]

Both functions achieve the same result. Choose the recursive version for its conciseness if you're confident about the depth of your nested arrays, and the iterative version for robustness in handling potentially very deep nesting. The iterative approach is generally preferred for production code because of its avoidance of potential stack overflow errors.

Here's a solution to flatten a nested array using JavaScript:

function flattenArray(arr) {
  return arr.reduce((flat, toFlatten) => {
    return flat.concat(
      Array.isArray(toFlatten) ? flattenArray(toFlatten) : toFlatten
    );
  }, []);
}

// Example usage
const nestedArray = [
  1,
  [2, 3],
  [4, [5, 6]],
  [7, [8, [9, 10]]],
  [11, [12, [13, [14, 15]]]],
  16,
  [17, 18, [19, 20, [21, 22]]],
  [],
  [[[23]]],
  [24, [], 25]
];

console.log(flattenArray(nestedArray));

This solution uses a recursive approach with reduce():

  1. The function flattenArray takes an array as input
  2. It uses reduce() to iterate through the array
  3. For each element, it checks if the element is an array
  • If it is an array, it recursively calls flattenArray on that nested array
  • If it's not an array, it simply includes the element
  1. The concat() method is used to build the flattened array
  2. An empty array [] is used as the initial accumulator

The output will be a completely flattened array:

[
  1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 
  16, 17, 18, 19, 20, 21, 22, 23, 24, 25
]

Alternative solutions include:

  • Using Array.flat() with Infinity depth (ES2019+)
  • Using a recursive function with a different approach
  • Using a stack-based iterative solution

The recursive reduce() method is concise and handles deeply nested arrays efficiently.

Here's a Python function to flatten a nested array:

def flatten_array(nested_array):
    """
    Flattens a nested array into a one-dimensional array.

    :param nested_array: A nested array to be flattened.
    :return: A one-dimensional list containing all elements from the nested array.
    """
    flattened_array = []
    for element in nested_array:
        if isinstance(element, list):
            # If the element is a list, recursively flatten it and extend the result
            flattened_array.extend(flatten_array(element))
        else:
            # If the element is not a list, append it to the result
            flattened_array.append(element)
    return flattened_array

# Test the function with the given example
nested_array = [
    1,
    [2, 3],
    [4, [5, 6]],
    [7, [8, [9, 10]]],
    [11, [12, [13, [14, 15]]]],
    16,
    [17, 18, [19, 20, [21, 22]]],
    [],
    [[[23]]],
    [24, [], 25]
]
print(flatten_array(nested_array))

When run, this will output:

[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25]

This function works by recursively checking each element in the array. If an element is a list, it is flattened recursively by calling flatten_array on it. If an element is not a list (i.e., it's a single value), it is appended directly to the result. The extend method is used instead of append when the element is a list, to efficiently add the entire flattened subarray to the result.

AnyModel: Explore and compare over 50 AI models side-by-side.

Performance Tier

All models provided functional solutions for flattening nested arrays, with varying approaches. ChatGPT 4.0 and Llama 3.1 70B offered Python implementations with clear recursive solutions and detailed documentation. Claude 3.5 Sonnet provided JavaScript solutions, including both forEach and reduce approaches, plus mentioned the built-in flat() method. Gemini 1.5 Pro gave a JavaScript solution with both recursive and modern flat() method implementations. Llama was fastest (2270ms), while Gemini was slowest (14599ms). Claude provided the most comprehensive answer by offering multiple implementation options.

Budget Tier

ChatGPT and Gemini provided comprehensive solutions with both recursive and iterative approaches, including detailed explanations. Claude offered a JavaScript implementation using reduce(), while Llama gave a simpler Python recursive solution. ChatGPT was fastest at 7.8s, with Llama notably quick at 0.9s but less detailed. Gemini took longest at 13s but included helpful implementation notes. Claude uniquely demonstrated JavaScript rather than Python, showcasing good technique but perhaps misinterpreting the task context. Overall, ChatGPT offered the best balance of speed, clarity and completeness.

Performance Verdict

After analyzing 15 code generation tasks across ChatGPT 4.0, Claude 3.5 Sonnet, Gemini 1.5 Pro, and Llama 3.1 70B, here's how the models compare:

Performance Overview:

Llama 3.1 70B Strengths:

  • Consistently fastest response times (2-4 seconds)
  • Excellent documentation and docstrings
  • Well-structured code organization
  • Good balance of completeness and efficiency Weaknesses:
  • Sometimes less comprehensive features compared to other models
  • Less likely to provide multiple implementation approaches

Gemini 1.5 Pro Strengths:

  • Most comprehensive solutions with advanced features
  • Excellent error handling and edge case coverage
  • Detailed explanations and test cases Weaknesses:
  • Significantly slower response times (12-27 seconds)
  • Sometimes overly complex for simple tasks

ChatGPT 4.0 Strengths:

  • Clean, production-ready code
  • Consistent error handling
  • Good balance of features and simplicity
  • Moderate response times (5-11 seconds) Weaknesses:
  • Less likely to provide alternative implementations
  • Sometimes less detailed documentation than Llama

Claude 3.5 Sonnet Strengths:

  • Concise, elegant solutions
  • Often provides multiple implementation approaches
  • Good performance (7-9 seconds average) Weaknesses:
  • Less comprehensive documentation than Llama or Gemini
  • Sometimes too minimalist in feature set

Winner: Llama 3.1 70B

Llama 3.1 70B emerges as the overall winner for code generation tasks. Its combination of extremely fast response times, excellent documentation, and well-structured solutions provides the best balance of practical utility. While Gemini often provided more comprehensive solutions and Claude offered more implementation alternatives, Llama's consistency, speed, and professional-grade documentation make it the most efficient choice for real-world development scenarios. Its ability to deliver complete, well-documented solutions in a fraction of the time required by other models is a significant advantage in practical applications.

Budget Verdict

Based on the comprehensive analysis of these 15 prompts focusing on code generation tasks, here's the comparative verdict for each model:

ChatGPT 4o Mini: Strengths:

  • Consistently thorough documentation
  • Well-balanced solutions combining practicality and educational value
  • Strong error handling implementation
  • Generally good response times (4-14 seconds)

Gemini 1.5 Flash: Strengths:

  • Most comprehensive solutions, often providing multiple implementation approaches
  • Excellent comparative analysis of different methods
  • Strong educational value with detailed explanations
  • Best handling of complex data structures Weaknesses:
  • Typically slowest response times (9-15 seconds)

Claude 3.5 Haiku: Strengths:

  • Most thorough technical analysis including complexity considerations
  • Excellent documentation standards
  • Strong focus on best practices
  • Robust error handling Weaknesses:
  • Consistently slower response times
  • Sometimes overly detailed for simple tasks

Llama 3.1 8B: Strengths:

  • Consistently fastest response times (0.8-1.4 seconds)
  • Clean, concise implementations
  • Good basic documentation
  • Efficient code organization Weaknesses:
  • Solutions sometimes lack advanced features
  • Less comprehensive than other models

Overall Winner: Gemini 1.5 Flash

While Llama 3.1 8B impressively dominates in speed and Claude 3.5 Haiku excels in technical depth, Gemini 1.5 Flash emerges as the overall winner for code generation tasks. It consistently provides the most comprehensive solutions with multiple implementation options, detailed comparisons, and robust error handling, making it the most valuable tool for both learning and practical development purposes. The longer response times are justified by the superior quality and completeness of its outputs.

Conclusion

Conclusion

This comprehensive analysis of code generation capabilities across leading AI models reveals distinct performance patterns and trade-offs between the two tiers of models. In the performance tier, Llama 3.1 70B emerged as the clear winner, combining remarkably fast response times with professional-grade documentation and consistent code quality. While Gemini 1.5 Pro often provided more feature-rich solutions and Claude offered elegant alternatives, Llama's efficiency and reliability made it the standout choice for production environments.

In the budget tier, Gemini 1.5 Flash proved to be the most valuable option despite slower response times, consistently delivering comprehensive solutions with multiple implementation approaches and detailed comparisons. Llama 3.1 8B impressed with its speed but offered simpler implementations, while Claude 3.5 Haiku provided excellent technical depth at the cost of slower processing.

The analysis demonstrates that while performance-tier models generally provide more sophisticated and nuanced solutions, budget-tier alternatives can still deliver high-quality code generation capabilities. The choice between tiers ultimately depends on specific needs - whether prioritizing speed, comprehensiveness, or cost-effectiveness. This comparative study provides valuable insights for developers and organizations seeking to optimize their AI-assisted coding workflows while managing resource constraints.