How to implement Rope data structure split operation - python

I was reading about Rope(or cord) data structure https://en.wikipedia.org/wiki/Rope_(data_structure) and trying to implement it, but I am struggling to implement the split operation. I tried to look it up but all related answers I was able to find were incorrect.
Below is the split operation:
We want to find the character and return two nodes before and after the split. For example, if we want to split at index 5 of'MyNameIsSimon' then we should return the root of two ropes 'MyName' and 'IsSimon' respectively. Finding the index is easy as given by the pseudo-code in wiki. But I'm struggling the split part especially how to join and return the 2nd half as a new rope. Anyone can help with pseudo-code or any language is much appreciated.

Wikipedia’s diagram looks muddled to me. Here’s a working implementation in Python (without balancing).
class Leaf:
def __init__(self, s):
self._s = s
def __len__(self):
return len(self._s)
def __str__(self):
return self._s
def inspect(self, indent=0):
print(" " * indent + repr(self._s))
def split(self, i):
return Leaf(self._s[:i]), Leaf(self._s[i:])
class Branch:
def __init__(self, a, b):
self._a = a
self._b = b
self._l = len(a) + len(b)
def __len__(self):
return self._l
def __str__(self):
return str(self._a) + str(self._b)
def inspect(self, indent=0):
self._a.inspect(indent + 2)
print(" " * indent + str(len(self._a)))
self._b.inspect(indent + 2)
def split(self, i):
if i < len(self._a):
a0, a1 = self._a.split(i)
return a0, Branch(a1, self._b)
elif i == len(self._a):
return self._a, self._b
else:
assert i > len(self._a)
b0, b1 = self._b.split(i - len(self._a))
return Branch(self._a, b0), b1
def make_test_rope():
e = Leaf("Hello ")
f = Leaf("my ")
c = Branch(e, f)
j = Leaf("na")
k = Leaf("me i")
g = Branch(j, k)
m = Leaf("s")
n = Leaf(" Simon")
h = Branch(m, n)
d = Branch(g, h)
b = Branch(c, d)
a = Branch(b, Leaf(""))
return a
def test():
a = make_test_rope()
a.inspect()
b, c = a.split(11)
print("--")
b.inspect()
print("--")
c.inspect()
test()
Output:
'Hello '
6
'my '
9
'na'
2
'me i'
6
's'
1
' Simon'
22
''
--
'Hello '
6
'my '
9
'na'
--
'me i'
4
's'
1
' Simon'
11
''

Related

How to properly print the output __str__

How to properly print the output str
class Complex(object):
def __init__(self, real, imaginary):
self.real = real
self.imaginary = imaginary
def __add__(self, other):
return Complex(self.real+other.real, self.imaginary+other.imaginary)
def __sub__(self, other):
return Complex(self.real-other.real, self.imaginary-other.imaginary)
def __str__(self):
return '{} & {}i'.format(self.real, self.imaginary)
if __name__ == '__main__':
c = map(float, input().split())
d = map(float, input().split())
x = Complex(*c)
#print (x)
y = Complex(*d)
#print (y)
print(*map(str, [x+y, x-y]), sep='\n')
Input
2 1
5 6
Output
7.0 & 7.0i
-3.0 & -5.0i
Expected out if for addtion it should print + and for substraction it should print -
7.00+7.00i
-3.00-5.00i
class Complex(object):
def __init__(self, real, imaginary):
self.real = real
self.imaginary = imaginary
def __add__(self, other):
return Complex(self.real+other.real, self.imaginary+other.imaginary)
def __sub__(self, other):
return Complex(self.real-other.real, self.imaginary-other.imaginary)
def __str__(self):
return '{:.2f}{}{:.2f}i'.format(self.real, '+' if self.imaginary >= 0 else '', self.imaginary)
if __name__ == '__main__':
c = map(float, input().split())
d = map(float, input().split())
x = Complex(*c)
#print (x)
y = Complex(*d)
#print (y)
print(*map(str, [x+y, x-y]), sep='\n')
You should manually add sign, if var is positive.
Also in your expected result you have 2 decimal points, so you need to add {:.2f}.
Use this in your str implementation.
def __str__(self):
return f"{self.real}{ '+' if self.imaginary >= 0 else ''}{self.imaginary}i"
Instead of this:
def __str__(self):
return '{} & {}i'.format(self.real, self.imaginary)
You could do this:
def __str__(self):
def __map_imaginary(imag):
if imag > 0:
return "+{:2f}i".format(imag)
if imag < 0:
return "{:2f}i".format(imag)
if imag == 0:
return ""
return "{}{}".format(self.real, __map_imaginary(self.imag))
I have assumed that you don't want to print imaginary part if it equals to 0. You can change that at will.

Adding objects using the mean (average) consistently

Say we have a class AverageNumber which when adding, finds the mean of the numbers being added:
class AverageNumber():
def __init__(self, value):
self.value = value
def __add__(self, other):
average = ( self.value + other.value ) / 2 # This is the issue?
return AverageNumber(average)
def __str__(self):
return self.value
This code is incorrect, as it fails to respect the additive commutative and associative properties that I was looking for, namely that:
average(1 + 3 + 2) = average(1 + 2 + 3) etc.
However this does not occur, as the above class adds two at a time.
The INCORRECT results are below:
>>> b = AverageNumber(1) + AverageNumber(3) + AverageNumber(2)
>>> b.value
2.0
>>> b = AverageNumber(1) + AverageNumber(2) + AverageNumber(3)
>>> b.value
2.25
My question is: How can I modify the code above to fix this issue?
You just need to track the number of numbers involved:
class AverageNumber():
def __init__(self, value, count=1):
self.value = value
self.count = count
def __add__(self, other):
total = self.value + other.value
count = self.count + other.count
return AverageNumber(total, count)
def getValue(self):
return self.value / self.count
b = AverageNumber(1) + AverageNumber(3) + AverageNumber(2)
print(b.getValue())
b = AverageNumber(1) + AverageNumber(2) + AverageNumber(3)
print(b.getValue())
Output:
2.0
2.0

How to create a cyclic iterator over the alphabet in Python?

Given the following scenario:
import string
UPPERCASE_ALPHABET = list(string.ascii_uppercase)
LOWERCASE_ALPHABET = list(string.ascii_lowercase)
How to create a cyclic loop over the alphabet jumping N positions?
Example 1:
letter = a, jump = 5
Result: f
Example 2:
letter = z, jump = 5
Result: e
So far, I got:
import string
UPPERCASE_ALPHABET = list(string.ascii_uppercase)
LOWERCASE_ALPHABET = list(string.ascii_lowercase)
def forward(letter, jump):
alphabet = LOWERCASE_ALPHABET if letter.islower() else UPPERCASE_ALPHABET
index = alphabet.index(letter)
count = 0
while True:
if count == jump:
return alphabet[index]
if index == len(alphabet):
index = 0
index += 1
count += 1
print forward('a', 5)
print forward('z', 5)
But it doesn't look Pythonic at all...
Is there a better and Pythonic way of doing this? Maybe using chr(ord('N') + position) ?
I think you had the right idea with ord and chr:
import string
def forward(letter, jump):
if letter.islower():
start_character = ord('a')
else:
start_character = ord('A')
start = ord(letter) - start_character
offset = ((start + jump) % 26) + start_character
result = chr(offset)
return result
print forward('a', 5)
print forward('z', 5)
print forward('z', 1)
print forward('a', 26)
print forward('A', 5)
print forward('Z', 5)
print forward('Z', 1)
print forward('A', 26)
Output
f
e
a
a
F
E
A
A
I'd write a custom iterator class to encapsulate itertools.cycle() and provide a skip() functionality, e.g.:
import itertools
class CyclicSkipIterator(object):
def __init__(self, iterable):
self._iterator = itertools.cycle(iterable)
def __iter__(self):
return self
def next(self): # use __next__ on Python 3.x
return next(self._iterator)
def skip(self, number=1):
for i in xrange(number): # use range() on Python 3.x
next(self._iterator)
Then you can do exactly what you wanted with it:
import string
LOWERCASE_ALPHABET = list(string.ascii_lowercase)
lower_iter = CyclicSkipIterator(LOWERCASE_ALPHABET)
print(next(lower_iter)) # a
lower_iter.skip(4) # skip next 4 letters: b, c, d, e
print(next(lower_iter)) # f
lower_iter.skip(19) # skip another 19 letters to arrive at z
print(next(lower_iter)) # z
lower_iter.skip(4) # skip next 4 letters: a, b, c, d
print(next(lower_iter)) # e
You can add even more functionality if you wanted to, like reversing, switching iterables mid-iteration etc.
UPDATE: If you want to jump to a specific element in the list, you can add a method for that to the CyclicSkipIterator:
class CyclicSkipIterator(object):
def __init__(self, iterable):
self._iterator = itertools.cycle(iterable)
def __iter__(self):
return self
def __next__(self): # use __next__ on Python 3.x
return next(self._iterator)
def skip(self, number=1):
for _ in range(number): # use range() on Python 3.x
next(self._iterator)
def skip_to(self, element, max_count=100): # max_count protects against endless cycling
max_count = max(1, max_count) # ensure at least one iteration
for _ in range(max_count): # use range() on Python 3.x
e = next(self._iterator)
if element == e:
break
Then you can skip_to whatever letter you want:
import string
LOWERCASE_ALPHABET = list(string.ascii_lowercase)
lower_iter = CyclicSkipIterator(LOWERCASE_ALPHABET)
print(next(lower_iter)) # a
lower_iter.skip(4) # skip 4 letters: b, c, d, e
print(next(lower_iter)) # f
lower_iter.skip_to("y") # skip all letters up to y
print(next(lower_iter)) # z
lower_iter.skip(4) # skip 4 letters: a, b, c, d
print(next(lower_iter)) # e
class CyclicIterator:
def __init__(self,lst):
self.lst=lst
self.i=0
def __iter__(self):
return self
def __next__(self):
result=self.lst[self.i % len(self.lst)]
self.i+=3 #increasing by 3
return result
class that has iter() and next() meets iterator protocol. creating an instance of this iterator class
iter_cycle=CyclicIterator('abcdefghiijklmnnoprstuvyz')
numbers=range(1,27,3) # 26 letters increases by 3
list(zip(list(numbers),iter_cycle))

Which data structure to use when implementing graph representation using adjacency list

I have a graph that is very big about 1,000,000 nodes and many edges. This is what i wanted to know which is the best suited data structure when implementing an adjacency list. Here are the objects that i keep track of
Edge list
Node to node connection list
I am coding with python so I used a set(because according to this it has a o(1) average insertion time) for edge list and a dictionary to node to node connection list(by making it completely hashable according to How to make an object properly hashable?). Here is my code
class node:
def __init__(self, name = ""):
self.__name = name
def getName(self):
return self.__name
def __str__(self):
return self.__name
def __hash__(self):
return hash(self.__name)
def __lt__(self, other):
if(type(self) != type(other)):
return NotImplemented
return self.__name.__lt__(other.__name)
def __eq__(self, other):
if(type(self)) != type(other):
return NotImplemented
return self.__name == other.__name
class Edge:
def __init__(self, name = "", node1 = None, node2 = None, weight = 0):
self.__name = name
self.__firstNode = node1
self.__secondNode = node2
self.__weight = weight
def getName(self):
return self.__name
def getFirstNode(self):
return self.__firstNode
def getSecondNode(self):
return self.__secondNode
def getWeight(self):
return self.__weight
def __lt__(self, other):
if(type(self) != type(other)):
return NotImplemented
return self.__name.__lt__(other.__name) and self.__firstNode.__lt__(other.__firstNode) and self.__secondNode.__lt__(other.__secondNode) and self.__weight.__lt__(other.__weight)
def __eq__(self, other):
if(type(self) != type(other)):
return NotImplemented
return self.__name == other.__name and self.__firstNode == other.__firstNode and self.__secondNode == other.__secondNode and self.__weight == other.__weight
def __str__(self):
return self.__name + " " + str(self.__firstNode) + " " + str(self.__secondNode) + " " + str(self.__weight)
def __hash__(self):
return hash(hash(self.__name) + hash(self.__firstNode) + hash(self.__secondNode) + hash(self.__weight))
class graph:
def __init__(self):
self.__nodeToNode = {}
self.__edgeList = set()
def addEdge(self, edge):
if(type(edge) != type(Edge())):
return False
self.__edgeList.add(edge)
if(not edge.getFirstNode() in self.__nodeToNode):
self.__nodeToNode[edge.getFirstNode()] = set()
self.__nodeToNode[edge.getFirstNode()].add(edge.getSecondNode())
if(not edge.getSecondNode() in self.__nodeToNode):
self.__nodeToNode[edge.getSecondNode()] = set()
self.__nodeToNode[edge.getSecondNode()].add(edge.getSecondNode())
return True
def getNodes(self):
return dict(self.__nodeToNode)
def getEdges(self):
return set(self.__edgeList)
import string
import random
import time
grp = graph()
nodes = [None] * 20000
for i in range(20000):
st = ''.join(random.SystemRandom().choice(string.ascii_letters) for i in range(10))
node1 = node(st)
nodes[i] = node1
current = time.time()
for i in range(3000000):
rdm = random.randint(0, 199)
rdm2 = random.randint(0, 199)
st = ''.join(random.SystemRandom().choice(string.ascii_letters) for i in range(10))
eg = Edge(st, nodes[rdm], nodes[rdm2])
grp.addEdge(eg)
last = time.time()
print((last - current))
nodes = grp.getNodes()
edges = grp.getEdges()
but this code runs very slowly can i make it faster? If so by using what data structure?
Let me introduce you a way to create an adjacency list:
Suppose you have the input like this:
4 4
1 2
3 2
4 3
1 4
The first line contains 2 numbers V and E, the next E lines defines an edge between two vertices.
You can either create a .txt file and read the input or directly type in via sys.stdin.read():
input = sys.stdin.read()
data = list(map(int, input.split()))
n, m = data[0:2]
data = data[2:]
edges = list(zip(data[0:(2 * m):2], data[1:(2 * m):2]))
x, y = data[2 * m:]
adj = [[] for _ in range(n)]
x, y = x - 1, y - 1
for (a, b) in edges:
adj[a - 1].append(b - 1)
adj[b - 1].append(a - 1)
Let's output the adjacency list adj:
>>> print(adj)
[[1, 3], [0, 2], [1, 3], [2, 0]]
adj[0] have two adj nodes: 1 and 3. Meaning the node 1 have two adj nodes: 2 and 4.
And now, if you want a directed, weighted graph, you just need to modify the input like this:
4 4
1 2 3 # edge(1, 2) has the weight of 3
3 2 1
4 3 1
1 4 2
input = sys.stdin.read()
data = list(map(int, input.split()))
n, m = data[0:2]
data = data[2:]
edges = list(zip(zip(data[0:(3 * m):3], data[1:(3 * m):3]), data[2:(3 * m):3]))
data = data[3 * m:]
adj = [[] for _ in range(n)]
cost = [[] for _ in range(n)]
for ((a, b), w) in edges:
adj[a - 1].append(b - 1)
cost[a - 1].append(w)
You store the weight in cost, and for example, cost[0][1] = 3, cost[0][3] = 2.
Hope this helped!

Printing a tree with branches recursively

I'm trying to print a tree recursively in Python. For some reason, the indentation isn't working (perhaps I'm too tired at this point to see an obvious flaw). Here's the structure / class definitions that I'm working with:
class Tree(object):
def __init__(self, data):
self.data = data
self.branches = []
class Branch(object):
def __init__(self, value):
self.label = value
self.node = None
As you see, each tree has Branches, which have a label and point to another Tree (that's the node value you see there). Here's how I'm trying to print out the tree:
def __str__(self):
return self.tree_string(0)
def tree_string(self, indent):
indentation = indent * " "
result = indentation + str(self.data) + "\n";
for branch in self.branches:
result += indentation + branch.label + ": \n" + branch.node.tree_string(indent + 2)
return result
This is giving me:
4
Somewhat:
Yes
Fuller:
3
Correct:
8
Caribbean:
2
Wrong:
Wrong
Correct:
Correct
Italian:
Wrong
Burger:
Correct
Wrong:
Wrong
Nothing:
Wrong
When it should be giving me something like
4
Somewhat:
Correct
Fuller:
3
Correct:
8
Caribbean:
2
Wrong:
Wrong
Correct:
Correct
Italian:
Wrong
Burger:
Correct
Wrong:
Wrong
Nothing:
Wrong
What's causing my code to have those extra newlines and not have the proper indents?
Update
Pretty sure the data is ok. Here's a modified version that shows it's ok:
def tree_string(self, indent):
indentation = indent * " "
result = str(self.data);
if len(self.branches) > 0:
result += "["
for branch in self.branches:
result += branch.label + ":" + branch.node.tree_string(indent + 2) + " "
result += "]"
return result
..which gives the output
4[Somewhat:Correct Fuller:3[Correct:8[Caribbean:2[No:No Correct:Correct ] Italian:Wrong Burger:Correct ] Wrong:Wrong ] Nothing:Wrong ]
However, the indent values are for some reason always 0 or 2.
Looks like it should work to me:
class Tree(object):
def __init__(self, data):
self.data = data
self.branches = []
def __str__(self):
return self.tree_string(0)
def tree_string(self, indent):
indentation = indent * " "
result = indentation + str(self.data) + "\n";
for branch in self.branches:
result += indentation + branch.label + ": \n" + branch.node.tree_string(indent + 2)
return result
class Branch(object):
def __init__(self, value):
self.label = value
self.node = None
tree = Tree(4)
b1 = Branch('Somewhat')
b1.node = Tree('Yes')
b2 = Branch('Fuller')
b2.node = Tree(3)
tree.branches = [b1, b2]
b3 = Branch('Correct')
b3.node = Tree(8)
b2.node.branches = [b3]
print(tree)
yields
4
Somewhat:
Yes
Fuller:
3
Correct:
8

Categories