def join(self, column_label, other, other_label=None):
if self.num_rows == <NUM_LIT:0> or other.num_rows == <NUM_LIT:0>:<EOL><INDENT>return None<EOL><DEDENT>if not other_label:<EOL><INDENT>other_label = column_label<EOL><DEDENT>self_rows = self.index_by(column_label)<EOL>other_rows = other.index_by(other_label)<EOL>joined_rows = []<EOL>for v, rows in self_rows.items():<EOL><INDENT>if v in other_rows:<EOL><INDENT>joined_rows += [row + o for row in rows for o in other_rows[v]]<EOL><DEDENT><DEDENT>if not joined_rows:<EOL><INDENT>return None<EOL><DEDENT>self_labels = list(self.labels)<EOL>other_labels = [self._unused_label(s) for s in other.labels]<EOL>other_labels_map = dict(zip(other.labels, other_labels))<EOL>joined = type(self)(self_labels + other_labels).with_rows(joined_rows)<EOL>joined._formats.update(self._formats)<EOL>for label in other._formats:<EOL><INDENT>joined._formats[other_labels_map[label]] = other._formats[label]<EOL><DEDENT>del joined[other_labels_map[other_label]]<EOL>if column_label not in self._formats and other_label in other._formats:<EOL><INDENT>joined._formats[column_label] = other._formats[other_label]<EOL><DEDENT>return joined.move_to_start(column_label).sort(column_label)<EOL>
Creates a new table with the columns of self and other, containing
        rows for all values of a column that appear in both tables.

        Args:
            ``column_label`` (``str``):  label of column in self that is used to
                join  rows of ``other``.
            ``other``: Table object to join with self on matching values of
                ``column_label``.

        Kwargs:
            ``other_label`` (``str``): default None, assumes ``column_label``.
                Otherwise in ``other`` used to join rows.

        Returns:
            New table self joined with ``other`` by matching values in
            ``column_label`` and ``other_label``. If the resulting join is
            empty, returns None.

        >>> table = Table().with_columns('a', make_array(9, 3, 3, 1),
        ...     'b', make_array(1, 2, 2, 10),
        ...     'c', make_array(3, 4, 5, 6))
        >>> table
        a    | b    | c
        9    | 1    | 3
        3    | 2    | 4
        3    | 2    | 5
        1    | 10   | 6
        >>> table2 = Table().with_columns( 'a', make_array(9, 1, 1, 1),
        ... 'd', make_array(1, 2, 2, 10),
        ... 'e', make_array(3, 4, 5, 6))
        >>> table2
        a    | d    | e
        9    | 1    | 3
        1    | 2    | 4
        1    | 2    | 5
        1    | 10   | 6
        >>> table.join('a', table2)
        a    | b    | c    | d    | e
        1    | 10   | 6    | 2    | 4
        1    | 10   | 6    | 2    | 5
        1    | 10   | 6    | 10   | 6
        9    | 1    | 3    | 1    | 3
        >>> table.join('a', table2, 'a') # Equivalent to previous join
        a    | b    | c    | d    | e
        1    | 10   | 6    | 2    | 4
        1    | 10   | 6    | 2    | 5
        1    | 10   | 6    | 10   | 6
        9    | 1    | 3    | 1    | 3
        >>> table.join('a', table2, 'd') # Repeat column labels relabeled
        a    | b    | c    | a_2  | e
        1    | 10   | 6    | 9    | 3
        >>> table2 #table2 has three rows with a = 1
        a    | d    | e
        9    | 1    | 3
        1    | 2    | 4
        1    | 2    | 5
        1    | 10   | 6
        >>> table #table has only one row with a = 1
        a    | b    | c
        9    | 1    | 3
        3    | 2    | 4
        3    | 2    | 5
        1    | 10   | 6