How to set a variable to a specific column in a 2D list? Is it possible?

Question:

I am trying to create a ‘check records’ function which accepts a 2D list (ID, account, operation, amount) and returns the number of valid or invalid items on the list. Which is based on set criteria. Each of the criteria also has its own function i.e. validate account number is a function which validates a list of account numbers.

The check records function then will look at the results of all the validate functions and remove any items from the full 2D list which has any part as invalid (returning false).

The full list looks something like this (For context):

[[‘SYD123’, ‘12823983’, ‘B’, ‘150.00’], [‘SYD127’, ‘12823983’, ‘D’, ‘20.00’], [‘BHS115’, ‘85849276’, ‘B’, ‘1000.85’], [‘BHS115’, ‘76530902’, ‘B’, ‘0.50’], [‘BMT251’, ‘49468141’, ‘W’, ‘500.00’], [‘DUB796’, ‘50175864’, ‘W’, ‘225.00’], [‘WGA584’,
‘34957765’, ‘D’, ‘2500.00’], [‘PMQ426’, ‘34957765’, ‘B’, ‘5700.00’]]

and prints like this:

[List table format][1]

The issue I’m having is that I’m always getting 4 valid and 0 invalid being returned. No matter how many there actually is. I believe the issue is because the variables below are only pointing to one element of the original list above. I need them to be the entire column with the relevant variable? If this is wrong please point me in the right direction.

What I’m getting:

Found (4) valid records.
Found (0) invalid records.

Items it thinks are valid (all should be valid):

[[‘SYD127’, ‘12823983’, ‘D’, ‘20.00’], [‘BHS115’, ‘76530902’, ‘B’, ‘0.50’], [‘DUB796’, ‘50175864’, ‘W’, ‘225.00’], [‘PMQ426’, ‘34957765’, ‘B’, ‘5700.00’]]

The problem code looks like this:

def check_records(log_records):
    #THESE VARIABLES!!!!!
    ID  = log_records [0]
    account = log_records [1]
    operation = log_records [2]
    amount = log_records [3]
    #HERE!!!!!!

    overall_valid = False
    count = 0

    #Use validate functions to get a valid or invalid record. 
    validate_atm_id(ID)
    validate_account(account)
    validate_operation(operation)
    validate_amount(amount)

if validate_atm_id == True and validate_account == True and validate_operation == True and 
validate_amount == True:
    overall_valid = True
else:
    overall_valid = False

for elem in log_records:
    if overall_valid == False:
        count + 1
        log_records.remove(elem) 
    
total_records = len(log_records)
invalid_records = count
valid_records = total_records - invalid_records
print(f"Found ({valid_records}) valid records.")
print(f"Found ({invalid_records}) invalid records.")
print(" ")

One of the validate functions (for extra context):

def validate_account(account):
    
    valid = False

    #Account number must be 8 digits long. 
    if len(account) != 8:
        valid = False
    #Account number must only contain numbers.
    elif not account.isdigit():
        valid = False
    #If the account number meets all requirments then it is valid.
    else:
        valid = True

    if valid == True:
       return True
    elif valid == False:
       return False
Asked By: Loree

||

Answers:

You can create column-like structures with list comprehensions:

ids = [i[0] for i in log_records]   # assumming log_records is your full list 
accounts = [i[1] for i in log_records]
operations = [i[2] for i in log_records]
amounts = [i[3] for i in log_records]

Although I’d not recommend doing it because what you want to check are individual records and if you create column-like variables you’ll have to deal with a lot of indexing and it’s a bit painful.

Also this is unnecessarily long:

if validate_atm_id == True and validate_account == True and validate_operation == True and 
validate_amount == True:
    overall_valid = True

I’d rewrite it as:

overall_valid = True
if not any((validate_atm_id, validate_account, validate_operation, validate_amount )):
    overall_valid = False

This looks like a typo:

for elem in log_records:
    if overall_valid == False:
        count + 1          # this line shouldn't work and should be "count += 1"
        log_records.remove(elem)
Answered By: pavel

Im going to leave some parts as an excersize to the reader

first understand how indexing works

a = [11,12,13]
a[0] # gets the first element (11)

next understand what you are indexing into

organized_by_rows = [
   ["r1c1","r1c2","r1c3","r1c4"],
   ["r2c1","r2c2","r2c3","r2c4"]
]
organized_by_rows[0] # gets first element (["r1c1","r1c2","r1c3","r1c4"])

now what you need to do is basically turn your rows on their side into columns, this is known as transposing

organized_by_cols = [
    ["r1c1","r2c1"],
    ["r1c2","r2c2"],
    ["r1c3","r2c3"],
    ["r1c4","r2c4"],
]
organized_by_cols[0] # gets first element (["r1c1","r2c1"])
# ie gets the first column

there are many ways to do this, but python provides a pretty simple builtin way

organized_by_cols = zip(*organized_by_rows)

using this info I am confident you can find your solution

Answered By: Joran Beasley
Categories: questions Tags: ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.