0

This may be a strange question - my code actually worked, but I feel like I got to a solution by brute force, rather than something more elegant.

I'm still not sure how to create and reference dictionaries in Python. When finding the longest match for each STR, I created a list str_counter that I reference in the next step.

But how would I instead create a dictionary, which had as keys the STRs themselves, which I pulled earlier (and inelegantly, since "name" made it into the list) STR = next(database)?

And could I do something similar for the csv when comparing, rather than using a loop and comparecount?

import csv
import sys
from cs50 import get_string


def main():

    # TODO: Check for command-line usage
    if len(sys.argv) != 3:
        print("Usage: python dna.py data.csv sequence.txt")
        exit()

    # TODO: Read database file into a variable
    with open(sys.argv[1], "r") as temp:
        database = csv.reader(temp)
        # This will capture the headers, which are the STRs needed for searching in the longest_match function
        STR = next(database)
#        print(STR[2])   # Printing during testing

    # TODO: Read DNA sequence file into a variable
    with open(sys.argv[2], "r") as temp2:
        sequence = temp2.read()
#        print(sequence) # Printing during testing

    # TODO: Find longest match of each STR in DNA sequence
    # Create an empty list, to be populated
    str_counter = []
    for i in range(1, len(STR)):
        matchlength = int(longest_match(sequence, STR[i]))
        # Populate list with output from longest_match function
        str_counter.append(matchlength)


    # TODO: Check database for matching profiles
    i = 1
    comparecount = 0

    with open(sys.argv[1], "r") as temp:
        database = csv.reader(temp)
        next(database)
        for row in database:
            for i in range(1, len(STR)):
                count = int(row[i])
                if (count != str_counter[i - 1]):
                    comparecount = 0
                elif (count == str_counter[i - 1]):
                    # row_values.append(count)
                    comparecount = comparecount + 1
                if (comparecount == len(STR) - 1):
                    print(row[0])
        if (comparecount < len(STR) - 1):
            print("No match")
    return


def longest_match(sequence, subsequence):
    """Returns length of longest run of subsequence in sequence."""

    # Initialize variables
    longest_run = 0
    subsequence_length = len(subsequence)
    sequence_length = len(sequence)

    # Check each character in sequence for most consecutive runs of subsequence
    for i in range(sequence_length):

        # Initialize count of consecutive runs
        count = 0

        # Check for a subsequence match in a "substring" (a subset of characters) within sequence
        # If a match, move substring to next potential match in sequence
        # Continue moving substring and checking for matches until out of consecutive matches
        while True:

            # Adjust substring start and end
            start = i + count * subsequence_length
            end = start + subsequence_length

            # If there is a match in the substring
            if sequence[start:end] == subsequence:
                count += 1

            # If there is no match in the substring
            else:
                break

        # Update most consecutive matches found
        longest_run = max(longest_run, count)

    # After checking for runs at each character in seqeuence, return longest run found
    return longest_run


main()

1 Answer 1

1

Let's start with the easy question: "how to create and reference Python dictionaries?". Dictionaries store key,value pairs (where keys must be an immutable object; e.g., ints, floats, strings or tuples). There are several ways to create a dictionary. The simplest method is shown below:

my_dict = {}
my_dict['key1'] = 'value1'
my_dict['One'] = 1
my_dict[2] = 'Two'
print(my_dict)
## Output shows key:value pairs:
{'key1': 'value1', 'One': 1, 2: 'Two'}

Dictionaries use the key as the index to the value (not an integer index like lists). So, print(my_dict['One']) outputs 1 and print(my_dict[2]) outputs Two.

This is how you can replace your list object (str_counter) with a dictionary named str_count_dict:

# Create a dictionary and populate with STR counts
    str_count_dict = {}
    for i in range(1, len(STR)):
        matchlength = int(longest_match(sequence, STR[i]))
        # Populate dictionary with output from longest_match function
        str_count_dict[STR[i]] = matchlength
    print(f'str_count_dict: {str_count_dict}')    

Replacing the list with a dictionary here comes with a caveat: Your code works because each DNA sequence is stored at the same index in 2 lists: str_counter and row. You will have to change your counts comparison logic with a dictionary. Here's a way that uses the csv.DictReader() method. It loads each database row to a dictionary. I added print statements so you can "see" what's going on. Code below:

with open(sys.argv[1], "r") as csv_f:
    db_reader = csv.DictReader(csv_f) 
    for row in db_reader:
        comparecount = 0
        print(f'checking CSV Row: {row}')
        for p_str in str_count_dict:
            if (int(row[p_str]) == str_count_dict[p_str]):
                comparecount += 1
        if (comparecount == len(str_count_dict)):
            print(f'DNA matches {row["name"]}')
        else:
            print(f'No match for {row["name"]}')

BTW, have you submitted this code? If so, was it accepted? I found "peculiarities" when I ran some of the examples. See 2 examples below:

## Output for small.csv, 1.txt
Bob
No match
## Output for small.csv, 4.txt
Alice
No match
2
  • Thanks so much for your help! I submitted the original code and it returned as all correct, despite the extra "No Match" in every result, per your flag above. But I corrected the code using a dictionary, and now it's working!
    – Cyrus
    Apr 14, 2022 at 0:05
  • Glad that worked out. Dictionaries can be very useful. This project shows a good application.
    – kcw78
    Apr 14, 2022 at 1:11

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .