This is a simple paired comparison analysis to compare a list of items amongst themselves to find a ranking for decision making.
#!/usr/bin/env python3
#######################################################
# Paired Comparison Analysis
# webmaster@memorymatrix.cloud
# 25.26.12.2053
#######################################################
import sys
import logging
def create_lists(list_a=None, list_b=None):
"""
Create two lists of items from user input
Args:
list_a (list): Initial items for List A (optional)
list_b (list): Initial items for List B (optional)
Returns:
tuple: Two lists (A and B), populated with items
Raises:
TypeError: If invalid items are provided
"""
try:
if list_a is None:
list_a = []
if list_b is None:
list_b = []
# Populate List A if not provided
while True:
item = input("Enter an item for List A (press Enter to stop): ")
if not item:
break
list_a.append(str(item))
# Copy List A to List B
list_b = list(list_a)
logging.info("Lists created successfully")
return list_a, list_b
except KeyboardInterrupt:
print("\nUser interrupted input")
sys.exit(1)
except Exception as e:
logging.error(f"Error creating lists: {str(e)}")
raise
def count_preferences(comparison_results):
"""
Count how many times each item was preferred
Args:
comparison_results (list): List of tuples from compare_items()
Returns:
dict: Dictionary mapping items to their preference counts
Raises:
ValueError: If invalid results are provided
"""
try:
if not comparison_results:
raise ValueError("No comparison results provided")
# Initialize count dictionary
counts = {}
for result in comparison_results:
preferred_item = result[2]
if preferred_item == 1:
counts[result[0]] = counts.get(result[0], 0) + 1
elif preferred_item == 2:
counts[result[1]] = counts.get(result[1], 0) + 1
return counts
except Exception as e:
logging.error(f"Error counting preferences: {str(e)}")
raise
def compare_items(list_a, list_b):
"""
Compare unique pairs of items between two lists and store preferences
Args:
list_a (list): First list of items
list_b (list): Second list of items
Returns:
list: Results of comparisons
Raises:
ValueError: If lists are empty or mismatched
"""
try:
if not list_a or not list_b:
raise ValueError("Both lists must contain items")
results = []
# Generate unique pairs (a, b) where a is from A and b is from B
# Skip comparisons where items are the same or already compared in reverse order
for item_a in list_a:
for item_b in list_b:
# Skip self-comparisons and reverse comparisons
if item_a == item_b or item_a > item_b: # Using '>' to sort alphabetically
continue
try:
preference = input(f"Compare {item_a} vs {item_b}: "
f"Enter 1 if you prefer {item_a}, "
f"2 if you prefer {item_b}: ")
if not preference.isdigit():
print("Invalid input. Please enter 1 or 2.")
continue
results.append((item_a, item_b, int(preference)))
except KeyboardInterrupt:
print("\nUser interrupted comparison")
return results # Return what we have so far
except Exception as e:
logging.error(f"Error during comparison: {str(e)}")
raise
return results
if __name__ == "__main__":
"""
Main program entry point with command line arguments
"""
try:
# Configure logging
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(levelname)s - %(message)s',
handlers=[logging.StreamHandler()]
)
# Get items from command line or user input
if len(sys.argv) >= 2:
list_a = [str(sys.argv[1]), str(sys.argv[2])]
else:
print("No command line arguments provided.")
first_item = input("Enter the first item for List A: ")
list_a = [first_item]
list_b, _ = create_lists(list_a=list_a)
results = compare_items(list_a, list_b)
# Get preference counts
preferences = count_preferences(results)
print("\nComparison Results:")
for res in results:
print(f"Comparing {res[0]} vs {res[1]} - Preferred: {res[2]}")
print("\nPreference Counts:")
for item, count in preferences.items():
print(f"{item} was preferred {count} times")
except IndexError:
# Handle cases where lists are too short
print("Error: Not enough items provided. At least two items required")
sys.exit(1)
except KeyboardInterrupt:
print("\nProgram interrupted by user")
sys.exit(0)
# Unit Tests
# to run this, go the source directory venv/bin folder, and use source ./activate
# then python3 -m pytest script-name.py
def test_create_lists():
"""
Test create_lists function with different scenarios
"""
from unittest.mock import patch
@patch('builtins.input')
def test_default_case(mock_input):
mock_input.side_effect = ['apple', 'banana', '', 'berry']
list_a, list_b = create_lists()
assert len(list_a) == 3
assert list_b == list_a
@patch('builtins.input')
def test_single_item(mock_input):
mock_input.side_effect = ['test', '']
list_a, list_b = create_lists()
assert len(list_a) == 1
assert list_b == list_a
def test_compare_items():
"""
Test compare_items function with various scenarios
"""
def test_count_preferences():
"""
Test count_preferences function with various scenarios
"""
from unittest.mock import patch
@patch('builtins.input')
def test_valid_comparison(mock_input):
mock_input.side_effect = ['1', '2']
results = compare_items(['a'], ['a', 'b'])
assert len(results) == 1
@patch('builtins.input')
def test_invalid_input(mock_input):
mock_input.side_effect = ['3', '1']
results = compare_items(['a'], ['a', 'b'])
assert len(results) == 1
def test_count_preferences():
"""
Test count_preferences function with various scenarios
"""
from unittest.mock import patch
@patch('builtins.input')
def test_valid_comparison(mock_input):
mock_input.side_effect = ['1', '2']
results = compare_items(['a'], ['a', 'b'])
preferences = count_preferences(results)
assert len(preferences) == 1
assert preferences.get('a', 0) == 1
@patch('builtins.input')
def test_multiple_comparisons(mock_input):
mock_input.side_effect = ['2', '1']
list_a = ['apple', 'orange']
list_b = ['pear', 'tomato']
results = compare_items(list_a, list_b)
preferences = count_preferences(results)
assert len(preferences) == 2
assert preferences.get('pear', 0) == 1
assert preferences.get('apple', 0) == 1