Experience with OpenAI's Codex

Articles

Problem 1

Given a the contents of a CSV file as csv_contents, return the difference in days between the date of the earliest and the oldest entry.

The CSV file starts with a header row, which contains at least one column called Date.

You are optionally provided with the pandas library if you need it.

Examples

Input: "Date,Price,Volume\n2014-01-27,550.50,1387\n2014-06-23,910.83,4361\n2014-05-20,604.51,5870"

Output: 147

Explanation: There are 147 days between 2014-01-27 and 2014-06-23.

My Code (completely unassisted)

from datetime import date
import pandas as pd
from io import StringIO
 
def diff_days(csv_contents: str) -> int:
    df = pd.read_csv(StringIO(csv_contents))
    convert_to_date = lambda x: date(int(x.split("-")[0]), int(x.split("-")[1]), int(x.split("-")[2]))
    max_date = convert_to_date(df['Date'].max())
    min_date = convert_to_date(df['Date'].min())
    return (max_date - min_date).days

OpenAI Code

from datetime import date
import pandas
 
def diff_days(csv_contents: str) -> int:
    """
    Codex attempt #8
    """
    df = pandas.read_csv(io.StringIO(csv_contents))
    min_date = date.fromisoformat(df['Date'].min())
    max_date = date.fromisoformat(df['Date'].max())
    return (max_date - min_date).days

Problem 2

source and target are two strings each containing file contents. Return the number of lines you would need to insert and the number of lines you would need to delete to get to target from source.

Return your answer as a tuple (inserted, deleted).

LIBRARY SUGGESTION

Consider using the difflib module.

Examples

Input:

source = "Apple\nOrange\nPear" target = "Apple\nPear\nBanana\nMango"

Output: (2, 1)

My Code (assisted – I didn't know wtf difflib did). Everything except the diff = list(diff) line was generated by Codex

import difflib
from typing import Tuple
 
def diff_files(source: str, target: str) -> Tuple[int, int]:
    d = difflib.Differ()
    diff = d.compare(source.splitlines(), target.splitlines())
    diff = list(diff)
    lines_to_add = len([i for i in diff if i.startswith('+ ')])
    lines_to_del = len([i for i in diff if i.startswith('- ')])
    return lines_to_add, lines_to_del

Open AI Code

import difflib
from typing import Tuple
 
def diff_files(source: str, target: str) -> Tuple[int, int]:
    """
    Codex attempt #3
    """
    source_lines = source.splitlines()
    target_lines = target.splitlines()
    d = difflib.Differ()
    diff = d.compare(source_lines, target_lines)
    inserted = 0
    deleted = 0
    for line in diff:
        if line.startswith('+'):
            inserted += 1
        elif line.startswith('-'):
            deleted += 1
    return inserted, deleted

Problem 3

Given a compressed message compressed and the prefix code tree used to encode it, decode and return the original message.

tree is a nested dictionary with characters at the leaves. For each character in compressed, traverse down one step of the tree. Once you reach a leaf of the tree, the character at that leaf is appended to the decoded message.

If the compressed message could not be decoded in full because the last step did not end at a leaf, return what was decoded so far.

CONSTRAINTS

The keys of tree and its subdictionaries are always '0' or '1', and the leaf values are also always single characters.

EXAMPLES

Input:

compressed = "110100100" tree = {"0": "a", "1": {"0": "n", "1": "b"}}

Output: "banana"

Input:

compressed = "0111010100" tree = {"0": {"0": "x", "1": "z"}, "1": "y"}

Output: "zyyzzx"

Input:

compressed = "000" tree = {"0": {"0": "x", "1": "z"}, "1": "y"}

Output: "x"

My Code (completely assisted – it would've taken me ages to understand wtf the instructions were asking for)

from typing import Dict, Union
 
Tree = Dict[str, Union[str, "Tree"]]
 
def decompress(compressed: str, tree: Tree) -> str:
    message = ""
    current_tree = tree
    for i in compressed:
        if isinstance(current_tree, str):
            message += current_tree
            current_tree = tree
        if i == "0":
            current_tree = current_tree["0"]
        else:
            current_tree = current_tree["1"]
        if isinstance(current_tree, str):
            message += current_tree
            current_tree = tree
    return message

OpenAI Code

from typing import Dict, Union
Tree = Dict[str, Union[str, "Tree"]]
 
def decompress(compressed: str, tree: Tree) -> str:
    """
    Codex attempt #44
    """
    current = tree
    decoded = ''
    for c in compressed:
        current = current[c]
        if isinstance(current, str):
            decoded += current
            current = tree
    return decoded

Problem 4

Parse the given Python source code and return the list of full-qualified paths for all imported symbols, sorted in ascending lexicographic order.

CONSTRAINTS

The input will not contain any wildcard imports (from ... import *).

Ignore aliases (renamings): from x import y as z should be represented as x.y.

LIBRARY SUGGESTION

Consider using the ast module.

EXAMPLES

Input

import os
import concurrent.futures
from os import path as renamed_path
from typing import (
    List, Tuple
)

Output

['concurrent.futures', 'os', 'os.path', 'typing.List', 'typing.Tuple']

My code (completely assisted) – this just worked the first time. I had no idea what the ast module did

import ast
from typing import List
 
def parse_imports(code: str) -> List[str]:
    tree = ast.parse(code)
    all_names = []
    for node in ast.walk(tree):
        if isinstance(node, ast.Import):
            for name in node.names:
                all_names.append(name.name)
        elif isinstance(node, ast.ImportFrom):
            for name in node.names:
                all_names.append(node.module + "." + name.name)
    return sorted(all_names)

Codex Code

import ast
from typing import List
 
def parse_imports(code: str) -> List[str]:
    """
    Codex attempt #18
    """
    tree = ast.parse(code)
    ans = []
    for statement in tree.body:
        if isinstance(statement, ast.Import):
            for name in statement.names:
                ans.append(name.name)
        elif isinstance(statement, ast.ImportFrom):
            for name in statement.names:
                ans.append(statement.module + '.' + name.name)
    return sorted(ans)

Problem 5

You have several buckets whose sizes are represented by the list sizes. Find the number of different ways to arrange the buckets such that the first bucket’s size is greater than the second bucket’s size.

CONSTRAINTS

sizes is a list of positive integers. If sizes has fewer than 2 buckets, return 0. Some buckets may have the same size, but are nevertheless treated as unique buckets.

LIBRARY SUGGESTION

Consider using the itertools module.

EXAMPLES

Input: [10] Output: 0 Explanation: No arrangement is possibl

Input: [1, 2] Output: 1 Explanation: The possible arrangements are (1, 2) and (2, 1). Of these, only (2, 1) has a first bucket that is bigger than the second bucket.

Input: [1, 3, 1] Output: 2 Explanation: Only the arrangements (3, 1, 1) and (3, 1, 1) satisfy the property that the first bucket is bigger than the second bucket.

My code (assisted – I would've got this on my own, but tried Codex a few times to see what kinds of outputs it would generate. It generated a fairly elegant one-liner)

import itertools
from typing import List
 
def count_arrangements(sizes: List[int]) -> int:
    if len(sizes) < 2:
        return 0
    return len(list(filter(lambda p: p[0] > p[1], itertools.permutations(sizes))))

Codex Code

import itertools
from typing import List
 
def count_arrangements(sizes: List[int]) -> int:
    """
    Codex attempt #37
    """
    if len(sizes) < 2:
        return 0
    return sum(1 for p in itertools.permutations(sizes, len(sizes))
               if p[0] > p[1])