code: def find_best_matching_array(
      base_arr, model_arr, same_size_use_model_arr_diff_thresh=None
  ):
      """
      Find an array <best_arr> based on <base_arr> that fits best to <model_arr> if their sizes differ.
      <best_arr> will have the same size as <model_arr> and either has surplus elements removed (if <base_arr> is
      bigger than <model_arr>) or missing elements added from <model_arr> (if <base_arr> is smaller than <model_arr>).
  
      Returns the best fitting array and the summed difference of this array and <model_arr>.
  
      It uses a brute force method so this is slow for big arrays.
  
      Example:
  
      values = [
          [0,  10,     30,         40],
          [0,  11,     29,         42],
          [10, 21, 25, 39,         52],
          [0,   9, 15, 29, 32,     41],
          [0,  10,     29, 35, 36, 40],
          [0,   9,                 41],
          [0,          33,           ],
      ]
  
      model = np.array(values[0])  # first row is the "model" -> we know that this is correct
      for row in values[1:]:
          row = np.array(row)
          print(row)
          corrected_row, diffsum = find_best_matching_array(row, model)
          print(corrected_row)
          print(diffsum)
          print()
  
      Output:
          [ 0 11 29 42]
          [ 0 11 29 42]
          4
  
          [10 21 25 39 52]
          [10 21 39 52]
          4
  
          [ 0  9 15 29 32 41]
          [ 0  9 29 41]
          3
  
          [ 0 10 29 35 36 40]
          [ 0 10 29 40]
          1
  
          [ 0  9 41]
          [ 0  9 30 41]
          2
  
          [ 0 33]
          [ 0 10 33 40]
          3
      """
      if type(base_arr) is not np.ndarray:
          raise TypeError("base_arr must be NumPy array")
      if type(model_arr) is not np.ndarray:
          raise TypeError("model_arr must be NumPy array")
  
      if len(base_arr) < 1:
          raise ValueError("base_arr length must be > 0")
      if len(model_arr) < 1:
          raise ValueError("model_arr length must be > 0")
  
      amount_diff = len(base_arr) - len(model_arr)
  
      if amount_diff > 0:  # too many values in base_arr
          # go through all possible combinations of surplus elements in the base_arr and
          # measure the match difference and save it to "candidates"
          del_indices_combi = itertools.combinations(
              range(len(base_arr)), amount_diff
          )
          candidates = []
          for del_ind in del_indices_combi:
              candidate_arr = np.delete(base_arr, del_ind)
              # model_arr is normalized -> add first value as offset
              center_medians_w_offset = model_arr + candidate_arr[0]
              diff = array_match_difference_1d(
                  candidate_arr, center_medians_w_offset
              )
              candidates.append((candidate_arr, diff))
  
          best_arr, diff = sorted(candidates, key=lambda x: x[1])[0]
      elif amount_diff < 0:  # too few values in base_arr
          # this time, reduce the model_arr so that it fits the number of values in base_arr
          # i.e. we find the best candidate of all adjusted model_arr first
          del_indices_combi = itertools.combinations(
              range(len(model_arr)), -amount_diff
          )
          candidates = []
          for del_ind in del_indices_combi:
              candidate_arr = np.delete(model_arr, del_ind)
              # model_arr is normalized -> add first value as offset
              diff = array_match_difference_1d(
                  candidate_arr + base_arr[0], base_arr
              )
              candidates.append((del_ind, diff))
  
          add_ind, _ = sorted(candidates, key=lambda x: x[1])[0]
          model_arr_w_offset = model_arr + base_arr[0]
  
          # take the missing values from best_model_arr
          best_arr = fill_array_a_with_values_from_b(
              base_arr, model_arr_w_offset, add_ind
          )
          diff = array_match_difference_1d(best_arr, model_arr_w_offset)
      else:  # number of values matches
          diff = array_match_difference_1d(
              base_arr, model_arr + base_arr[0]
          )
          best_arr = base_arr.copy()
  
      if (
          same_size_use_model_arr_diff_thresh is not None
          and diff > same_size_use_model_arr_diff_thresh
      ):
          best_arr = model_arr + base_arr[0]
          diff = 0  # can only be zero
  
      return best_arr, diff
  
file_path: pdftabextract/pdftabextract/clustering.py
imports: import itertools
  import numpy
  from scipy.stats import chisquare
  from pdftabextract import logger
  from pdftabextract.common import fill_array_a_with_values_from_b, sorted_by_attr, flatten_list, update_text_dict_dim, DIRECTION_HORIZONTAL, DIRECTION_VERTICAL
label_desc: Use image node_id 11 for calling a global function with example usage: find_best_matching_array(base_arr, model_arr, same_size_use_model_arr_diff_thresh) and returns: best_arr,  diff