6
\$\begingroup\$

Requirement:

For the input list of tuples to create single line output showing father of the family|spouse|child1,child2....

Input:

input_list = [("David","Polly","Spouse"),
          ("Roger","Patty","Spouse"),
          ("David","Lily","Child"),
          ("Roger","Max","Child"),
          ("David","Sam","Child")]

Expected output:

David|Polly|Lily,Sam
Roger|Patty|Max

I have written the code but it is very clunky. Any improvement and shorter/efficient version is much appreciated.

input_list = [("David","Polly","Spouse"),
          ("Roger","Patty","Spouse"),
          ("David","Lily","Child"),
          ("Roger","Max","Child"),
          ("David","Sam","Child")]
# Expected output
'''
David|Polly|Lily,Sam
Roger|Patty|Max
'''
priority = {"Spouse" :1,"Child" :2} 
intermediate_list = []
final_list =[]
return_name = ''
input_list_w_priority = [tuple(x) + (priority[x[2]],) for x in input_list ] #  spouse has priority 1, children have 'lower' priority
sorted_input_list = sorted(input_list_w_priority)
get_father = sorted(list(set([ x[0] for  x in sorted_input_list]))) # getting 'unique' father
for x in range(len(get_father)):
    i =0
    intermediate_list =[]
    spouse_name =''
    final_name = ''
    for y in range(len(sorted_input_list)):  # traversing the input list for a single father

        i+=1

        if(get_father[x] == sorted_input_list[y][0]):
            intermediate_list.append((sorted_input_list[y][1],sorted_input_list[y][3])) # assigning spouse/child name and priority

    if(i == len(sorted_input_list)):
    final_tuple = sorted(intermediate_list,key=lambda x : x[1]) #sorting on priority

    for z in range(len(final_tuple)):
        if(final_tuple[z][1] == 1): # if spouse then pipe separated
            spouse_name = '|'+ final_tuple[z][0] + '|'
        else:
            final_name = final_name + ','+ final_tuple[z][0]
    return_name = return_name + get_father[x] + spouse_name +final_name[1:] + '\n'
print(return_name)
\$\endgroup\$

2 Answers 2

1
\$\begingroup\$

It looks like example for defaultdict use. No errors handling, no sorting handling at below example

    from collections import defaultdict
    families = defaultdict(lambda: {'Spouse': set(), 'Child': set()})
    for father, person, kind in input_list:
        families[father][kind].add(person)

    print('\n'.join("%s|%s|%s"% (father, 
                                 ','.join(families[father]['Spouse']), 
                                 ','.join(families[father]['Child'])) 
                    for father in families.keys()))
\$\endgroup\$
4
\$\begingroup\$

Using a dictionary to group your data is arguably a better alternative to sorting, and building the actual output strings is a perfect fit for the .join() method of strings:

data = {}
for head, tail, kind in input_list:
    tails = data.setdefault(head, [None, []])
    kind = kind.lower()
    if kind == 'spouse' and tails[0] is None:
        # Duplicate spouse entries raise, should we do differently?
        tails[0] = tail
    elif kind == 'child':
        tails[1].append(tail)
    else:
        # Should wrong inputs be ignored, rather than raise?
        raise ValueError('Wrong input')
for head, (spouse, children) in data.items():
    print('|'.join((head, spouse, ','.join(children))))

This will print the families in some arbitrary order, but you could get them sorted by sorting the last for loop, i.e.

for head, (spouse, children) in sorted(data.items()):
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.