Thursday, December 3, 2020

Get string in between braces when position of brace is given

 Let's say there is a string with braces and braces can be (),{},[] and the string has multiple sub-strings that are in braces. Given the position of start of a brace we need to print the string that qualifies. Say for example

Hello (This world is so beautiful (seriously) and I love it).

If the user inputs 1 as position, the output should be

This world is so beautiful (seriously) and I love it.

If the position is 2 then output should be seriously

Of course handle exceptions as well. How do we do that?


It looks tricky but a straight forward solution. The idea behind is to identify for a given brace where it ends. So, we leverage concept of stack. Algorithm is as follows

For each character in the string
If the character is opening brace, add it to a list
If the character is closing brace, pop the item from list (if there is no corresponding opening brace, we have an index out of range issue) and add the start and end positions to a dictionary/ hash map
After the complete string is traversed,
get the position from where the substring needs to be pulled. For that get the matching end and print the substring





def get_string_in_between(string_, brace, position):
    tmp_open_brace_pos = []
    brace_dict = {'(':')', '{':'}', '[':']'}
    start_end_pos_dict = {}
    if brace not in string_ or brace_dict.get(brace) not in string_:
        print('There are no recognized braces')
    else:
        for cnt, chr_ in enumerate(string_):
            if chr_ == brace:
                tmp_open_brace_pos.append(cnt)
            if chr_== brace_dict.get(brace):
                try:
                    start_end_pos_dict[tmp_open_brace_pos.pop()] = cnt
                except IndexError:
                    print('Unbalanced string. Too many closing braces')

    if tmp_open_brace_pos:
        print('There are too many opening braces')

    else:
        # sort the dictionary keys so we know the positions where the opening braces are
        ordered_indices = sorted(start_end_pos_dict)
        # indexes start at 0. However, the input will be >0 for position
        if position > len(ordered_indices):
            print('Out of range for start position. There are only {} braces'.format(str(len(ordered_indices))))
        else:
            return string_[ordered_indices[position-1]+1 : start_end_pos_dict[ordered_indices[position-1]]]


string = 'Hello (This world is so beautiful (seriously) and I love it)'


d = get_string_in_between(string, '(', 2)
print(d)

Tuesday, June 9, 2020

How to sort a list based on element's position

Let's say there is a list of numbers

data = [9,10,15,51,68,85,19]

Sort the list based on the number in the units place. So, here sort the data based on the second digit and output should be

[10, 51, 15, 85, 68, 9, 19]

Remember single digits has 0 prepended internally. We can do it with a single line using lambda and built in sort function of list

sorted(data, key=lambda x: x%10)

This works well for numerics. What if the list has a combination of strings and numerics or strings? In this case we want to convert everything into a string and sort based on the index of string required. In this example as we are looking at second digit/ letter, index will be 1 (remember indexes start with 0)

sorted(data, key=lambda x: str(x)[1] if len(str(x))>1 else str(x)[0])


Find pair of numbers that will generate target value

Let's say there is a list of values and you are given a target value. How will you find all the pair of numbers when added up will give the target value?

Example:

data = [1,5,11,2,10,9,3,2,10]
target = 12

In this example (1,11), (2,10), (9,3) and (2,10) again will produce the target of 12. However, we don't want to have the sequence of numbers repeating. How can we do that?

There are several ways to do it. However, the clean and easy way to do this is, removing duplicates from the list. How?

data = list(set(data))

We are converting list to set and back to list. This is going to remove duplicate values. Now to get the pairs, we can use list comprehension and produce list of tuples

[(val, target-val) for cnt,val in enumerate(data) if target-val in data[cnt+1:]]