<s> from agate . rows import Row <EOL> from agate import utils <EOL> @ utils . allow_tableset_proxy <EOL> def join ( self , right_table , left_key , right_key = None , inner = False , require_match = False , columns = None ) : <EOL> """<STR_LIT>""" <EOL> if right_key is None : <EOL> right_key = left_key <EOL> right_key_indices = [ ] <EOL> left_key_is_func = hasattr ( left_key , '<STR_LIT>' ) <EOL> left_key_is_sequence = utils . issequence ( left_key ) <EOL> if left_key_is_func : <EOL> left_data = [ left_key ( row ) for row in self . _rows ] <EOL> elif left_key_is_sequence : <EOL> left_columns = [ self . _columns [ key ] for key in left_key ] <EOL> left_data = zip ( * [ column . values ( ) for column in left_columns ] ) <EOL> else : <EOL> left_data = self . _columns [ left_key ] . values ( ) <EOL> right_key_is_func = hasattr ( right_key , '<STR_LIT>' ) <EOL> right_key_is_sequence = utils . issequence ( right_key ) <EOL> if right_key_is_func : <EOL> right_data = [ right_key ( row ) for row in right_table . _rows ] <EOL> elif right_key_is_sequence : <EOL> right_columns = [ right_table . _columns [ key ] for key in right_key ] <EOL> right_data = zip ( * [ column . values ( ) for column in right_columns ] ) <EOL> right_key_indices = [ right_table . _columns . _keys . index ( key ) for key in right_key ] <EOL> else : <EOL> right_column = right_table . _columns [ right_key ] <EOL> right_data = right_column . values ( ) <EOL> right_key_indices = [ right_table . _columns . _keys . index ( right_key ) ] <EOL> column_names = list ( self . _column_names ) <EOL> column_types = list ( self . _column_types ) <EOL> for i , column in enumerate ( right_table . _columns ) : <EOL> name = column . name <EOL> if columns is None and i in right_key_indices : <EOL> continue <EOL> if columns is not None and name not in columns : <EOL> continue <EOL> if name in self . column_names : <EOL> column_names . append ( '<STR_LIT>' % name ) <EOL> else : <EOL> column_names . append ( name ) <EOL> column_types . append ( column . data_type ) <EOL> if columns is not None : <EOL> right_table = right_table . select ( [ n for n in right_table . _column_names if n in columns ] ) <EOL> right_hash = { } <EOL> for i , value in enumerate ( right_data ) : <EOL> if value not in right_hash : <EOL> right_hash [ value ] = [ ] <EOL> right_hash [ value ] . append ( right_table . _rows [ i ] ) <EOL> rows = [ ] <EOL> if self . _row_names is not None : <EOL> row_names = [ ] <EOL> else : <EOL> row_names = None <EOL> for left_index , left_value in enumerate ( left_data ) : <EOL> matching_rows = right_hash . get ( left_value , None ) <EOL> if require_match and matching_rows is None : <EOL> raise ValueError ( '<STR_LIT>' % left_value ) <EOL> if matching_rows : <EOL> for right_row in matching_rows : <EOL> new_row = list ( self . _rows [ left_index ] ) <EOL> for k , v in enumerate ( right_row ) : <EOL> if columns is None and k in right_key_indices : <EOL> continue <EOL> new_row . append ( v ) <EOL> rows . append ( Row ( new_row , column_names ) ) <EOL> if self . _row_names is not None : <EOL> row_names . append ( self . _row_names [ left_index ] ) <EOL> elif not inner : <EOL> new_row = list ( self . _rows [ left_index ] ) <EOL> for k , v in enumerate ( right_table . _column_names ) : <EOL> if columns is None and k in right_key_indices : <EOL> continue <EOL> new_row . append ( None ) <EOL> rows . append ( Row ( new_row , column_names ) ) <EOL> if self . _row_names is not None : <EOL> row_names . append ( self . _row_names [ left_index ] ) <EOL> return self . _fork ( rows , column_names , column_types , row_names = row_names ) </s>
