nodes: 0, module; 1, function_definition; 2, function_name:generate_bins_generic; 3, parameters; 4, block; 5, identifier:values; 6, identifier:binner; 7, identifier:closed; 8, expression_statement; 9, expression_statement; 10, expression_statement; 11, if_statement; 12, comment:# check binner fits data; 13, if_statement; 14, if_statement; 15, expression_statement; 16, expression_statement; 17, comment:# index into values; 18, expression_statement; 19, comment:# bin count; 20, comment:# linear scan, presume nothing about values/binner except that it fits ok; 21, for_statement; 22, return_statement; 23, comment:"""
      Generate bin edge offsets and bin labels for one array using another array
      which has bin edge values. Both arrays must be sorted.
  
      Parameters
      ----------
      values : array of values
      binner : a comparable array of values representing bins into which to bin
          the first array. Note, 'values' end-points must fall within 'binner'
          end-points.
      closed : which end of bin is closed; left (default), right
  
      Returns
      -------
      bins : array of offsets (into 'values' argument) of bins.
          Zero and last edge are excluded in result, so for instance the first
          bin is values[0:bin[0]] and the last is values[bin[-1]:]
      """; 24, assignment; 25, assignment; 26, boolean_operator; 27, block; 28, comparison_operator:values[0] < binner[0]; 29, block; 30, comparison_operator:values[lenidx - 1] > binner[lenbin - 1]; 31, block; 32, assignment; 33, assignment; 34, assignment; 35, identifier:i; 36, call; 37, block; 38, identifier:bins; 39, identifier:lenidx; 40, call; 41, identifier:lenbin; 42, call; 43, comparison_operator:lenidx <= 0; 44, comparison_operator:lenbin <= 0; 45, raise_statement; 46, subscript; 47, subscript; 48, raise_statement; 49, subscript; 50, subscript; 51, raise_statement; 52, identifier:bins; 53, call; 54, identifier:j; 55, integer:0; 56, identifier:bc; 57, integer:0; 58, identifier:range; 59, argument_list; 60, expression_statement; 61, comment:# count values in current bin, advance to next bin; 62, while_statement; 63, expression_statement; 64, expression_statement; 65, identifier:len; 66, argument_list; 67, identifier:len; 68, argument_list; 69, identifier:lenidx; 70, integer:0; 71, identifier:lenbin; 72, integer:0; 73, call; 74, identifier:values; 75, integer:0; 76, identifier:binner; 77, integer:0; 78, call; 79, identifier:values; 80, binary_operator:lenidx - 1; 81, identifier:binner; 82, binary_operator:lenbin - 1; 83, call; 84, attribute; 85, argument_list; 86, integer:0; 87, binary_operator:lenbin - 1; 88, assignment; 89, boolean_operator; 90, block; 91, assignment; 92, augmented_assignment; 93, identifier:values; 94, identifier:binner; 95, identifier:ValueError; 96, argument_list; 97, identifier:ValueError; 98, argument_list; 99, identifier:lenidx; 100, integer:1; 101, identifier:lenbin; 102, integer:1; 103, identifier:ValueError; 104, argument_list; 105, identifier:np; 106, identifier:empty; 107, binary_operator:lenbin - 1; 108, keyword_argument; 109, identifier:lenbin; 110, integer:1; 111, identifier:r_bin; 112, subscript; 113, comparison_operator:j < lenidx; 114, parenthesized_expression; 115, expression_statement; 116, subscript; 117, identifier:j; 118, identifier:bc; 119, integer:1; 120, string:"Invalid length for values or for binner"; 121, string:"Values falls before first bin"; 122, string:"Values falls after last bin"; 123, identifier:lenbin; 124, integer:1; 125, identifier:dtype; 126, attribute; 127, identifier:binner; 128, binary_operator:i + 1; 129, identifier:j; 130, identifier:lenidx; 131, boolean_operator; 132, augmented_assignment; 133, identifier:bins; 134, identifier:bc; 135, identifier:np; 136, identifier:int64; 137, identifier:i; 138, integer:1; 139, comparison_operator:values[j] < r_bin; 140, parenthesized_expression; 141, identifier:j; 142, integer:1; 143, subscript; 144, identifier:r_bin; 145, boolean_operator; 146, identifier:values; 147, identifier:j; 148, comparison_operator:closed == 'right'; 149, comparison_operator:values[j] == r_bin; 150, identifier:closed; 151, string; 152, subscript; 153, identifier:r_bin; 154, string_content:right; 155, identifier:values; 156, identifier:j
code: def generate_bins_generic(values, binner, closed):
      """
      Generate bin edge offsets and bin labels for one array using another array
      which has bin edge values. Both arrays must be sorted.
  
      Parameters
      ----------
      values : array of values
      binner : a comparable array of values representing bins into which to bin
          the first array. Note, 'values' end-points must fall within 'binner'
          end-points.
      closed : which end of bin is closed; left (default), right
  
      Returns
      -------
      bins : array of offsets (into 'values' argument) of bins.
          Zero and last edge are excluded in result, so for instance the first
          bin is values[0:bin[0]] and the last is values[bin[-1]:]
      """
      lenidx = len(values)
      lenbin = len(binner)
  
      if lenidx <= 0 or lenbin <= 0:
          raise ValueError("Invalid length for values or for binner")
  
      # check binner fits data
      if values[0] < binner[0]:
          raise ValueError("Values falls before first bin")
  
      if values[lenidx - 1] > binner[lenbin - 1]:
          raise ValueError("Values falls after last bin")
  
      bins = np.empty(lenbin - 1, dtype=np.int64)
  
      j = 0  # index into values
      bc = 0  # bin count
  
      # linear scan, presume nothing about values/binner except that it fits ok
      for i in range(0, lenbin - 1):
          r_bin = binner[i + 1]
  
          # count values in current bin, advance to next bin
          while j < lenidx and (values[j] < r_bin or
                                (closed == 'right' and values[j] == r_bin)):
              j += 1
  
          bins[bc] = j
          bc += 1
  
      return bins