AVL tree

[[Category:Data Structures]]

In computer science, an '''AVL tree''' is a self-balancing binary search tree. In an AVL tree, the heights of the two child subtrees of any node differ by at most one; at no time do they differ by more than one because rebalancing is done ensure this is the case. Lookup, insertion, and deletion all take O(log ''n'') time in both the average and worst cases, where n is the number of nodes in the tree prior to the operation. Insertions and deletions may require the tree to be rebalanced by one or more tree rotations. Note the tree of nodes comprise a set, so duplicate node keys are not allowed.

AVL trees are often compared with red-black trees because they support the same set of operations and because red-black trees also take O(log ''n'') time for the basic operations.  Because AVL trees are more rigidly balanced, they are faster than red-black trees for lookup-intensive applications. Similar to red-black trees, AVL trees are height-balanced, but in general not weight-balanced nor μ-balanced; that is, sibling nodes can have hugely differing numbers of descendants.

;Task:
Implement an AVL tree in the language of choice, and provide at least basic operations.

;Related task
[[Red_black_tree_sort]]

Solution:
# Module: calculus.py

import enum

class entry_not_found(Exception):
   """Raised when an entry is not found in a collection"""
   pass

class entry_already_exists(Exception):
   """Raised when an entry already exists in a collection"""
   pass

class state(enum.Enum):
   header = 0
   left_high = 1
   right_high = 2
   balanced = 3

class direction(enum.Enum):
   from_left = 0
   from_right = 1

from abc import ABC, abstractmethod

class comparer(ABC):

    @abstractmethod
    def compare(self,t):
        pass

class node(comparer):

    def __init__(self):
        self.parent = None
        self.left = self
        self.right = self
        self.balance = state.header

    def compare(self,t):
        if self.key < t:
             return -1
        elif t < self.key:
             return 1
        else:
             return 0

    def is_header(self):
        return self.balance == state.header

    def length(self):
        if self != None:
           if self.left != None:
              left = self.left.length()
           else:
              left = 0
           if self.right != None:
              right = self.right.length()
           else:
              right = 0

           return left + right + 1
        else:
           return 0

    def rotate_left(self):
         _parent = self.parent
         x = self.right
         self.parent = x
         x.parent = _parent
         if x.left is not None:
             x.left.parent = self
         self.right = x.left
         x.left = self
         return x

    def rotate_right(self):
        _parent = self.parent
        x = self.left
        self.parent = x
        x.parent = _parent;
        if x.right is not None:
            x.right.parent = self
        self.left = x.right
        x.right = self
        return x

    def balance_left(self):

       _left = self.left

       if _left is None:
          return self;

       if _left.balance == state.left_high:
                self.balance = state.balanced
                _left.balance = state.balanced
                self = self.rotate_right()
       elif _left.balance == state.right_high:
                subright = _left.right
                if subright.balance == state.balanced:
                        self.balance = state.balanced
                        _left.balance = state.balanced
                elif subright.balance == state.right_high:
                        self.balance = state.balanced
                        _left.balance = state.left_high
                elif subright.balance == left_high:
                        root.balance = state.right_high
                        _left.balance = state.balanced
                subright.balance = state.balanced
                _left = _left.rotate_left()
                self.left = _left
                self = self.rotate_right()
       elif _left.balance == state.balanced:
               self.balance = state.left_high
               _left.balance = state.right_high
               self = self.rotate_right()
       return self;

    def balance_right(self):

       _right = self.right

       if _right is None:
          return self;

       if _right.balance == state.right_high:
                self.balance = state.balanced
                _right.balance = state.balanced
                self = self.rotate_left()
       elif _right.balance == state.left_high:
                subleft = _right.left;
                if subleft.balance == state.balanced:
                        self.balance = state.balanced
                        _right.balance = state.balanced
                elif subleft.balance == state.left_high:
                        self.balance = state.balanced
                        _right.balance = state.right_high
                elif subleft.balance == state.right_high:
                        self.balance = state.left_high
                        _right.balance = state.balanced
                subleft.balance = state.balanced
                _right = _right.rotate_right()
                self.right = _right
                self = self.rotate_left()
       elif _right.balance == state.balanced:
                self.balance = state.right_high
                _right.balance = state.left_high
                self = self.rotate_left()
       return self

    def balance_tree(self, direct):
        taller = True
        while taller:
            _parent = self.parent;
            if _parent.left == self:
                next_from =  direction.from_left
            else:
                next_from = direction.from_right;

            if direct == direction.from_left:
                if self.balance == state.left_high:
                        if _parent.is_header():
                            _parent.parent = _parent.parent.balance_left()
                        elif _parent.left == self:
                            _parent.left = _parent.left.balance_left()
                        else:
                            _parent.right = _parent.right.balance_left()
                        taller = False

                elif self.balance == state.balanced:
                        self.balance = state.left_high
                        taller = True

                elif self.balance == state.right_high:
                        self.balance = state.balanced
                        taller = False
            else:
              if self.balance == state.left_high:
                        self.balance = state.balanced
                        taller = False

              elif self.balance ==  state.balanced:
                        self.balance = state.right_high
                        taller = True

              elif self.balance ==  state.right_high:
                        if _parent.is_header():
                            _parent.parent = _parent.parent.balance_right()
                        elif _parent.left == self:
                            _parent.left = _parent.left.balance_right()
                        else:
                            _parent.right = _parent.right.balance_right()
                        taller = False

            if taller:
                if _parent.is_header():
                    taller = False
                else:
                    self = _parent
                    direct = next_from

    def balance_tree_remove(self, _from):

        if self.is_header():
            return;

        shorter = True;

        while shorter:
            _parent = self.parent;
            if _parent.left == self:
                next_from = direction.from_left
            else:
                next_from = direction.from_right

            if _from == direction.from_left:
                if self.balance == state.left_high:
                        shorter = True

                elif self.balance == state.balanced:
                        self.balance = state.right_high;
                        shorter = False

                elif self.balance == state.right_high:
                        if self.right is not None:
                            if self.right.balance == state.balanced:
                                shorter = False
                            else:
                                shorter = True
                        else:
                            shorter = False;

                        if _parent.is_header():
                            _parent.parent = _parent.parent.balance_right()
                        elif _parent.left == self:
                            _parent.left = _parent.left.balance_right();
                        else:
                            _parent.right = _parent.right.balance_right()

            else:
                if self.balance == state.right_high:
                        self.balance = state.balanced
                        shorter = True

                elif self.balance == state.balanced:
                        self.balance = state.left_high
                        shorter = False

                elif self.balance == state.left_high:

                        if self.left is not None:
                            if self.left.balance == state.balanced:
                                shorter = False
                            else:
                                shorter = True
                        else:
                           short = False;

                        if _parent.is_header():
                            _parent.parent = _parent.parent.balance_left();
                        elif _parent.left == self:
                            _parent.left = _parent.left.balance_left();
                        else:
                            _parent.right = _parent.right.balance_left();

            if shorter:
               if _parent.is_header():
                    shorter = False
               else:
                    _from = next_from
                    self = _parent

    def previous(self):
        if self.is_header():
            return self.right

        if self.left is not None:
            y = self.left
            while y.right is not None:
                y = y.right
            return y

        else:
            y = self.parent;
            if y.is_header():
                return y

            x = self
            while x == y.left:
                x = y
                y = y.parent

            return y

    def next(self):
        if self.is_header():
            return self.left

        if self.right is not None:
            y = self.right
            while y.left is not None:
                y = y.left
            return y;

        else:
            y = self.parent
            if y.is_header():
                return y

            x = self;
            while x == y.right:
                x = y
                y = y.parent;

            return y

    def swap_nodes(a, b):

        if b == a.left:
            if b.left is not None:
                b.left.parent = a

            if b.right is not None:
                b.right.parent = a

            if a.right is not None:
                a.right.parent = b

            if not a.parent.is_header():
                if a.parent.left == a:
                    a.parent.left = b
                else:
                    a.parent.right = b;
            else:
                a.parent.parent = b

            b.parent = a.parent
            a.parent = b

            a.left = b.left
            b.left = a

            temp = a.right
            a.right = b.right
            b.right = temp
        elif b == a.right:
            if b.right is not None:
                b.right.parent = a

            if b.left is not None:
               b.left.parent = a

            if a.left is not None:
               a.left.parent = b

            if not a.parent.is_header():
                if a.parent.left == a:
                    a.parent.left = b
                else:
                    a.parent.right = b
            else:
               a.parent.parent = b

            b.parent = a.parent
            a.parent = b

            a.right = b.right
            b.right = a

            temp = a.left
            a.left = b.left
            b.left = temp
        elif a == b.left:
            if a.left is not None:
                a.left.parent = b

            if a.right is not None:
                a.right.parent = b

            if b.right is not None:
                b.right.parent = a

            if not parent.is_header():
                if b.parent.left == b:
                    b.parent.left = a
                else:
                    b.parent.right = a
            else:
                b.parent.parent = a

            a.parent = b.parent
            b.parent = a

            b.left = a.left
            a.left = b

            temp = a.right
            a.right = b.right
            b.right = temp
        elif a == b.right:
            if a.right is not None:
                a.right.parent = b
            if a.left is not None:
               a.left.parent = b

            if b.left is not None:
               b.left.parent = a

            if not b.parent.is_header():
                if b.parent.left == b:
                    b.parent.left = a
                else:
                    b.parent.right = a
            else:
                b.parent.parent = a

            a.parent = b.parent
            b.parent = a

            b.right = a.right
            a.right = b

            temp = a.left
            a.left = b.left
            b.left = temp
        else:
            if a.parent == b.parent:
                temp = a.parent.left
                a.parent.left = a.parent.right
                a.parent.right = temp
            else:
                if not a.parent.is_header():
                    if a.parent.left == a:
                        a.parent.left = b
                    else:
                        a.parent.right = b
                else:
                    a.parent.parent = b

                if not b.parent.is_header():
                    if b.parent.left == b:
                        b.parent.left = a
                    else:
                        b.parent.right = a
                else:
                    b.parent.parent = a

            if b.left is not None:
                b.left.parent = a

            if b.right is not None:
                b.right.parent = a

            if a.left is not None:
                a.left.parent = b

            if a.right is not None:
                a.right.parent = b

            temp1 = a.left
            a.left = b.left
            b.left = temp1

            temp2 = a.right
            a.right = b.right
            b.right = temp2

            temp3 = a.parent
            a.parent = b.parent
            b.parent = temp3

        balance = a.balance
        a.balance = b.balance
        b.balance = balance

class parent_node(node):

    def __init__(self, parent):
        self.parent = parent
        self.left = None
        self.right = None
        self.balance = state.balanced

class set_node(node):

    def __init__(self, parent, key):
        self.parent = parent
        self.left = None
        self.right = None
        self.balance = state.balanced
        self.key = key

class ordered_set:

    def __init__(self):
        self.header = node()

    def __iter__(self):
        self.node = self.header
        return self

    def __next__(self):
        self.node = self.node.next()
        if self.node.is_header():
            raise StopIteration
        return self.node.key

    def __delitem__(self, key):
          self.remove(key)

    def __lt__(self, other):
        first1 = self.header.left
        last1 = self.header
        first2 = other.header.left
        last2 = other.header

        while (first1 != last1) and (first2 != last2):
           l =  first1.key < first2.key
           if not l:
              first1 = first1.next();
              first2 = first2.next();
           else:
              return True;

        a = self.__len__()
        b = other.__len__()
        return a < b

    def __hash__(self):
        h = 0
        for i in self:
            h = h + i.__hash__()
        return h

    def __eq__(self, other):
       if self < other:
          return False
       if other < self:
          return False
       return True

    def __ne__(self, other):
       if self < other:
          return True
       if other < self:
          return True
       return False

    def __len__(self):
        return self.header.parent.length()

    def __getitem__(self, key):
          return self.contains(key)

    def __str__(self):
       l = self.header.right
       s = "{"
       i = self.header.left
       h = self.header
       while i != h:
           s = s + i.key.__str__()
           if i != l:
               s = s + ","
           i = i.next()

       s = s + "}"
       return s

    def __or__(self, other):
       r = ordered_set()

       first1 = self.header.left
       last1 = self.header
       first2 = other.header.left
       last2 = other.header

       while first1 != last1 and first2 != last2:
          les = first1.key < first2.key
          graater = first2.key < first1.key

          if les:
             r.add(first1.key)
             first1 = first1.next()
          elif graater:
             r.add(first2.key)
             first2 = first2.next()
          else:
             r.add(first1.key)
             first1 = first1.next()
             first2 = first2.next()

       while first1 != last1:
          r.add(first1.key)
          first1 = first1.next()

       while first2 != last2:
          r.add(first2.key)
          first2 = first2.next()

       return r

    def __and__(self, other):
       r = ordered_set()

       first1 = self.header.left
       last1 = self.header
       first2 = other.header.left
       last2 = other.header

       while first1 != last1 and first2 != last2:
          les = first1.key < first2.key
          graater = first2.key < first1.key

          if les:
             first1 = first1.next()
          elif graater:
             first2 = first2.next()
          else:
             r.add(first1.key)
             first1 = first1.next()
             first2 = first2.next()

       return r

    def __xor__(self, other):
       r = ordered_set()

       first1 = self.header.left
       last1 = self.header
       first2 = other.header.left
       last2 = other.header

       while first1 != last1 and first2 != last2:
          les = first1.key < first2.key
          graater = first2.key < first1.key

          if les:
             r.add(first1.key)
             first1 = first1.next()
          elif graater:
             r.add(first2.key)
             first2 = first2.next()
          else:
             first1 = first1.next()
             first2 = first2.next()

       while first1 != last1:
          r.add(first1.key)
          first1 = first1.next()

       while first2 != last2:
          r.add(first2.key)
          first2 = first2.next()

       return r

    def __sub__(self, other):
       r = ordered_set()

       first1 = self.header.left
       last1 = self.header
       first2 = other.header.left
       last2 = other.header

       while first1 != last1 and first2 != last2:
          les = first1.key < first2.key
          graater = first2.key < first1.key

          if les:
             r.add(first1.key)
             first1 = first1.next()
          elif graater:
             r.add(first2.key)
             first2 = first2.next()
          else:
             first1 = first1.next()
             first2 = first2.next()

       while first1 != last1:
          r.add(first1.key)
          first1 = first1.next()

       return r

    def __lshift__(self, data):
       self.add(data)
       return self

    def __rshift__(self, data):
       self.remove(data)
       return self

    def is_subset(self, other):
       first1 = self.header.left
       last1 = self.header
       first2 = other.header.left
       last2 = other.header

       is_subet = True

       while first1 != last1 and first2 != last2:
          if first1.key < first2.key:
              is_subset = False
              break
          elif first2.key < first1.key:
             first2 = first2.next()
          else:
             first1 = first1.next()
             first2 = first2.next()

          if is_subet:
             if first1 != last1:
                is_subet = False

       return is_subet

    def is_superset(self,other):
       return other.is_subset(self)

    def add(self, data):
            if self.header.parent is None:
                self.header.parent = set_node(self.header,data)
                self.header.left = self.header.parent
                self.header.right = self.header.parent
            else:

                root = self.header.parent

                while True:
                    c = root.compare(data)
                    if c >= 0:
                        if root.left is not None:
                            root = root.left
                        else:
                            new_node = set_node(root,data)
                            root.left = new_node

                            if self.header.left == root:
                                 self.header.left = new_node
                            root.balance_tree(direction.from_left)
                            return

                    else:
                        if root.right is not None:
                            root = root.right
                        else:
                            new_node = set_node(root, data)
                            root.right = new_node
                            if self.header.right == root:
                                  self.header.right = new_node
                            root.balance_tree(direction.from_right)
                            return

    def remove(self,data):
        root = self.header.parent;

        while True:
            if root is None:
                raise entry_not_found("Entry not found in collection")

            c  = root.compare(data)

            if c < 0:
               root = root.left;

            elif c > 0:
               root = root.right;

            else:

                 if root.left is not None:
                     if root.right is not None:
                         replace = root.left
                         while replace.right is not None:
                             replace = replace.right
                         root.swap_nodes(replace)

                 _parent = root.parent

                 if _parent.left == root:
                     _from = direction.from_left
                 else:
                     _from = direction.from_right

                 if self.header.left == root:

                     n = root.next();

                     if n.is_header():
                         self.header.left = self.header
                         self.header.right = self.header
                     else:
                        self.header.left = n
                 elif self.header.right == root:

                     p = root.previous();

                     if p.is_header():
                          self.header.left = self.header
                          self.header.right = self.header
                     else:
                          self.header.right = p

                 if root.left is None:
                     if _parent == self.header:
                         self.header.parent = root.right
                     elif _parent.left == root:
                         _parent.left = root.right
                     else:
                         _parent.right = root.right

                     if root.right is not None:
                          root.right.parent = _parent

                 else:
                     if _parent == self.header:
                          self.header.parent = root.left
                     elif _parent.left == root:
                         _parent.left = root.left
                     else:
                         _parent.right = root.left

                     if root.left is not None:
                         root.left.parent = _parent;

                 _parent.balance_tree_remove(_from)
                 return

    def contains(self,data):
        root = self.header.parent;

        while True:
            if root == None:
                return False

            c  = root.compare(data);

            if c > 0:
               root = root.left;

            elif c < 0:
               root = root.right;

            else:

                 return True

    def find(self,data):
        root = self.header.parent;

        while True:
            if root == None:
                raise entry_not_found("An entry is not found in a collection")

            c  = root.compare(data);

            if c > 0:
               root = root.left;

            elif c < 0:
               root = root.right;

            else:

                 return root.key;

class key_value(comparer):

    def __init__(self, key, value):
        self.key = key
        self.value = value

    def compare(self,kv):
        if self.key < kv.key:
             return -1
        elif kv.key < self.key:
             return 1
        else:
             return 0

    def __lt__(self, other):
        return self.key < other.key

    def __str__(self):
        return '(' + self.key.__str__() + ',' + self.value.__str__() + ')'

    def __eq__(self, other):
       return self.key == other.key

    def __hash__(self):
        return hash(self.key)

class dictionary:

    def __init__(self):
        self.set = ordered_set()
        return None

    def __lt__(self, other):
       if self.keys() < other.keys():
          return true

       if other.keys() < self.keys():
          return false

       first1 = self.set.header.left
       last1 = self.set.header
       first2 = other.set.header.left
       last2 = other.set.header

       while (first1 != last1) and (first2 != last2):
          l =  first1.key.value < first2.key.value
          if not l:
             first1 = first1.next();
             first2 = first2.next();
          else:
             return True;

       a = self.__len__()
       b = other.__len__()
       return a < b

    def add(self, key, value):
       try:
           self.set.remove(key_value(key,None))
       except entry_not_found:
            pass
       self.set.add(key_value(key,value))
       return

    def remove(self, key):
       self.set.remove(key_value(key,None))
       return

    def clear(self):
       self.set.header = node()

    def sort(self):

      sort_bag = bag()
      for e in self:
        sort_bag.add(e.value)
      keys_set = self.keys()
      self.clear()
      i = sort_bag.__iter__()
      i = sort_bag.__next__()
      try:
        for e in keys_set:
          self.add(e,i)
          i = sort_bag.__next__()
      except:
         return

    def keys(self):
         keys_set = ordered_set()
         for e in self:
             keys_set.add(e.key)
         return keys_set

    def __len__(self):
        return self.set.header.parent.length()

    def __str__(self):
       l = self.set.header.right;
       s = "{"
       i = self.set.header.left;
       h = self.set.header;
       while i != h:
           s = s + "("
           s = s + i.key.key.__str__()
           s = s + ","
           s = s + i.key.value.__str__()
           s = s + ")"
           if i != l:
               s = s + ","
           i = i.next()

       s = s + "}"
       return s;

    def __iter__(self):

        self.set.node = self.set.header
        return self

    def __next__(self):
        self.set.node = self.set.node.next()
        if self.set.node.is_header():
            raise StopIteration
        return key_value(self.set.node.key.key,self.set.node.key.value)

    def __getitem__(self, key):
          kv = self.set.find(key_value(key,None))
          return kv.value

    def __setitem__(self, key, value):
          self.add(key,value)
          return

    def __delitem__(self, key):
          self.set.remove(key_value(key,None))

class array:

    def __init__(self):
        self.dictionary = dictionary()
        return None

    def __len__(self):
        return self.dictionary.__len__()

    def push(self, value):
       k = self.dictionary.set.header.right
       if k == self.dictionary.set.header:
           self.dictionary.add(0,value)
       else:
           self.dictionary.add(k.key.key+1,value)
       return

    def pop(self):
       if self.dictionary.set.header.parent != None:
          data = self.dictionary.set.header.right.key.value
          self.remove(self.dictionary.set.header.right.key.key)
          return data

    def add(self, key, value):
       try:
          self.dictionary.remove(key)
       except entry_not_found:
          pass
       self.dictionary.add(key,value)
       return

    def remove(self, key):
       self.dictionary.remove(key)
       return

    def sort(self):
       self.dictionary.sort()

    def clear(self):
      self.dictionary.header = node();

    def __iter__(self):
        self.dictionary.node = self.dictionary.set.header
        return self

    def __next__(self):
        self.dictionary.node = self.dictionary.node.next()
        if self.dictionary.node.is_header():
            raise StopIteration
        return self.dictionary.node.key.value

    def __getitem__(self, key):
          kv = self.dictionary.set.find(key_value(key,None))
          return kv.value

    def __setitem__(self, key, value):
          self.add(key,value)
          return

    def __delitem__(self, key):
          self.dictionary.remove(key)

    def __lshift__(self, data):
         self.push(data)
         return self

    def __lt__(self, other):
       return self.dictionary < other.dictionary

    def __str__(self):
       l = self.dictionary.set.header.right;
       s = "{"
       i = self.dictionary.set.header.left;
       h = self.dictionary.set.header;
       while i != h:
           s = s + i.key.value.__str__()
           if i != l:
               s = s + ","
           i = i.next()

       s = s + "}"
       return s;

class bag:

    def __init__(self):
        self.header = node()

    def __iter__(self):
        self.node = self.header
        return self

    def __delitem__(self, key):
          self.remove(key)

    def __next__(self):
        self.node = self.node.next()
        if self.node.is_header():
            raise StopIteration
        return self.node.key

    def __str__(self):
       l = self.header.right;
       s = "("
       i = self.header.left;
       h = self.header;
       while i != h:
           s = s + i.key.__str__()
           if i != l:
               s = s + ","
           i = i.next()

       s = s + ")"
       return s;

    def __len__(self):
        return self.header.parent.length()

    def __lshift__(self, data):
       self.add(data)
       return self

    def add(self, data):
            if self.header.parent is None:
                self.header.parent = set_node(self.header,data)
                self.header.left = self.header.parent
                self.header.right = self.header.parent
            else:

                root = self.header.parent

                while True:
                    c = root.compare(data)
                    if c >= 0:
                        if root.left is not None:
                            root = root.left
                        else:
                            new_node = set_node(root,data)
                            root.left = new_node

                            if self.header.left == root:
                                 self.header.left = new_node

                            root.balance_tree(direction.from_left)
                            return

                    else:
                        if root.right is not None:
                            root = root.right
                        else:
                            new_node = set_node(root, data)
                            root.right = new_node

                            if self.header.right == root:
                                  self.header.right = new_node

                            root.balance_tree(direction.from_right)
                            return

    def remove_first(self,data):

        root = self.header.parent;

        while True:
            if root is None:
                return False;

            c  = root.compare(data);

            if c > 0:
               root = root.left;

            elif c < 0:
               root = root.right;

            else:

                 if root.left is not None:
                     if root.right is not None:
                         replace = root.left;
                         while replace.right is not None:
                             replace = replace.right;
                         root.swap_nodes(replace);

                 _parent = root.parent

                 if _parent.left == root:
                     _from = direction.from_left
                 else:
                     _from = direction.from_right

                 if self.header.left == root:

                     n = root.next();

                     if n.is_header():
                         self.header.left = self.header
                         self.header.right = self.header
                     else:
                        self.header.left = n;
                 elif self.header.right == root:

                     p = root.previous();

                     if p.is_header():
                          self.header.left = self.header
                          self.header.right = self.header
                     else:
                          self.header.right = p

                 if root.left is None:
                     if _parent == self.header:
                         self.header.parent = root.right
                     elif _parent.left == root:
                         _parent.left = root.right
                     else:
                         _parent.right = root.right

                     if root.right is not None:
                          root.right.parent = _parent

                 else:
                     if _parent == self.header:
                          self.header.parent = root.left
                     elif _parent.left == root:
                         _parent.left = root.left
                     else:
                         _parent.right = root.left

                     if root.left is not None:
                         root.left.parent = _parent;

                 _parent.balance_tree_remove(_from)
                 return True;

    def remove(self,data):
       success = self.remove_first(data)
       while success:
          success = self.remove_first(data)

    def remove_node(self, root):

        if root.left != None and root.right != None:
            replace = root.left
            while replace.right != None:
               replace = replace.right
            root.swap_nodes(replace)

        parent = root.parent;

        if parent.left == root:
           next_from = direction.from_left
        else:
           next_from = direction.from_right

        if self.header.left == root:
            n = root.next()

            if n.is_header():
                self.header.left = self.header;
                self.header.right = self.header
            else:
                self.header.left = n
        elif self.header.right == root:
             p = root.previous()

             if p.is_header():
                root.header.left = root.header
                root.header.right = header
             else:
                self.header.right = p

        if root.left == None:
            if parent == self.header:
                self.header.parent = root.right
            elif parent.left == root:
                parent.left = root.right
            else:
                parent.right = root.right

            if root.right != None:
               root.right.parent = parent
        else:
            if parent == self.header:
                self.header.parent = root.left
            elif parent.left == root:
                parent.left = root.left
            else:
                parent.right = root.left

            if root.left != None:
               root.left.parent = parent;

        parent.balance_tree_remove(next_from)

    def remove_at(self, data, ophset):

            p = self.search(data);

            if p == None:
                return
            else:
                lower = p
                after = after(data)

            s = 0
            while True:
                if ophset == s:
                    remove_node(lower);
                    return;
                lower = lower.next_node()
                if after == lower:
                   break
                s = s+1

            return

    def search(self, key):
        s = before(key)
        s.next()
        if s.is_header():
           return None
        c = s.compare(s.key)
        if c != 0:
           return None
        return s

    def before(self, data):
        y = self.header;
        x = self.header.parent;

        while x != None:
            if x.compare(data) >= 0:
                x = x.left;
            else:
                y = x;
                x = x.right;
        return y

    def after(self, data):
        y = self.header;
        x = self.header.parent;

        while x != None:
            if x.compare(data) > 0:
                y = x
                x = x.left
            else:
                x = x.right

        return y;

    def find(self,data):
        root = self.header.parent;

        results = array()

        while True:
            if root is None:
                break;

            p = self.before(data)
            p = p.next()
            if not p.is_header():
               i = p
               l = self.after(data)
               while i != l:
                  results.push(i.key)
                  i = i.next()

               return results
            else:
               break;

        return results

class bag_dictionary:

    def __init__(self):
        self.bag = bag()
        return None

    def add(self, key, value):
       self.bag.add(key_value(key,value))
       return

    def remove(self, key):
       self.bag.remove(key_value(key,None))
       return

    def remove_at(self, key, index):
       self.bag.remove_at(key_value(key,None), index)
       return

    def clear(self):
       self.bag.header = node()

    def __len__(self):
        return self.bag.header.parent.length()

    def __str__(self):
       l = self.bag.header.right;
       s = "{"
       i = self.bag.header.left;
       h = self.bag.header;
       while i != h:
           s = s + "("
           s = s + i.key.key.__str__()
           s = s + ","
           s = s + i.key.value.__str__()
           s = s + ")"
           if i != l:
               s = s + ","
           i = i.next()

       s = s + "}"
       return s;

    def __iter__(self):

        self.bag.node = self.bag.header
        return self

    def __next__(self):
        self.bag.node = self.bag.node.next()
        if self.bag.node.is_header():
            raise StopIteration
        return key_value(self.bag.node.key.key,self.bag.node.key.value)

    def __getitem__(self, key):
          kv_array = self.bag.find(key_value(key,None))
          return kv_array

    def __setitem__(self, key, value):
          self.add(key,value)
          return

    def __delitem__(self, key):
          self.bag.remove(key_value(key,None))

class unordered_set:

    def __init__(self):
        self.bag_dictionary = bag_dictionary()

    def __len__(self):
        return self.bag_dictionary.__len__()

    def __hash__(self):
        h = 0
        for i in self:
            h = h + i.__hash__()
        return h

    def __eq__(self, other):
        for t in self:
           if not other.contains(t):
              return False
        for u in other:
           if self.contains(u):
              return False
        return true;

    def __ne__(self, other):
        return not self == other

    def __or__(self, other):
       r = unordered_set()

       for t in self:
          r.add(t);

       for u in other:
          if not self.contains(u):
             r.add(u);

       return r

    def __and__(self, other):
       r = unordered_set()

       for t in self:
          if other.contains(t):
              r.add(t)

       for u in other:
              if self.contains(u) and not r.contains(u):
                  r.add(u);

       return r

    def __xor__(self, other):
       r = unordered_set()

       for t in self:
          if not other.contains(t):
             r.add(t)

       for u in other:
          if not self.contains(u) and not r.contains(u):
             r.add(u)

       return r

    def __sub__(self, other):
       r = ordered_set()

       for t in self:
          if not other.contains(t):
             r.add(t);

       return r

    def __lshift__(self, data):
       self.add(data)
       return self

    def __rshift__(self, data):
       self.remove(data)
       return self

    def __getitem__(self, key):
          return self.contains(key)

    def is_subset(self, other):

       is_subet = True

       for t in self:
          if not other.contains(t):
             subset = False
             break

       return is_subet

    def is_superset(self,other):
       return other.is_subset(self)

    def add(self, value):
       if not self.contains(value):
           self.bag_dictionary.add(hash(value),value)
       else:
          raise entry_already_exists("Entry already exists in the unordered set")

    def contains(self, data):
            if self.bag_dictionary.bag.header.parent == None:
                return False;
            else:
                index = hash(data);

                _search = self.bag_dictionary.bag.header.parent;

                search_index =  _search.key.key;

                if index < search_index:
                   _search = _search.left

                elif index > search_index:
                   _search = _search.right

                if _search == None:
                    return False

                while _search != None:
                    search_index =  _search.key.key;

                    if index < search_index:
                       _search = _search.left

                    elif index > search_index:
                       _search = _search.right

                    else:
                       break

                if _search == None:
                   return False

                return self.contains_node(data, _search)

    def contains_node(self,data,_node):

        previous = _node.previous()
        save = _node

        while not previous.is_header() and previous.key.key == _node.key.key:
            save = previous;
            previous = previous.previous()

        c = _node.key.value
        _node = save
        if c == data:
           return True

        next = _node.next()
        while not next.is_header() and next.key.key == _node.key.key:
            _node = next
            c = _node.key.value
            if c == data:
               return True;
            next = _node.next()

        return False;

    def find(self,data,_node):

        previous = _node.previous()
        save = _node

        while not previous.is_header() and previous.key.key == _node.key.key:
            save = previous;
            previous = previous.previous();

        _node = save;
        c = _node.key.value
        if c == data:
           return _node

        next = _node.next()
        while not next.is_header() and next.key.key == _node.key.key:
            _node = next
            c = _node.data.value
            if c == data:
               return _node
            next = _node.next()

        return None

    def search(self, data):
        if self.bag_dictionary.bag.header.parent == None:
            return None
        else:
            index = hash(data)

            _search = self.bag_dictionary.bag.header.parent

            c = _search.key.key

            if index < c:
               _search = _search.left;

            elif index > c:
               _search = _search.right;

            while _search != None:

                if index != c:
                   break

                c = _search.key.key

                if index < c:
                   _search = _search.left;

                elif index > c:
                   _search = _search.right;

                else:
                   break

            if _search == None:
               return None

            return self.find(data, _search)

    def remove(self,data):
       found = self.search(data);
       if found != None:
          self.bag_dictionary.bag.remove_node(found);
       else:
          raise entry_not_found("Entry not found in the unordered set")

    def clear(self):
       self.bag_dictionary.bag.header = node()

    def __str__(self):
       l = self.bag_dictionary.bag.header.right;
       s = "{"
       i = self.bag_dictionary.bag.header.left;
       h = self.bag_dictionary.bag.header;
       while i != h:
           s = s + i.key.value.__str__()
           if i != l:
               s = s + ","
           i = i.next()

       s = s + "}"
       return s;

    def __iter__(self):

        self.bag_dictionary.bag.node = self.bag_dictionary.bag.header
        return self

    def __next__(self):
        self.bag_dictionary.bag.node = self.bag_dictionary.bag.node.next()
        if self.bag_dictionary.bag.node.is_header():
            raise StopIteration
        return self.bag_dictionary.bag.node.key.value

class map:

    def __init__(self):
        self.set = unordered_set()
        return None

    def __len__(self):
        return self.set.__len__()

    def add(self, key, value):
       try:
           self.set.remove(key_value(key,None))
       except entry_not_found:
            pass
       self.set.add(key_value(key,value))
       return

    def remove(self, key):
       self.set.remove(key_value(key,None))
       return

    def clear(self):
       self.set.clear()

    def __str__(self):
       l = self.set.bag_dictionary.bag.header.right;
       s = "{"
       i = self.set.bag_dictionary.bag.header.left;
       h = self.set.bag_dictionary.bag.header;
       while i != h:
           s = s + "("
           s = s + i.key.value.key.__str__()
           s = s + ","
           s = s + i.key.value.value.__str__()
           s = s + ")"
           if i != l:
               s = s + ","
           i = i.next()

       s = s + "}"
       return s;

    def __iter__(self):

        self.set.node = self.set.bag_dictionary.bag.header
        return self

    def __next__(self):
        self.set.node = self.set.node.next()
        if self.set.node.is_header():
            raise StopIteration
        return key_value(self.set.node.key.key,self.set.node.key.value)

    def __getitem__(self, key):
          kv = self.set.find(key_value(key,None))
          return kv.value

    def __setitem__(self, key, value):
          self.add(key,value)
          return

    def __delitem__(self, key):
          self.remove(key)


Abbreviations, automatic

The use of   abbreviations    (also sometimes called synonyms, nicknames, AKAs, or aliases)    can be an
easy way to add flexibility when specifying or using commands, sub─commands, options, etc.

It would make a list of words easier to maintain   (as words are added, changed, and/or deleted)   if
the minimum abbreviation length of that list could be automatically (programmatically) determined.

For this task, use the list (below) of the days-of-the-week names that are expressed in about a hundred languages   (note that there is a blank line in the list).

Sunday Monday Tuesday Wednesday Thursday Friday Saturday
Sondag Maandag Dinsdag Woensdag Donderdag Vrydag Saterdag
E_djelë E_hënë E_martë E_mërkurë E_enjte E_premte E_shtunë
Ehud Segno Maksegno Erob Hamus Arbe Kedame
Al_Ahad Al_Ithinin Al_Tholatha'a Al_Arbia'a Al_Kamis Al_Gomia'a Al_Sabit
Guiragui Yergou_shapti Yerek_shapti Tchorek_shapti Hink_shapti Ourpat Shapat
domingu llunes martes miércoles xueves vienres sábadu
Bazar_gÜnÜ Birinci_gÜn Çkinci_gÜn ÜçÜncÜ_gÜn DÖrdÜncÜ_gÜn Bes,inci_gÜn Altòncò_gÜn
Igande Astelehen Astearte Asteazken Ostegun Ostiral Larunbat
Robi_bar Shom_bar Mongal_bar Budhh_bar BRihashpati_bar Shukro_bar Shoni_bar
Nedjelja Ponedeljak Utorak Srijeda Cxetvrtak Petak Subota
Disul Dilun Dimeurzh Dimerc'her Diriaou Digwener Disadorn
nedelia ponedelnik vtornik sriada chetvartak petak sabota
sing_kei_yaht sing_kei_yat sing_kei_yee sing_kei_saam sing_kei_sie sing_kei_ng sing_kei_luk
Diumenge Dilluns Dimarts Dimecres Dijous Divendres Dissabte
Dzeenkk-eh Dzeehn_kk-ehreh Dzeehn_kk-ehreh_nah_kay_dzeeneh Tah_neesee_dzeehn_neh Deehn_ghee_dzee-neh Tl-oowey_tts-el_dehlee Dzeentt-ahzee
dy_Sul dy_Lun dy_Meurth dy_Mergher dy_You dy_Gwener dy_Sadorn
Dimanch Lendi Madi Mèkredi Jedi Vandredi Samdi
nedjelja ponedjeljak utorak srijeda cxetvrtak petak subota
nede^le ponde^lí úterÿ str^eda c^tvrtek pátek sobota
Sondee Mondee Tiisiday Walansedee TOOsedee Feraadee Satadee
s0ndag mandag tirsdag onsdag torsdag fredag l0rdag
zondag maandag dinsdag woensdag donderdag vrijdag zaterdag
Diman^co Lundo Mardo Merkredo ^Jaùdo Vendredo Sabato
pÜhapäev esmaspäev teisipäev kolmapäev neljapäev reede laupäev

Diu_prima Diu_sequima Diu_tritima Diu_quartima Diu_quintima Diu_sextima Diu_sabbata
sunnudagur mánadagur tÿsdaguy mikudagur hósdagur friggjadagur leygardagur
Yek_Sham'beh Do_Sham'beh Seh_Sham'beh Cha'har_Sham'beh Panj_Sham'beh Jom'eh Sham'beh
sunnuntai maanantai tiistai keskiviiko torsktai perjantai lauantai
dimanche lundi mardi mercredi jeudi vendredi samedi
Snein Moandei Tiisdei Woansdei Tonersdei Freed Sneon
Domingo Segunda_feira Martes Mércores Joves Venres Sábado
k'vira orshabati samshabati otkhshabati khutshabati p'arask'evi shabati
Sonntag Montag Dienstag Mittwoch Donnerstag Freitag Samstag
Kiriaki' Defte'ra Tri'ti Teta'rti Pe'mpti Paraskebi' Sa'bato
ravivaar somvaar mangalvaar budhvaar guruvaar shukravaar shanivaar
pópule pó`akahi pó`alua pó`akolu pó`ahá pó`alima pó`aono
Yom_rishon Yom_sheni Yom_shlishi Yom_revi'i Yom_chamishi Yom_shishi Shabat
ravivara somavar mangalavar budhavara brahaspativar shukravara shanivar
vasárnap hétfö kedd szerda csütörtök péntek szombat
Sunnudagur Mánudagur ╞riδjudagur Miδvikudagar Fimmtudagur FÖstudagur Laugardagur
sundio lundio mardio merkurdio jovdio venerdio saturdio
Minggu Senin Selasa Rabu Kamis Jumat Sabtu
Dominica Lunedi Martedi Mercuridi Jovedi Venerdi Sabbato
Dé_Domhnaigh Dé_Luain Dé_Máirt Dé_Ceadaoin Dé_ardaoin Dé_hAoine Dé_Sathairn
domenica lunedí martedí mercoledí giovedí venerdí sabato
Nichiyou_bi Getzuyou_bi Kayou_bi Suiyou_bi Mokuyou_bi Kin'you_bi Doyou_bi
Il-yo-il Wol-yo-il Hwa-yo-il Su-yo-il Mok-yo-il Kum-yo-il To-yo-il
Dies_Dominica Dies_Lunæ Dies_Martis Dies_Mercurii Dies_Iovis Dies_Veneris Dies_Saturni
sve-tdien pirmdien otrdien tresvdien ceturtdien piektdien sestdien
Sekmadienis Pirmadienis Antradienis Trec^iadienis Ketvirtadienis Penktadienis S^es^tadienis
Wangu Kazooba Walumbe Mukasa Kiwanuka Nnagawonye Wamunyi
xing-_qi-_rì xing-_qi-_yi-. xing-_qi-_èr xing-_qi-_san-. xing-_qi-_sì xing-_qi-_wuv. xing-_qi-_liù
Jedoonee Jelune Jemayrt Jecrean Jardaim Jeheiney Jesam
Jabot Manre Juje Wonje Taije Balaire Jarere
geminrongo minòmishi mártes mièrkoles misheushi bèrnashi mishábaro
Ahad Isnin Selasa Rabu Khamis Jumaat Sabtu
sφndag mandag tirsdag onsdag torsdag fredag lφrdag
lo_dimenge lo_diluns lo_dimarç lo_dimèrcres lo_dijòus lo_divendres lo_dissabte
djadomingo djaluna djamars djarason djaweps djabièrna djasabra
Niedziela Poniedzial/ek Wtorek S,roda Czwartek Pia,tek Sobota
Domingo segunda-feire terça-feire quarta-feire quinta-feire sexta-feira såbado
Domingo Lunes martes Miercoles Jueves Viernes Sabado
Duminicª Luni Mart'i Miercuri Joi Vineri Sâmbªtª
voskresenie ponedelnik vtornik sreda chetverg pyatnitsa subbota
Sunday Di-luain Di-màirt Di-ciadain Di-ardaoin Di-haoine Di-sathurne
nedjelja ponedjeljak utorak sreda cxetvrtak petak subota
Sontaha Mmantaha Labobedi Laboraro Labone Labohlano Moqebelo
Iridha- Sandhudha- Anga.haruwa-dha- Badha-dha- Brahaspa.thindha- Sikura-dha- Sena.sura-dha-
nedel^a pondelok utorok streda s^tvrtok piatok sobota
Nedelja Ponedeljek Torek Sreda Cxetrtek Petek Sobota
domingo lunes martes miércoles jueves viernes sábado
sonde mundey tude-wroko dride-wroko fode-wroko freyda Saturday
Jumapili Jumatatu Jumanne Jumatano Alhamisi Ijumaa Jumamosi
söndag måndag tisdag onsdag torsdag fredag lordag
Linggo Lunes Martes Miyerkoles Huwebes Biyernes Sabado
Lé-pài-jít Pài-it Pài-jï Pài-sañ Pài-sì Pài-gÖ. Pài-lák
wan-ar-tit wan-tjan wan-ang-kaan wan-phoet wan-pha-ru-hat-sa-boh-die wan-sook wan-sao
Tshipi Mosupologo Labobedi Laboraro Labone Labotlhano Matlhatso
Pazar Pazartesi Sali Çar,samba Per,sembe Cuma Cumartesi
nedilya ponedilok vivtorok sereda chetver pyatnytsya subota
Chu?_Nhâ.t Thú*_Hai Thú*_Ba Thú*_Tu* Thú*_Na'm Thú*_Sáu Thú*_Ba?y
dydd_Sul dyds_Llun dydd_Mawrth dyds_Mercher dydd_Iau dydd_Gwener dyds_Sadwrn
Dibeer Altine Talaata Allarba Al_xebes Aljuma Gaaw
iCawa uMvulo uLwesibini uLwesithathu uLuwesine uLwesihlanu uMgqibelo
zuntik montik dinstik mitvokh donershtik fraytik shabes
iSonto uMsombuluko uLwesibili uLwesithathu uLwesine uLwesihlanu uMgqibelo
Dies_Dominica Dies_Lunæ Dies_Martis Dies_Mercurii Dies_Iovis Dies_Veneris Dies_Saturni
Bazar_gÜnÜ Bazar_ærtæsi Çærs,ænbæ_axs,amò Çærs,ænbæ_gÜnÜ CÜmæ_axs,amò CÜmæ_gÜnÜ CÜmæ_Senbæ
Sun Moon Mars Mercury Jove Venus Saturn
zondag maandag dinsdag woensdag donderdag vrijdag zaterdag
KoseEraa GyoOraa BenEraa Kuoraa YOwaaraa FeEraa Memenaa
Sonntag Montag Dienstag Mittwoch Donnerstag Freitag Sonnabend
Domingo Luns Terza_feira Corta_feira Xoves Venres Sábado
Dies_Solis Dies_Lunae Dies_Martis Dies_Mercurii Dies_Iovis Dies_Veneris Dies_Sabbatum
xing-_qi-_tiàn xing-_qi-_yi-. xing-_qi-_èr xing-_qi-_san-. xing-_qi-_sì xing-_qi-_wuv. xing-_qi-_liù
djadomingu djaluna djamars djarason djaweps djabièrnè djasabra
Killachau Atichau Quoyllurchau Illapachau Chaskachau Kuychichau Intichau

''Caveat:   The list (above) most surely contains errors (or, at the least, differences) of what the actual (or true) names for the days-of-the-week.''

To make this Rosetta Code task page as small as possible, if processing the complete list, read the days-of-the-week from a file (that is created from the above list).

Notes concerning the above list of words
::*   each line has a list of days-of-the-week for a language, separated by at least one blank
::*   the words on each line happen to be in order, from Sunday ──► Saturday
::*   most lines have words in mixed case and some have all manner of accented words and other characters
::*   some words were translated to the nearest character that was available to ''code page''   '''437'''
::*   the characters in the words are not restricted except that they may not have imbedded blanks
::*   for this example, the use of an underscore ('''_''') was used to indicate a blank in a word

;Task:
::*   The list of words   (days of the week)   needn't be verified/validated.
::*   Write a function to find the (numeric) minimum length abbreviation for each line that would make abbreviations unique.
::*   A blank line   (or a null line)   should return a null string.
::*   Process and show the output for at least the first '''five''' lines of the file.
::*   Show all output here.

Solution:
#include
#include
#include

void process(int lineNum, char buffer[]) {
    char days[7][64];
    int i = 0, d = 0, j = 0;

    while (buffer[i] != 0) {
        if (buffer[i] == ' ') {
            days[d][j] = '\0';
            ++d;
            j = 0;
        } else if (buffer[i] == '\n' || buffer[i] == '\r') {
            days[d][j] = '\0';
            ++d;
            break;
        } else {
            days[d][j] = buffer[i];
            ++j;
        }

        if (d >= 7) {
            printf("There aren't 7 days in line %d\n", lineNum);
            return;
        }
        ++i;
    }
    if (buffer[i] == '\0') {
        days[d][j] = '\0';
        ++d;
    }

    if (d < 7) {
        printf("There aren't 7 days in line %d\n", lineNum);
        return;
    } else {
        int len = 0;

        for (len = 1; len < 64; ++len) {
            int d1;
            for (d1 = 0; d1 < 7; ++d1) {
                int d2;
                for (d2 = d1 + 1; d2 < 7; ++d2) {
                    int unique = 0;
                    for (i = 0; i < len; ++i) {
                        if (days[d1][i] != days[d2][i]) {
                            unique = 1;
                            break;
                        }
                    }
                    if (!unique) {
                        goto next_length;
                    }
                }
            }

            // uniqueness found for this length
            printf("%2d ", len);
            for (i = 0; i < 7; ++i) {
                printf(" %s", days[i]);
            }
            printf("\n");
            return;

            // a duplication was found at the current length
        next_length: {}
        }
    }

    printf("Failed to find uniqueness within the bounds.");
}

int main() {
    char buffer[1024];
    int lineNum = 1, len;
    FILE *fp;

    fp = fopen("days_of_week.txt", "r");
    while (1) {
        memset(buffer, 0, sizeof(buffer));

        fgets(buffer, sizeof(buffer), fp);
        len = strlen(buffer);

        if (len == 0 || buffer[len - 1] == '\0') {
            break;
        }

        process(lineNum++, buffer);
    }
    fclose(fp);

    return 0;
}


Abbreviations, automatic

Solution:
===Procedural===
The list of the names was edited and embedded in the HTML-Document with a <script>-tag, where it is accessible as an array called $list.
<syntaxhighlight lang="javascript">
Array.prototype.hasDoubles = function() {
  let arr = this.slice();
  while (arr.length > 1) {
    let cur = arr.shift();
    if (arr.includes(cur)) return true;
  }
  return false;
}

function getMinAbbrLen(arr) {
  if (arr.length <= 1) return '';
  let testArr = [],
      len = 0, i;
  do {
    len++;
    for (i = 0; i < arr.length; i++)
      testArr[i] = arr[i].substr(0, len);
  } while (testArr.hasDoubles());
  return len;
}

// testing
for (let x = 0; x < list.length; x++) {
  let days = list[x].split(' '),
      l    = getMinAbbrLen(days);
  for (let y = 0; y < days.length; y++)
    days[y] = days[y].substring(0, l);
  document.write(`<p>(${l}): ${days.join('. ')}.</p>`);
}
</syntaxhighlight>


Abbreviations, automatic

Solution:
def shortest_abbreviation_length(line, list_size):
    words = line.split()
    word_count = len(words)
    # Can't give true answer with unexpected number of entries
    if word_count != list_size:
        raise ValueError(f'Not enough entries, expected {list_size} found {word_count}')

    # Find the small slice length that gives list_size unique values
    abbreviation_length = 1
    abbreviations = set()
    while(True):
        abbreviations = {word[:abbreviation_length] for word in words}
        if len(abbreviations) == list_size:
            return abbreviation_length
        abbreviation_length += 1
        abbreviations.clear()

def automatic_abbreviations(filename, words_per_line):
    with open(filename) as file:
        for line in file:
            line = line.rstrip()
            if len(line) > 0:
                length = shortest_abbreviation_length(line, words_per_line)
                print(f'{length:2} {line}')
            else:
                print()

automatic_abbreviations('daysOfWeek.txt', 7)


Abbreviations, easy

This task is an easier (to code) variant of the Rosetta Code task:    [[Abbreviations, simple]].

For this task, the following   ''command table''   will be used:
    Add ALTer  BAckup Bottom  CAppend Change SCHANGE  CInsert CLAst COMPress COpy
    COUnt COVerlay CURsor DELete CDelete Down DUPlicate Xedit EXPand EXTract Find
    NFind NFINDUp NFUp CFind FINdup FUp FOrward GET Help HEXType Input POWerinput
    Join SPlit SPLTJOIN  LOAD  Locate CLocate  LOWercase UPPercase  LPrefix MACRO
    MErge MODify MOve MSG Next Overlay PARSE PREServe PURge PUT PUTD  Query  QUIT
    READ  RECover REFRESH RENum REPeat  Replace CReplace  RESet  RESTore  RGTLEFT
    RIght LEft  SAVE  SET SHift SI  SORT  SOS  STAck STATus  TOP TRAnsfer Type Up

Notes concerning the above   ''command table'':
::*   it can be thought of as one long literal string   (with blanks at end-of-lines)
::*   it may have superfluous blanks
::*   it may be in any case (lower/upper/mixed)
::*   the order of the words in the   ''command table''   must be preserved as shown
::*   the user input(s) may be in any case (upper/lower/mixed)
::*   commands will be restricted to the Latin alphabet   (A ──► Z,   a ──► z)
::*   A valid abbreviation is a word that has:
:::*   at least the minimum length of the number of capital letters of the word in the ''command table''
:::*   compares equal (regardless of case) to the leading characters of the word in the ''command table''
:::*   a length not longer than the word in the ''command table''
::::*   '''ALT''',   '''aLt''',   '''ALTE''',   and   '''ALTER'''   are all abbreviations of   '''ALTer'''
::::*   '''AL''',   '''ALF''',   '''ALTERS''',   '''TER''',   and   '''A'''    aren't valid abbreviations of   '''ALTer'''
::::*   The number of capital letters in   '''ALTer'''   indicates that any abbreviation for   '''ALTer'''   must be at least three letters
::::*   Any word longer than five characters can't be an abbreviation for   '''ALTer'''
::::*   '''o''',    '''ov''',    '''oVe''',    '''over''',    '''overL''',    '''overla'''   are all acceptable abbreviations for   '''Overlay'''
::*   if there isn't any lowercase letters in the word in the ''command table'',   then there isn't an abbreviation permitted

;Task:
::*   The command table needn't be verified/validated.
::*   Write a function to validate if the user "words"   (given as input)   are valid   (in the ''command table'').
::*   If the word   is   valid,   then return the full uppercase version of that "word".
::*   If the word        isn't     valid,   then return the lowercase string:    '''*error*'''        (7 characters).
::*   A blank input   (or a null input)   should return a null string.
::*   Show all output here.

;An example test case to be used for this task:
For a user string of:
  riG   rePEAT copies  put mo   rest    types   fup.    6       poweRin
the computer program should return the string:
  RIGHT REPEAT *error* PUT MOVE RESTORE *error* *error* *error* POWERINPUT

Solution:
#include
#include
#include
#include
#include

const char* command_table =
  "Add ALTer  BAckup Bottom  CAppend Change SCHANGE  CInsert CLAst COMPress COpy "
  "COUnt COVerlay CURsor DELete CDelete Down DUPlicate Xedit EXPand EXTract Find "
  "NFind NFINDUp NFUp CFind FINdup FUp FOrward GET Help HEXType Input POWerinput "
  "Join SPlit SPLTJOIN  LOAD  Locate CLocate  LOWercase UPPercase  LPrefix MACRO "
  "MErge MODify MOve MSG Next Overlay PARSE PREServe PURge PUT PUTD  Query  QUIT "
  "READ  RECover REFRESH RENum REPeat  Replace CReplace  RESet  RESTore  RGTLEFT "
  "RIght LEft  SAVE  SET SHift SI  SORT  SOS  STAck STATus  TOP TRAnsfer Type Up";

typedef struct command_tag {
    char* cmd;
    size_t length;
    size_t min_len;
    struct command_tag* next;
} command_t;

// str is assumed to be all uppercase
bool command_match(const command_t* command, const char* str) {
    size_t olen = strlen(str);
    return olen >= command->min_len && olen <= command->length
        && strncmp(str, command->cmd, olen) == 0;
}

// convert string to uppercase
char* uppercase(char* str, size_t n) {
    for (size_t i = 0; i < n; ++i)
        str[i] = toupper((unsigned char)str[i]);
    return str;
}

size_t get_min_length(const char* str, size_t n) {
    size_t len = 0;
    while (len < n && isupper((unsigned char)str[len]))
        ++len;
    return len;
}

void fatal(const char* message) {
    fprintf(stderr, "%s\n", message);
    exit(1);
}

void* xmalloc(size_t n) {
    void* ptr = malloc(n);
    if (ptr == NULL)
        fatal("Out of memory");
    return ptr;
}

void* xrealloc(void* p, size_t n) {
    void* ptr = realloc(p, n);
    if (ptr == NULL)
        fatal("Out of memory");
    return ptr;
}

char** split_into_words(const char* str, size_t* count) {
    size_t size = 0;
    size_t capacity = 16;
    char** words = xmalloc(capacity * sizeof(char*));
    size_t len = strlen(str);
    for (size_t begin = 0; begin < len; ) {
        size_t i = begin;
        for (; i < len && isspace((unsigned char)str[i]); ++i) {}
        begin = i;
        for (; i < len && !isspace((unsigned char)str[i]); ++i) {}
        size_t word_len = i - begin;
        if (word_len == 0)
            break;
        char* word = xmalloc(word_len + 1);
        memcpy(word, str + begin, word_len);
        word[word_len] = 0;
        begin += word_len;
        if (capacity == size) {
            capacity *= 2;
            words = xrealloc(words, capacity * sizeof(char*));
        }
        words[size++] = word;
    }
    *count = size;
    return words;
}

command_t* make_command_list(const char* table) {
    command_t* cmd = NULL;
    size_t count = 0;
    char** words = split_into_words(table, &count);
    for (size_t i = 0; i < count; ++i) {
        char* word = words[i];
        command_t* new_cmd = xmalloc(sizeof(command_t));
        size_t word_len = strlen(word);
        new_cmd->length = word_len;
        new_cmd->min_len = get_min_length(word, word_len);
        new_cmd->cmd = uppercase(word, word_len);
        new_cmd->next = cmd;
        cmd = new_cmd;
    }
    free(words);
    return cmd;
}

void free_command_list(command_t* cmd) {
    while (cmd != NULL) {
        command_t* next = cmd->next;
        free(cmd->cmd);
        free(cmd);
        cmd = next;
    }
}

const command_t* find_command(const command_t* commands, const char* word) {
    for (const command_t* cmd = commands; cmd != NULL; cmd = cmd->next) {
        if (command_match(cmd, word))
            return cmd;
    }
    return NULL;
}

void test(const command_t* commands, const char* input) {
    printf(" input: %s\n", input);
    printf("output:");
    size_t count = 0;
    char** words = split_into_words(input, &count);
    for (size_t i = 0; i < count; ++i) {
        char* word = words[i];
        uppercase(word, strlen(word));
        const command_t* cmd_ptr = find_command(commands, word);
        printf(" %s", cmd_ptr ? cmd_ptr->cmd : "*error*");
        free(word);
    }
    free(words);
    printf("\n");
}

int main() {
    command_t* commands = make_command_list(command_table);
    const char* input = "riG   rePEAT copies  put mo   rest    types   fup.    6       poweRin";
    test(commands, input);
    free_command_list(commands);
    return 0;
}


Abbreviations, easy

Solution:
var abr=`Add ALTer  BAckup Bottom  CAppend Change SCHANGE  CInsert CLAst COMPress COpy
   COUnt COVerlay CURsor DELete CDelete Down DUPlicate Xedit EXPand EXTract Find
   NFind NFINDUp NFUp CFind FINdup FUp FOrward GET Help HEXType Input POWerinput
   Join SPlit SPLTJOIN  LOAD  Locate CLocate  LOWercase UPPercase  LPrefix MACRO
   MErge MODify MOve MSG Next Overlay PARSE PREServe PURge PUT PUTD  Query  QUIT
   READ  RECover REFRESH RENum REPeat  Replace CReplace  RESet  RESTore  RGTLEFT
   RIght LEft  SAVE  SET SHift SI  SORT  SOS  STAck STATus  TOP TRAnsfer Type Up`
   .split(/\W+/).map(_=>_.trim())
function escapeRegex(string) {
    return string.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&');
}
var input = prompt();
console.log(input.length==0?null:input.trim().split(/\s+/)
            .map(
              (s=>abr.filter(
                a=>(new RegExp('^'+escapeRegex(s),'i'))
                  .test(a)&&s.length>=a.match(/^[A-Z]+/)[0].length
				  )[0])
				)
            .map(_=>typeof _=="undefined"?"*error*":_).join(' ')
			)


Abbreviations, easy

Solution:
command_table_text = \
"""Add ALTer  BAckup Bottom  CAppend Change SCHANGE  CInsert CLAst COMPress COpy
COUnt COVerlay CURsor DELete CDelete Down DUPlicate Xedit EXPand EXTract Find
NFind NFINDUp NFUp CFind FINdup FUp FOrward GET Help HEXType Input POWerinput
Join SPlit SPLTJOIN  LOAD  Locate CLocate  LOWercase UPPercase  LPrefix MACRO
MErge MODify MOve MSG Next Overlay PARSE PREServe PURge PUT PUTD  Query  QUIT
READ  RECover REFRESH RENum REPeat  Replace CReplace  RESet  RESTore  RGTLEFT
RIght LEft  SAVE  SET SHift SI  SORT  SOS  STAck STATus  TOP TRAnsfer Type Up"""

user_words = "riG   rePEAT copies  put mo   rest    types   fup.    6       poweRin"

def find_abbreviations_length(command_table_text):
    """ find the minimal abbreviation length for each word by counting capital letters.
        a word that does not have capital letters gets it's full length as the minimum.
    """
    command_table = dict()
    for word in command_table_text.split():
        abbr_len = sum(1 for c in word if c.isupper())
        if abbr_len == 0:
            abbr_len = len(word)
        command_table[word] = abbr_len
    return command_table

def find_abbreviations(command_table):
    """ for each command insert all possible abbreviations"""
    abbreviations = dict()
    for command, min_abbr_len in command_table.items():
        for l in range(min_abbr_len, len(command)+1):
            abbr = command[:l].lower()
            abbreviations[abbr] = command.upper()
    return abbreviations

def parse_user_string(user_string, abbreviations):
    user_words = [word.lower() for word in user_string.split()]
    commands = [abbreviations.get(user_word, "*error*") for user_word in user_words]
    return " ".join(commands)

command_table = find_abbreviations_length(command_table_text)
abbreviations_table = find_abbreviations(command_table)

full_words = parse_user_string(user_words, abbreviations_table)

print("user words:", user_words)
print("full words:", full_words)


Abbreviations, simple

The use of   abbreviations    (also sometimes called synonyms, nicknames, AKAs, or aliases)    can be an
easy way to add flexibility when specifying or using commands, sub─commands, options, etc.

For this task, the following   ''command table''   will be used:
    add 1  alter 3  backup 2  bottom 1  Cappend 2  change 1  Schange  Cinsert 2  Clast 3
    compress 4 copy 2 count 3 Coverlay 3 cursor 3  delete 3 Cdelete 2  down 1  duplicate
    3 xEdit 1 expand 3 extract 3  find 1 Nfind 2 Nfindup 6 NfUP 3 Cfind 2 findUP 3 fUP 2
    forward 2  get  help 1 hexType 4  input 1 powerInput 3  join 1 split 2 spltJOIN load
    locate 1 Clocate 2 lowerCase 3 upperCase 3 Lprefix 2  macro  merge 2 modify 3 move 2
    msg  next 1 overlay 1 parse preserve 4 purge 3 put putD query 1 quit  read recover 3
    refresh renum 3 repeat 3 replace 1 Creplace 2 reset 3 restore 4 rgtLEFT right 2 left
    2  save  set  shift 2  si  sort  sos  stack 3 status 4 top  transfer 3  type 1  up 1

Notes concerning the above   ''command table'':
::*   it can be thought of as one long literal string   (with blanks at end-of-lines)
::*   it may have superfluous blanks
::*   it may be in any case (lower/upper/mixed)
::*   the order of the words in the   ''command table''   must be preserved as shown
::*   the user input(s) may be in any case (upper/lower/mixed)
::*   commands will be restricted to the Latin alphabet   (A ──► Z,   a ──► z)
::*   a command is followed by an optional number, which indicates the minimum abbreviation
::*   A valid abbreviation is a word that has:
:::*   at least the minimum length of the word's minimum number in the ''command table''
:::*   compares equal (regardless of case) to the leading characters of the word in the ''command table''
:::*   a length not longer than the word in the ''command table''
::::*   '''ALT''',   '''aLt''',   '''ALTE''',   and   '''ALTER'''   are all abbreviations of   '''ALTER 3'''
::::*   '''AL''',   '''ALF''',   '''ALTERS''',   '''TER''',   and   '''A'''    aren't valid abbreviations of   '''ALTER 3'''
::::*   The   '''3'''   indicates that any abbreviation for   '''ALTER'''   must be at least three characters
::::*   Any word longer than five characters can't be an abbreviation for   '''ALTER'''
::::*   '''o''',    '''ov''',    '''oVe''',    '''over''',    '''overL''',    '''overla'''   are all acceptable abbreviations for   '''overlay 1'''
::*   if there isn't a number after the command,   then there isn't an abbreviation permitted

;Task:
::*   The command table needn't be verified/validated.
::*   Write a function to validate if the user "words"   (given as input)   are valid   (in the ''command table'').
::*   If the word   is   valid,   then return the full uppercase version of that "word".
::*   If the word        isn't     valid,   then return the lowercase string:    '''*error*'''        (7 characters).
::*   A blank input   (or a null input)   should return a null string.
::*   Show all output here.

;An example test case to be used for this task:
For a user string of:
  riG   rePEAT copies  put mo   rest    types   fup.    6       poweRin
the computer program should return the string:
  RIGHT REPEAT *error* PUT MOVE RESTORE *error* *error* *error* POWERINPUT

Solution:
#include
#include
#include
#include
#include

const char* command_table =
  "add 1  alter 3  backup 2  bottom 1  Cappend 2  change 1  Schange  Cinsert 2  Clast 3 "
  "compress 4 copy 2 count 3 Coverlay 3 cursor 3  delete 3 Cdelete 2  down 1  duplicate "
  "3 xEdit 1 expand 3 extract 3  find 1 Nfind 2 Nfindup 6 NfUP 3 Cfind 2 findUP 3 fUP 2 "
  "forward 2  get  help 1 hexType 4  input 1 powerInput 3  join 1 split 2 spltJOIN load "
  "locate 1 Clocate 2 lowerCase 3 upperCase 3 Lprefix 2  macro  merge 2 modify 3 move 2 "
  "msg  next 1 overlay 1 parse preserve 4 purge 3 put putD query 1 quit  read recover 3 "
  "refresh renum 3 repeat 3 replace 1 Creplace 2 reset 3 restore 4 rgtLEFT right 2 left "
  "2  save  set  shift 2  si  sort  sos  stack 3 status 4 top  transfer 3  type 1  up 1";

typedef struct command_tag {
    char* cmd;
    size_t length;
    size_t min_len;
    struct command_tag* next;
} command_t;

// str is assumed to be all uppercase
bool command_match(const command_t* command, const char* str) {
    size_t olen = strlen(str);
    return olen >= command->min_len && olen <= command->length
        && strncmp(str, command->cmd, olen) == 0;
}

// convert string to uppercase
char* uppercase(char* str, size_t n) {
    for (size_t i = 0; i < n; ++i)
        str[i] = toupper((unsigned char)str[i]);
    return str;
}

void fatal(const char* message) {
    fprintf(stderr, "%s\n", message);
    exit(1);
}

void* xmalloc(size_t n) {
    void* ptr = malloc(n);
    if (ptr == NULL)
        fatal("Out of memory");
    return ptr;
}

void* xrealloc(void* p, size_t n) {
    void* ptr = realloc(p, n);
    if (ptr == NULL)
        fatal("Out of memory");
    return ptr;
}

char** split_into_words(const char* str, size_t* count) {
    size_t size = 0;
    size_t capacity = 16;
    char** words = xmalloc(capacity * sizeof(char*));
    size_t len = strlen(str);
    for (size_t begin = 0; begin < len; ) {
        size_t i = begin;
        for (; i < len && isspace((unsigned char)str[i]); ++i) {}
        begin = i;
        for (; i < len && !isspace((unsigned char)str[i]); ++i) {}
        size_t word_len = i - begin;
        if (word_len == 0)
            break;
        char* word = xmalloc(word_len + 1);
        memcpy(word, str + begin, word_len);
        word[word_len] = 0;
        begin += word_len;
        if (capacity == size) {
            capacity *= 2;
            words = xrealloc(words, capacity * sizeof(char*));
        }
        words[size++] = word;
    }
    *count = size;
    return words;
}

command_t* make_command_list(const char* table) {
    command_t* cmd = NULL;
    size_t count = 0;
    char** words = split_into_words(table, &count);
    for (size_t i = 0; i < count; ++i) {
        char* word = words[i];
        command_t* new_cmd = xmalloc(sizeof(command_t));
        size_t word_len = strlen(word);
        new_cmd->length = word_len;
        new_cmd->min_len = word_len;
        new_cmd->cmd = uppercase(word, word_len);
        if (i + 1 < count) {
            char* eptr = 0;
            unsigned long min_len = strtoul(words[i + 1], &eptr, 10);
            if (min_len > 0 && *eptr == 0) {
                free(words[i + 1]);
                new_cmd->min_len = min_len;
                ++i;
            }
        }
        new_cmd->next = cmd;
        cmd = new_cmd;
    }
    free(words);
    return cmd;
}

void free_command_list(command_t* cmd) {
    while (cmd != NULL) {
        command_t* next = cmd->next;
        free(cmd->cmd);
        free(cmd);
        cmd = next;
    }
}

const command_t* find_command(const command_t* commands, const char* word) {
    for (const command_t* cmd = commands; cmd != NULL; cmd = cmd->next) {
        if (command_match(cmd, word))
            return cmd;
    }
    return NULL;
}

void test(const command_t* commands, const char* input) {
    printf(" input: %s\n", input);
    printf("output:");
    size_t count = 0;
    char** words = split_into_words(input, &count);
    for (size_t i = 0; i < count; ++i) {
        char* word = words[i];
        uppercase(word, strlen(word));
        const command_t* cmd_ptr = find_command(commands, word);
        printf(" %s", cmd_ptr ? cmd_ptr->cmd : "*error*");
        free(word);
    }
    free(words);
    printf("\n");
}

int main() {
    command_t* commands = make_command_list(command_table);
    const char* input = "riG   rePEAT copies  put mo   rest    types   fup.    6       poweRin";
    test(commands, input);
    free_command_list(commands);
    return 0;
}


Abbreviations, simple

Solution:
(() => {
    'use strict';

    // withExpansions :: [(String, Int)] -> String -> String
    const withExpansions = tbl => s =>
        unwords(map(expanded(tbl), words(s)));

    // expanded :: [(String, Int)] -> String -> String
    const expanded = tbl => s => {
        const
            lng = s.length,
            u = toUpper(s),
            p = wn => {
                const [w, n] = Array.from(wn);
                return lng >= n && isPrefixOf(u, w);
            }
        return maybe(
            '*error*',
            fst,
            0 < lng ? (
                find(p, tbl)
            ) : Just(Tuple([], 0))
        );
    };

    // cmdsFromString :: String -> [(String, Int)]
    const cmdsFromString = s =>
        fst(foldr(
            (w, a) => {
                const [xs, n] = Array.from(a);
                return isDigit(head(w)) ? (
                    Tuple(xs, parseInt(w, 10))
                ) : Tuple(
                    [Tuple(toUpper(w), n)].concat(xs),
                    0
                );
            },
            Tuple([], 0),
            words(s)
        ));

    // TEST -----------------------------------------------
    const main = () => {

        // table :: [(String, Int)]
        const table = cmdsFromString(
            `add 1  alter 3  backup 2  bottom 1  Cappend 2  change 1
            Schange Cinsert 2  Clast 3 compress 4 copy 2 count 3 Coverlay 3
            cursor 3  delete 3 Cdelete 2  down 1  duplicate 3 xEdit 1 expand 3
            extract 3  find 1 Nfind 2 Nfindup 6 NfUP 3 Cfind 2 findUP 3 fUP 2
            forward 2  get  help 1 hexType 4 input 1 powerInput 3  join 1
            split 2 spltJOIN load locate 1 Clocate 2 lowerCase 3 upperCase 3
            Lprefix 2  macro  merge 2 modify 3 move 2 msg  next 1 overlay 1
            parse preserve 4 purge 3 put putD query 1 quit read recover 3
            refresh renum 3 repeat 3 replace 1 Creplace 2 reset 3 restore 4
            rgtLEFT right 2 left 2  save  set  shift 2  si  sort  sos stack 3
            status 4 top  transfer 3  type 1  up 1`
        );

        return fTable(
            'Abbreviation tests:\n',
            s => "'" + s + "'",
            s => "\n\t'" + s + "'",
            withExpansions(table),
            [
                'riG   rePEAT copies  put mo   rest    types   fup.    6      poweRin',
                ''
            ]
        );
    };

    // GENERIC FUNCTIONS ----------------------------------

    // Just :: a -> Maybe a
    const Just = x => ({
        type: 'Maybe',
        Nothing: false,
        Just: x
    });

    // Nothing :: Maybe a
    const Nothing = () => ({
        type: 'Maybe',
        Nothing: true,
    });

    // Tuple (,) :: a -> b -> (a, b)
    const Tuple = (a, b) => ({
        type: 'Tuple',
        '0': a,
        '1': b,
        length: 2
    });

    // compose (<<<) :: (b -> c) -> (a -> b) -> a -> c
    const compose = (f, g) => x => f(g(x));

    // find :: (a -> Bool) -> [a] -> Maybe a
    const find = (p, xs) => {
        for (let i = 0, lng = xs.length; i < lng; i++) {
            if (p(xs[i])) return Just(xs[i]);
        }
        return Nothing();
    };

    // flip :: (a -> b -> c) -> b -> a -> c
    const flip = f =>
        1 < f.length ? (
            (a, b) => f(b, a)
        ) : (x => y => f(y)(x));

    // foldl1 :: (a -> a -> a) -> [a] -> a
    const foldl1 = (f, xs) =>
        1 < xs.length ? xs.slice(1)
        .reduce(f, xs[0]) : xs[0];

    // foldr :: (a -> b -> b) -> b -> [a] -> b
    const foldr = (f, a, xs) => xs.reduceRight(flip(f), a);

    // fst :: (a, b) -> a
    const fst = tpl => tpl[0];

    // fTable :: String -> (a -> String) ->
    //                     (b -> String) -> (a -> b) -> [a] -> String
    const fTable = (s, xShow, fxShow, f, xs) => {
        // Heading -> x display function ->
        //           fx display function ->
        //    f -> values -> tabular string
        const
            ys = map(xShow, xs),
            w = maximum(map(length, ys)),
            rows = zipWith(
                (a, b) => justifyRight(w, ' ', a) + ' -> ' + b,
                ys,
                map(compose(fxShow, f), xs)
            );
        return s + '\n' + unlines(rows);
    };

    // head :: [a] -> a
    const head = xs => xs.length ? xs[0] : undefined;

    // isDigit :: Char -> Bool
    const isDigit = c => {
        const n = ord(c);
        return 48 <= n && 57 >= n;
    };

    // isPrefixOf takes two lists or strings and returns
    // true iff the first is a prefix of the second.

    // isPrefixOf :: [a] -> [a] -> Bool
    // isPrefixOf :: String -> String -> Bool
    const isPrefixOf = (xs, ys) => {
        const go = (xs, ys) => {
            const intX = xs.length;
            return 0 < intX ? (
                ys.length >= intX ? xs[0] === ys[0] && go(
                    xs.slice(1), ys.slice(1)
                ) : false
            ) : true;
        };
        return 'string' !== typeof xs ? (
            go(xs, ys)
        ) : ys.startsWith(xs);
    };

    // justifyRight :: Int -> Char -> String -> String
    const justifyRight = (n, cFiller, s) =>
        n > s.length ? (
            s.padStart(n, cFiller)
        ) : s;

    // Returns Infinity over objects without finite length.
    // This enables zip and zipWith to choose the shorter
    // argument when one is non-finite, like cycle, repeat etc

    // length :: [a] -> Int
    const length = xs =>
        (Array.isArray(xs) || 'string' === typeof xs) ? (
            xs.length
        ) : Infinity;

    // map :: (a -> b) -> [a] -> [b]
    const map = (f, xs) =>
        (Array.isArray(xs) ? (
            xs
        ) : xs.split('')).map(f);

    // maximum :: Ord a => [a] -> a
    const maximum = xs =>
        0 < xs.length ? (
            foldl1((a, x) => x > a ? x : a, xs)
        ) : undefined;

    // maybe :: b -> (a -> b) -> Maybe a -> b
    const maybe = (v, f, m) =>
        m.Nothing ? v : f(m.Just);

    // ord :: Char -> Int
    const ord = c => c.codePointAt(0);

    // take :: Int -> [a] -> [a]
    // take :: Int -> String -> String
    const take = (n, xs) =>
        'GeneratorFunction' !== xs.constructor.constructor.name ? (
            xs.slice(0, n)
        ) : [].concat.apply([], Array.from({
            length: n
        }, () => {
            const x = xs.next();
            return x.done ? [] : [x.value];
        }));

    // toUpper :: String -> String
    const toUpper = s => s.toLocaleUpperCase();

    // unlines :: [String] -> String
    const unlines = xs => xs.join('\n');

    // unwords :: [String] -> String
    const unwords = xs => xs.join(' ');

    // words :: String -> [String]
    const words = s => s.split(/\s+/);

    // Use of `take` and `length` here allows zipping with non-finite lists
    // i.e. generators like cycle, repeat, iterate.

    // zipWith :: (a -> b -> c) -> [a] -> [b] -> [c]
    const zipWith = (f, xs, ys) => {
        const
            lng = Math.min(length(xs), length(ys)),
            as = take(lng, xs),
            bs = take(lng, ys);
        return Array.from({
            length: lng
        }, (_, i) => f(as[i], bs[i], i));
    };

    // MAIN ---
    return main();
})();


Abbreviations, simple

Solution:
command_table_text = """add 1  alter 3  backup 2  bottom 1  Cappend 2  change 1  Schange  Cinsert 2  Clast 3
   compress 4 copy 2 count 3 Coverlay 3 cursor 3  delete 3 Cdelete 2  down 1  duplicate
   3 xEdit 1 expand 3 extract 3  find 1 Nfind 2 Nfindup 6 NfUP 3 Cfind 2 findUP 3 fUP 2
   forward 2  get  help 1 hexType 4  input 1 powerInput 3  join 1 split 2 spltJOIN load
   locate 1 Clocate 2 lowerCase 3 upperCase 3 Lprefix 2  macro  merge 2 modify 3 move 2
   msg  next 1 overlay 1 parse preserve 4 purge 3 put putD query 1 quit  read recover 3
   refresh renum 3 repeat 3 replace 1 Creplace 2 reset 3 restore 4 rgtLEFT right 2 left
   2  save  set  shift 2  si  sort  sos  stack 3 status 4 top  transfer 3  type 1  up 1"""

user_words = "riG   rePEAT copies  put mo   rest    types   fup.    6       poweRin"

def find_abbreviations_length(command_table_text):
    """ find the minimal abbreviation length for each word.
        a word that does not have minimum abbreviation length specified
        gets it's full lengths as the minimum.
    """
    command_table = dict()
    input_iter = iter(command_table_text.split())

    word = None
    try:
        while True:
            if word is None:
                word = next(input_iter)
            abbr_len = next(input_iter, len(word))
            try:
                command_table[word] = int(abbr_len)
                word = None
            except ValueError:
                command_table[word] = len(word)
                word = abbr_len
    except StopIteration:
        pass
    return command_table

def find_abbreviations(command_table):
    """ for each command insert all possible abbreviations"""
    abbreviations = dict()
    for command, min_abbr_len in command_table.items():
        for l in range(min_abbr_len, len(command)+1):
            abbr = command[:l].lower()
            abbreviations[abbr] = command.upper()
    return abbreviations

def parse_user_string(user_string, abbreviations):
    user_words = [word.lower() for word in user_string.split()]
    commands = [abbreviations.get(user_word, "*error*") for user_word in user_words]
    return " ".join(commands)

command_table = find_abbreviations_length(command_table_text)
abbreviations_table = find_abbreviations(command_table)

full_words = parse_user_string(user_words, abbreviations_table)

print("user words:", user_words)
print("full words:", full_words)


Abelian sandpile model

Implement the '''Abelian sandpile model''' also known as '''Bak–Tang–Wiesenfeld model'''. Its history, mathematical definition and properties can be found under its [https://en.wikipedia.org/wiki/Abelian_sandpile_model wikipedia article].

The task requires the creation of a 2D grid of arbitrary size on which "piles of sand" can be placed. Any "pile" that has 4 or more sand particles on it ''collapses'', resulting in '''four particles being subtracted from the pile''' and '''distributed among its neighbors.'''

It is recommended to display the output in some kind of image format, as terminal emulators are usually too small to display images larger than a few dozen characters tall. As an example of how to accomplish this, see the [https://rosettacode.org/wiki/Bitmap/Write_a_PPM_file Bitmap/Write a PPM file] task.
[http://www.math.cmu.edu/~wes/sand.html Examples up to 2^30, wow!]
[http://www.natureincode.com/code/various/sandpile.html javascript running on web]
'''Examples:'''

0 0 0 0 0    0 0 0 0 0
0 0 0 0 0    0 0 1 0 0
0 0 4 0 0 -> 0 1 0 1 0
0 0 0 0 0    0 0 1 0 0
0 0 0 0 0    0 0 0 0 0

0 0 0 0 0    0 0 0 0 0
0 0 0 0 0    0 0 1 0 0
0 0 6 0 0 -> 0 1 2 1 0
0 0 0 0 0    0 0 1 0 0
0 0 0 0 0    0 0 0 0 0

0  0 0  0  0    0 0 1 0 0
0  0 0  0  0    0 2 1 2 0
0  0 16 0  0 -> 1 1 0 1 1
0  0 0  0  0    0 2 1 2 0
0  0 0  0  0    0 0 1 0 0

Solution:
#include
#include
#include

int main(int argc, char** argv)
{
	int i,j,sandPileEdge, centerPileHeight, processAgain = 1,top,down,left,right;
	int** sandPile;
	char* fileName;
	static unsigned char colour[3];

	if(argc!=3){
		printf("Usage: %s  ",argv[0]);
		return 0;
	}

	sandPileEdge = atoi(argv[1]);
	centerPileHeight = atoi(argv[2]);

	if(sandPileEdge<=0 || centerPileHeight<=0){
		printf("Sand pile and center pile dimensions must be positive integers.");
		return 0;
	}

	sandPile = (int**)malloc(sandPileEdge * sizeof(int*));

	for(i=0;i=4){
					if(i-1>=0){
						top = 1;
						sandPile[i-1][j]+=1;
						if(sandPile[i-1][j]>=4)
							processAgain = 1;
					}
					if(i+1=4)
							processAgain = 1;
					}
					if(j-1>=0){
						left = 1;
						sandPile[i][j-1]+=1;
						if(sandPile[i][j-1]>=4)
							processAgain = 1;
					}
					if(j+1=4)
							processAgain = 1;
					}
				sandPile[i][j] -= (top + down + left + right);
				if(sandPile[i][j]>=4)
					processAgain = 1;
				}
			}
		}
	}

	printf("Final sand pile : \n\n");

	for(i=0;i

Console output :

abhishek_ghosh@Azure:~/doodles$ ./a.out 10 64
Initial sand pile :

  0  0  0  0  0  0  0  0  0  0
  0  0  0  0  0  0  0  0  0  0
  0  0  0  0  0  0  0  0  0  0
  0  0  0  0  0  0  0  0  0  0
  0  0  0  0  0  0  0  0  0  0
  0  0  0  0  0 64  0  0  0  0
  0  0  0  0  0  0  0  0  0  0
  0  0  0  0  0  0  0  0  0  0
  0  0  0  0  0  0  0  0  0  0
  0  0  0  0  0  0  0  0  0  0
Final sand pile :

  0  0  0  0  0  0  0  0  0  0
  0  0  0  0  0  0  0  0  0  0
  0  0  0  0  1  2  1  0  0  0
  0  0  0  2  2  2  2  2  0  0
  0  0  1  2  2  2  2  2  1  0
  0  0  2  2  2  0  2  2  2  0
  0  0  1  2  2  2  2  2  1  0
  0  0  0  2  2  2  2  2  0  0
  0  0  0  0  1  2  1  0  0  0
  0  0  0  0  0  0  0  0  0  0

Image file written to Final_Sand_Pile_10_64.ppm


Abelian sandpile model

Solution:
import numpy as np
import matplotlib.pyplot as plt

def iterate(grid):
    changed = False
    for ii, arr in enumerate(grid):
        for jj, val in enumerate(arr):
            if val > 3:
                grid[ii, jj] -= 4
                if ii > 0:
                    grid[ii - 1, jj] += 1
                if ii < len(grid)-1:
                    grid[ii + 1, jj] += 1
                if jj > 0:
                    grid[ii, jj - 1] += 1
                if jj < len(grid)-1:
                    grid[ii, jj + 1] += 1
                changed = True
    return grid, changed

def simulate(grid):
    while True:
        grid, changed = iterate(grid)
        if not changed:
            return grid

if __name__ == '__main__':
    start_grid = np.zeros((10, 10))
    start_grid[4:5, 4:5] = 64
    final_grid = simulate(start_grid.copy())
    plt.figure()
    plt.gray()
    plt.imshow(start_grid)
    plt.figure()
    plt.gray()
    plt.imshow(final_grid)