Open In App

Python – Convert delimiter separated Mixed String to valid List

Given a string with elements and delimiters, split elements on delimiter to extract with elements ( including containers).

Input : test_str = “6*2*9*[3, 5, 6]*(7, 8)*8*4*10”, delim = “*” 
Output : [6, 2, 9, [3, 5, 6], (7, 8), 8, 4, 10] 
Explanation : Containers and elements separated using *.



Input : test_str = “[3, 5, 6]*(7, 8)*8*4*10”, delim = “*” 
Output : [[3, 5, 6], (7, 8), 8, 4, 10] 
Explanation : Containers and elements separated using *. 

Method #1 :  Using loop + eval() + split()



This is one way in which this task can be done. In this the separation is done using split() and eval() does the important task of performing the evaluation of data types to be containers or simpler elements. 

Step-by-step approach:

Below is the implementation of the above approach:




# Python3 code to demonstrate working of
# Convert delimiter separated Mixed String to valid List
# Using loop + split() + eval()
 
# initializing string
test_str = "6# 2# 9#[3, 5, 6]#(7, 8)# 8# 4# 10"
 
# printing original string
print("The original string is : " + str(test_str))
 
# initializing delim
delim = "#"
 
# splitting using split()
temp = test_str.split(delim)
res = []
 
# using loop + eval() to convert to
# required result
for ele in temp:
  res.append(eval(ele))
 
# printing result
print("List after conversion : " + str(res))

Output
The original string is : 6#2#9#[3, 5, 6]#(7, 8)#8#4#10
List after conversion : [6, 2, 9, [3, 5, 6], (7, 8), 8, 4, 10]

Time complexity:O(n), where n is the number of elements in the input string ‘test_str’.
Auxiliary space: O(n), as it creates a temporary list ‘temp’ of size n, and a result list ‘res’ of size n.

Method #2 : Using eval() + split() + list comprehension

This is yet another way in which this task can be performed. In this, we perform the similar task as the above method. The only difference being that entire logic is encapsulated as one liner using list comprehension.




# Python3 code to demonstrate working of
# Convert delimiter separated Mixed String to valid List
# Using eval() + split() + list comprehension
 
# initializing string
test_str = "6# 2# 9#[3, 5, 6]#(7, 8)# 8# 4# 10"
 
# printing original string
print("The original string is : " + str(test_str))
 
# initializing delim
delim = "#"
 
# encapsulating entire result in list comprehension
res = [eval(ele) for ele in test_str.split(delim)]
 
# printing result
print("List after conversion : " + str(res))

Output
The original string is : 6#2#9#[3, 5, 6]#(7, 8)#8#4#10
List after conversion : [6, 2, 9, [3, 5, 6], (7, 8), 8, 4, 10]

Time complexity:O(n), where n is the number of elements in the input string ‘test_str’.
Auxiliary space: O(n), as it creates a temporary list ‘temp’ of size n, and a result list ‘res’ of size n.

Method #3: Using Regex and eval

This code splits the input string test_str using the delimiter specified by delim. It uses a regular expression to split the string only at positions where the delimiter is not inside a bracketed expression (either […] or (…)).

For each split element, it applies the eval() function to evaluate the expression as either a list or a tuple. The resulting list is stored in the res variable and printed at the end.




import re
 
test_str = "6# 2# 9#[3, 5, 6]#(7, 8)# 8# 4# 10"
delim = "#"
 
res = [eval(s) for s in re.split(delim + "(?![^\[]*\])(?![^(]*\))", test_str)]
print("List after conversion : " + str(res))
#This code is contributed by Vinay Pinjala.

Output
List after conversion : [6, 2, 9, [3, 5, 6], (7, 8), 8, 4, 10]

Time complexity: O(n), where n is the length of the input string. The split() method and the loop that follows both have a linear time complexity of O(n), where n is the length of the input string.
Auxiliary space: O(n), where n is the length of the input string. This is because the list ‘res’ is created to store the converted elements of the input string, and its size can grow up to n if all the characters in the input string need to be stored as separate elements in the list. Additionally, the ‘delim’ variable is stored, which takes constant space.

Method #4: Using str.split() and str.strip() without eval()

Uses str.split() and str.strip() to split the input string into individual elements and remove any leading/trailing whitespace, without using eval().




# Python3 code to demonstrate working of
# Convert delimiter separated Mixed String to valid List
# Using split() and strip()
 
# initializing string
test_str = "6# 2# 9#[3, 5, 6]#(7, 8)# 8# 4# 10"
 
# printing original string
print("The original string is : " + str(test_str))
 
# initializing delim
delim = "#"
 
# split string into elements and strip leading/trailing whitespace
elements = [e.strip() for e in test_str.split(delim)]
 
# convert elements to appropriate types
res = []
for e in elements:
    if e.startswith('[') or e.startswith('('):
        res.append(eval(e))
    else:
        res.append(int(e))
 
# printing result
print("List after conversion : " + str(res))

Output
The original string is : 6# 2# 9#[3, 5, 6]#(7, 8)# 8# 4# 10
List after conversion : [6, 2, 9, [3, 5, 6], (7, 8), 8, 4, 10]

Time complexity: O(n), where n is the length of the input string. 
Auxiliary space: O(n), where n is the length of the input string.

Method#5: Using Recursive method.

Algorithm:

  1. Define a recursive function convert_string_to_list that takes in the input string and delimiter as arguments.
  2. In the function, check if the delimiter is present in the input string. If not, return the input string after stripping any leading/trailing whitespaces.
  3. If the delimiter is present, split the input string based on the delimiter.
  4. Traverse through each substring and recursively call the convert_string_to_list function with the substring and delimiter as arguments.
  5. Append the result of the recursive call to a list.
  6. Return the list.
  7. Call the convert_string_to_list function with the input string and delimiter as arguments.
  8. Print the result.




def convert_string_to_list(s, delim):
    if delim not in s:
        # base case: if delimiter not found, return the value as-is
        return s.strip()
     
    # recursive case: split the string and recursively process each substring
    temp = s.split(delim)
    res = []
    for ele in temp:
        res.append(eval(convert_string_to_list(ele, delim)))
    return res
test_str = "6# 2# 9#[3, 5, 6]#(7, 8)# 8# 4# 10"
delim = "#"
print("The original string is : " + str(test_str))
res = convert_string_to_list(test_str, delim)
print("List after conversion : " + str(res))

Output
The original string is : 6# 2# 9#[3, 5, 6]#(7, 8)# 8# 4# 10
List after conversion : [6, 2, 9, [3, 5, 6], (7, 8), 8, 4, 10]

Time complexity

Time complexity of the split() function is O(n), where n is the length of the input string.
Time complexity of the for loop to traverse through each substring is also O(n), where n is the length of the input string.
In the worst case scenario, the input string may have all elements enclosed in brackets, resulting in a recursive call for each element. In that case, the function will be called a total of O(n) times, where n is the length of the input string.
Time complexity of the strip() function is O(k), where k is the length of the input string after stripping any leading/trailing whitespaces.

space complexity 
Space complexity of the list to store the results is O(n), where n is the length of the input string.
In the worst case scenario, the function call stack may contain O(n) frames, where n is the length of the input string.
Therefore, the overall time complexity is O(n^2) and the space complexity is O(n).

Method 5: Use the Python built-in function reduce() from the functools module. 

Step-by-step approach:

Below is the implementation of the above approach:




from functools import reduce
 
def process_element(lst, d):
    if d not in lst[0]:
        return lst[0].strip()
    else:
        return eval(process_element(lst[1:], d)) + lst[0].strip()
 
def convert_string_to_list(s, delim):
    elements = s.split(delim)
    return reduce(lambda acc, e: acc + [process_element([e], delim)], elements, [])
 
test_str = "6# 2# 9#[3, 5, 6]#(7, 8)# 8# 4# 10"
delim = "#"
print("The original string is : " + str(test_str))
res = convert_string_to_list(test_str, delim)
print("List after conversion : " + str(res))

Output
The original string is : 6# 2# 9#[3, 5, 6]#(7, 8)# 8# 4# 10
List after conversion : ['6', '2', '9', '[3, 5, 6]', '(7, 8)', '8', '4', '10']

Time complexity: O(n^2), where n is the length of the input string s. 
Auxiliary space: O(n^2) as well, due to the recursive calls of the process_element() function that build up a new string to evaluate for each element of the list.

Method 6: Using numpy:

  1. Import numpy as np.
  2. Define the convert_string_to_list() function.
  3. Check if the delimiter is present in the string. If it’s not present, return the stripped string as is.
  4. If the delimiter is present, split the string into a list of substrings using the delimiter.
  5. Create an empty list res.
  6. For each substring, recursively call the convert_string_to_list() function and append the result to res.
  7. Convert res to a numpy array.
  8. Return the resulting numpy array.
  9. Define the test_str and delim variables.
  10. Call the convert_string_to_list() function with test_str and delim.
  11. Print the original string and the resulting numpy array.




import numpy as np
 
def convert_string_to_list(s, delim):
    if delim not in s:
        # base case: if delimiter not found, return the value as-is
        return s.strip()
     
    # recursive case: split the string and recursively process each substring
    temp = s.split(delim)
    res = []
    for ele in temp:
        res.append(np.array(convert_string_to_list(ele, delim)))
    return np.array(res)
 
test_str = "6# 2# 9#[3, 5, 6]#(7, 8)# 8# 4# 10"
delim = "#"
print("The original string is : " + str(test_str))
res = convert_string_to_list(test_str, delim)
print("List after conversion : " + str(res))
#This code is contributed by Jyothi pinjala.

Output:
The original string is : 6# 2# 9#[3, 5, 6]#(7, 8)# 8# 4# 10
List after conversion : ['6' '2' '9' '[3, 5, 6]' '(7, 8)' '8' '4' '10']

The time complexity of the convert_string_to_list() function using numpy is proportional to the length of the input string and the depth of the nested lists/tuples. In the worst-case scenario, where the input string contains nested lists/tuples of maximum depth, the time complexity is O(d * n * log n).

The auxiliary space is also proportional to the depth of the nested lists/tuples. In the worst-case scenario, where the input string contains nested lists/tuples of maximum depth, the space complexity is O(d * n * log n).


Article Tags :