# Converting a 1D list to a 2D table

A few days ago someone asked this question. But they quickly deleted the post offering no solution.
Given:

a = ['COP' , '\t\t\t', 'Basis', 'Notl', 'dv01', '6m', '9m', '1y',
'18m', '2y', '3y', "15.6", 'mm', '4.6', '4y', '5y', '10', 'mm',
'4.6', '6y', '7y', '8y', '9y', '10y', '20y', 'TOTAL', '\t\t9.2' ]


They needed to traverse the list and get the following 2D table. Where the first column has only values ending in "m" or "y".

"COB", "Basis", "Notl"
('6m', '', '')
('9m', '', '')
('1y', '', '')
('18m', '', '')
('2y', '', '')
('3y', '15.6', '')
('4y', '', '')
('5y', '10', '')
('6y', '', '')
('7y', '', '')
('8y', '', '')
('9y', '', '')
('10y', '', '')
('20y', '', '')


I answered the question, using a coroutine and a linked list as shown below:


a = ['COP' , '\t\t\t', 'Basis', 'Notl', 'dv01', '6m', '9m', '1y',
'18m', '2y', '3y', "15.6", 'mm', '4.6', '4y', '5y', '10', 'mm',
'4.6', '6y', '7y', '8y', '9y', '10y', '20y', 'TOTAL', '\t\t9.2' ]

headers = ('COP', "Basis", 'Notl', 'dv01')

def is_Number(value):
is_number = False
try:
float(value)
except ValueError:
pass
else:
is_number = True
return is_number

def is_cob(value):
return True if (value[0].isnumeric() and (value[-1] == "m" or value[-1] == "y")) \
else False

class Node:
def __init__(self, data=None, next_cop=None, next_column=None):
self.data = data
self.next_cop = None
self.next_column = None

class LinkedList:
def __init__(self):
self.headNode = None

def printlist(self):
print("This is the list =>:")
temp = self.headNode
while temp:
print("Data-> :", temp.data)
temp1 = temp.next_column
while temp1:
print("|")
print("--->Column: Bias, Notl =", temp1.data)
temp1 = temp1.next_column
temp = temp.next_cop

def isEmpty(self):
return False if self.headNode else True

def insert_at_head(self, node):
if self.isEmpty():
self.headNode = node
else:
node.next_cop = self.headNode
self.headNode = node

def insert_at_tail(self, node):
if self.isEmpty():
self.headNode = node
return
temp = self.headNode
while temp.next_cop:
temp = temp.next_cop
temp.next_cop = node

def insert_at_tail_column_of_nodeX(self, nodeX, node):
temp = self.get_pointer_to_nodeX(nodeX)
while temp.next_column:
temp = temp.next_column
temp.next_column = node

def get_pointer_to_nodeX(self, nodeX):
temp = self.headNode
while temp.next_cop != nodeX:
temp = temp.next_cop
temp = temp.next_cop
return temp

def get_last_node_data(self):
if self.isEmpty():
return self.headNode.data
temp = self.headNode
while temp.next_cop:
temp = temp.next_cop
return temp.data

def get_last_node(self):
if self.isEmpty():
return self.headNode
temp = self.headNode
while temp.next_cop:
temp = temp.next_cop
return temp

def iterate_from(self, node=None):
while node is not None:
yield node
node = node.next_cop

def rows(llist):
lst = []
while True:
value = yield
if value is None:
break
lst.append(value)
is_number = is_Number(value)
if is_cob(value):
llist.insert_at_tail(Node(value))
if is_number and is_cob(llist.get_last_node_data()) \
and (is_cob(lst[-2]) or is_Number(lst[-2])):
llist.insert_at_tail_column_of_nodeX(llist.get_last_node(), Node(value))
return llist

if __name__ == "__main__":
llist = LinkedList()

sent_to_coro = [elem for elem in a if elem not in headers]
coro_rows = rows(llist)
next(coro_rows)
for element in sent_to_coro:
print("Sending....", element)
coro_rows.send(element)
try:
coro_rows.send(None)
except StopIteration as exc:
result = exc.value

out = []
for item in llist.iterate_from(llist.headNode):
cop = item.data
basis = item.next_column.data if item.next_column else ""
notl = item.next_column.next_column.data if basis and item.next_column.next_column else ""
out.append((cop,basis,notl))
for itm in out:
print(itm)



Someone posted a solution with regex that was just a few lines of code, but unfortunately it was deleted because the question itself was just a question with no code and immediately started to be downvoted of course.

I would like to:

1. Hear some suggestion on this code. Specifically, I wanted to know if there is any real improvement to this code.
2. Is this solution overworked?
3. I would like to see other solutions to this problem using Regex
• Do you have a link to the original post. Even though it is deleted? Jan 29, 2020 at 14:03
• Unfortunately no. It was all so fast, I just can tell it was a couple of days ago and it was his/her first post in stackoverflow.com Jan 29, 2020 at 14:15
• Let me clarify, that I answered the question but was not even able to post it. What I'm looking for is a review of my response and the answer that was posted that was using RegEx Jan 29, 2020 at 14:18
• @Peilonrayz, I guess it is the link stackoverflow.com/questions/59940421/… Jan 29, 2020 at 14:23

## 2 Answers

To be brief on your three points.

You can try to omit extra variables and trust the function boundary. For example, your code starts with this excellently named function:

def is_Number(value):
is_number = False
try:
float(value)
except ValueError:
pass
else:
is_number = True
return is_number


or more concisely,

def is_Number(value):
try:
float(value)
except ValueError:
return False
return True


You might see Code Like A Pythonista for a better explanation.

Yes, your code does seem overly worked for the problem.

Instead of giving you a regex, I recommend Regex101. It is a single web page playground for experimenting with RegEx with full explanations of what matches. Be sure to pick 'Python' for the dialect.

Keep hacking! Keep notes.

• yes, this is a valid observation.Thanks Jan 31, 2020 at 16:41

With some help I found a solution using RegEx that indeed shows what I did is overworked. I failed to see the array as a long string and apply a RegEx to it

import re
a = ['COP' , '\t\t\t', 'Basis', 'Notl', 'dv01', '6m', '9m', '1y',
'18m', '2y', '3y', "15.6", 'mm', '4.6', '4y', '5y', '10', 'mm',
'4.6', '6y', '7y', '8y', '9y', '10y', '20y', 'TOTAL', '\t\t9.2']

rule2 = re.compile(r"\b(\d+[ym])\W+([0-9]+\.?[0-9]*)*\b")
a_str = " ".join(a)
OUT2 = re.findall(rule2, a_str)
print(OUT2)



output

>> [('6m', ''), ('9m', ''), ('1y', ''), ('18m', ''), ('2y', ''), ('3y', '15.6'), ('4y', ''), ('5y', '10'), ('6y', ''), ('7y', ''), ('8y', ''), ('9y', ''), ('10y', ''), ('20y', '')]