Code editing task: pandas_apply
Topic: Data Science; change kind: corrective
Libraries: pandas

Original code:
import pandas as pd

class StringOperations:
    """A class containing a series of string operations"""

    def remove_duplicates(text):
        """Returns the text with only unique characters"""
        unique = []
        for char in text:
            if char not in unique:
                unique.append(char)
        return ''.join(unique)
    
    def word_reversal(text):
        """Returns the text with words reversed"""
        sentences = text.split(' ')
        return ' '.join(reversed(sentences))
    
    def remove_vowels(text):
        """Returnes the text with vowels removed"""
        vowels = 'aeiou'
        return ''.join(char for char in text if char.lower() not in vowels)
    
def calculate_all_properties(text):
    properties = [StringOperations.remove_vowels(text), StringOperations.word_reversal(text), StringOperations.remove_duplicates(text)]
    return properties

def multi_apply(data, col, colnames):
    properties = data[col].apply(calculate_all_properties)
    properties_columns = pd.DataFrame(properties.tolist(), columns=colnames)
    return pd.concat([data, properties_columns], axis=1)

Instruction (descriptive):
Fix the `calculate_all_properties` and `multi_apply` functions to have the signatures `calculate_all_properties(text, functions)` and `multi_apply(data, col, colnames, functions)`, respectively, so that instead of hardcoding the functions used to calculate the properties, `multi_apply` accepts a list of functions to be applied, which it passes as a parameter to the `calculate_all_properties` function to use.

Instruction (lazy):
Fix the `calculate_all_properties` and `multi_apply` functions to have the signatures `calculate_all_properties(text, functions)` and `multi_apply(data, col, colnames, functions)`, respectively, so that both functions take in a list of functions to calculate the properties with, rather than just having hardcoded functions.

Edited code:
import pandas as pd

class StringOperations:
    """A class containing a series of string operations"""

    def remove_duplicates(text):
        """Returns the text with only unique characters"""
        unique = []
        for char in text:
            if char not in unique:
                unique.append(char)
        return ''.join(unique)
    
    def word_reversal(text):
        """Returns the text with words reversed"""
        sentences = text.split(' ')
        return ' '.join(reversed(sentences))
    
    def remove_vowels(text):
        """Returnes the text with vowels removed"""
        vowels = 'aeiou'
        return ''.join(char for char in text if char.lower() not in vowels)
    
def calculate_all_properties(text, functions):
    properties = [func(text) for func in functions]
    return properties

def multi_apply(data, col, colnames, functions):
    properties = data[col].apply(calculate_all_properties, args=(functions,))
    properties_columns = pd.DataFrame(properties.tolist(), columns=colnames)
    return pd.concat([data, properties_columns], axis=1)

Tests:
### START TESTS ###
if True:  # pragma: no cover
        
    assert StringOperations.remove_duplicates('hello') == 'helo'
    assert StringOperations.remove_duplicates('mississippi') == 'misp'
    assert StringOperations.remove_duplicates('python') == 'python'
    assert StringOperations.remove_duplicates('unique characters') == 'uniqe charts'

    assert StringOperations.word_reversal('Hello. How are you?') == 'you? are How Hello.'
    assert StringOperations.word_reversal('This is a test.') == 'test. a is This'
    assert StringOperations.word_reversal('unique characters') == 'characters unique'
    assert StringOperations.word_reversal('') == ''

    assert StringOperations.remove_vowels('hello') == 'hll'
    assert StringOperations.remove_vowels('world') == 'wrld'
    assert StringOperations.remove_vowels('aeiou') == ''
    assert StringOperations.remove_vowels('') == ''

    assert calculate_all_properties("this is the pandas application problem", [StringOperations.remove_vowels, StringOperations.word_reversal, StringOperations.remove_duplicates]) == ['ths s th pnds pplctn prblm', 'problem application pandas the is this', 'this epandlcorbm']
    assert calculate_all_properties("Lorem ipsum dolor sit amet consectetur adipiscing elit", [StringOperations.remove_vowels, StringOperations.word_reversal, StringOperations.remove_duplicates]) == ['Lrm psm dlr st mt cnscttr dpscng lt', 'elit adipiscing consectetur amet sit dolor ipsum Lorem', 'Lorem ipsudltacng']
    assert calculate_all_properties("reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla", [StringOperations.remove_vowels, StringOperations.word_reversal, StringOperations.remove_duplicates]) == ['rprhndrt n vlptt vlt ss cllm dlr  fgt nll', 'nulla fugiat eu dolore cillum esse velit voluptate in reprehenderit', 'rephndit voluascmfg']

    data = {
        'col1': ['Lorem ipsum', 'dolor sit', 'amet, consectetur', 'adipiscing elit'],
        'col2': ['Sed do', 'eiusmod tempor', 'incididunt ut', 'labore et dolore'],
        'col3': ['Ut enim', 'ad minim veniam', 'quis nostrud exercitation', 'ullamco laboris']
    }

    df = pd.DataFrame(data)

    col3 = multi_apply(df, 'col3', ['vowels_removed', 'words_reversed', 'dupes_removed'], [StringOperations.remove_vowels, StringOperations.word_reversal, StringOperations.remove_duplicates])
    result_col3 = [['Lorem ipsum', 'Sed do', 'Ut enim', 't nm', 'enim Ut', 'Ut enim'], ['dolor sit', 'eiusmod tempor', 'ad minim veniam', 'd mnm vnm', 'veniam minim ad', 'ad minve'], ['amet, consectetur', 'incididunt ut', 'quis nostrud exercitation', 'qs nstrd xrcttn', 'exercitation nostrud quis', 'quis notrdexca'], ['adipiscing elit', 'labore et dolore', 'ullamco laboris', 'llmc lbrs', 'laboris ullamco', 'ulamco bris']]
    assert col3.values.tolist() == result_col3
    assert col3.columns.tolist() == ["col1", 'col2', 'col3', 'vowels_removed', 'words_reversed', 'dupes_removed']

    col1 = multi_apply(df, 'col1', ['dupes_removed', 'words_reversed'], [StringOperations.remove_duplicates, StringOperations.word_reversal])
    result_col1 = [['Lorem ipsum', 'Sed do', 'Ut enim', 'Lorem ipsu', 'ipsum Lorem'], ['dolor sit', 'eiusmod tempor', 'ad minim veniam', 'dolr sit', 'sit dolor'], ['amet, consectetur', 'incididunt ut', 'quis nostrud exercitation', 'amet, consur', 'consectetur amet,'], ['adipiscing elit', 'labore et dolore', 'ullamco laboris', 'adipscng elt', 'elit adipiscing']]
    assert col1.values.tolist() == result_col1
    assert col1.columns.tolist() == ['col1', 'col2', 'col3', 'dupes_removed', 'words_reversed']