code: def concat(
      objs: List[Union[DataFrame, Series]],
      axis: Axis = 0,
      join: str = "outer",
      ignore_index: bool = False,
      sort: bool = False,
  ) -> Union[Series, DataFrame]:
      """
      Concatenate pandas-on-Spark objects along a particular axis with optional set logic
      along the other axes.
  
      Parameters
      ----------
      objs : a sequence of Series or DataFrame
          Any None objects will be dropped silently unless
          they are all None in which case a ValueError will be raised
      axis : {0/'index', 1/'columns'}, default 0
          The axis to concatenate along.
      join : {'inner', 'outer'}, default 'outer'
          How to handle indexes on other axis (or axes).
      ignore_index : bool, default False
          If True, do not use the index values along the concatenation axis. The
          resulting axis will be labeled 0, ..., n - 1. This is useful if you are
          concatenating objects where the concatenation axis does not have
          meaningful indexing information. Note the index values on the other
          axes are still respected in the join.
      sort : bool, default False
          Sort non-concatenation axis if it is not already aligned.
  
      Returns
      -------
      object, type of objs
          When concatenating all ``Series`` along the index (axis=0), a
          ``Series`` is returned. When ``objs`` contains at least one
          ``DataFrame``, a ``DataFrame`` is returned. When concatenating along
          the columns (axis=1), a ``DataFrame`` is returned.
  
      See Also
      --------
      DataFrame.join : Join DataFrames using indexes.
      DataFrame.merge : Merge DataFrames by indexes or columns.
  
      Examples
      --------
      >>> from pyspark.pandas.config import set_option, reset_option
      >>> set_option("compute.ops_on_diff_frames", True)
  
      Combine two ``Series``.
  
      >>> s1 = ps.Series(['a', 'b'])
      >>> s2 = ps.Series(['c', 'd'])
      >>> ps.concat([s1, s2])
      0    a
      1    b
      0    c
      1    d
      dtype: object
  
      Clear the existing index and reset it in the result
      by setting the ``ignore_index`` option to ``True``.
  
      >>> ps.concat([s1, s2], ignore_index=True)
      0    a
      1    b
      2    c
      3    d
      dtype: object
  
      Combine two ``DataFrame`` objects with identical columns.
  
      >>> df1 = ps.DataFrame([['a', 1], ['b', 2]],
      ...                    columns=['letter', 'number'])
      >>> df1
        letter  number
      0      a       1
      1      b       2
      >>> df2 = ps.DataFrame([['c', 3], ['d', 4]],
      ...                    columns=['letter', 'number'])
      >>> df2
        letter  number
      0      c       3
      1      d       4
  
      >>> ps.concat([df1, df2])
        letter  number
      0      a       1
      1      b       2
      0      c       3
      1      d       4
  
      Combine ``DataFrame`` and ``Series`` objects with different columns.
  
      >>> ps.concat([df2, s1])
        letter  number     0
      0      c     3.0  None
      1      d     4.0  None
      0   None     NaN     a
      1   None     NaN     b
  
      Combine ``DataFrame`` objects with overlapping columns
      and return everything. Columns outside the intersection will
      be filled with ``None`` values.
  
      >>> df3 = ps.DataFrame([['c', 3, 'cat'], ['d', 4, 'dog']],
      ...                    columns=['letter', 'number', 'animal'])
      >>> df3
        letter  number animal
      0      c       3    cat
      1      d       4    dog
  
      >>> ps.concat([df1, df3])
        letter  number animal
      0      a       1   None
      1      b       2   None
      0      c       3    cat
      1      d       4    dog
  
      Sort the columns.
  
      >>> ps.concat([df1, df3], sort=True)
        animal letter  number
      0   None      a       1
      1   None      b       2
      0    cat      c       3
      1    dog      d       4
  
      Combine ``DataFrame`` objects with overlapping columns
      and return only those that are shared by passing ``inner`` to
      the ``join`` keyword argument.
  
      >>> ps.concat([df1, df3], join="inner")
        letter  number
      0      a       1
      1      b       2
      0      c       3
      1      d       4
  
      >>> df4 = ps.DataFrame([['bird', 'polly'], ['monkey', 'george']],
      ...                    columns=['animal', 'name'])
  
      Combine with column axis.
  
      >>> ps.concat([df1, df4], axis=1)
        letter  number  animal    name
      0      a       1    bird   polly
      1      b       2  monkey  george
  
      >>> reset_option("compute.ops_on_diff_frames")
      """
      if isinstance(objs, (DataFrame, IndexOpsMixin)) or not isinstance(
          objs, Iterable
      ):  # TODO: support dict
          raise TypeError(
              "first argument must be an iterable of pandas-on-Spark "
              "objects, you passed an object of type "
              '"{name}"'.format(name=type(objs).__name__)
          )
  
      if len(cast(Sized, objs)) == 0:
          raise ValueError("No objects to concatenate")
      objs = list(filter(lambda obj: obj is not None, objs))
      if len(objs) == 0:
          raise ValueError("All objects passed were None")
  
      for obj in objs:
          if not isinstance(obj, (Series, DataFrame)):
              raise TypeError(
                  "cannot concatenate object of type "
                  "'{name}"
                  "; only ps.Series "
                  "and ps.DataFrame are valid".format(
                      name=type(objs).__name__
                  )
              )
  
      if join not in ["inner", "outer"]:
          raise ValueError(
              "Only can inner (intersect) or outer (union) join the other axis."
          )
  
      if all([obj.empty for obj in objs]):
          warnings.warn(
              "The behavior of array concatenation with empty entries is "
              "deprecated. In a future version, this will no longer exclude "
              "empty items when determining the result dtype. "
              "To retain the old behavior, exclude the empty entries before "
              "the concat operation.",
              FutureWarning,
          )
  
      axis = validate_axis(axis)
      psdf: DataFrame
      if axis == 1:
          psdfs: List[DataFrame] = [
              obj.to_frame() if isinstance(obj, Series) else obj
              for obj in objs
          ]
  
          level: int = min(
              psdf._internal.column_labels_level for psdf in psdfs
          )
          psdfs = [
              DataFrame._index_normalized_frame(level, psdf)
              if psdf._internal.column_labels_level > level
              else psdf
              for psdf in psdfs
          ]
  
          concat_psdf = psdfs[0]
          column_labels: List[
              Label
          ] = concat_psdf._internal.column_labels.copy()
  
          psdfs_not_same_anchor = []
          for psdf in psdfs[1:]:
              duplicated = [
                  label
                  for label in psdf._internal.column_labels
                  if label in column_labels
              ]
              if len(duplicated) > 0:
                  pretty_names = [
                      name_like_string(label) for label in duplicated
                  ]
                  raise ValueError(
                      "Labels have to be unique; however, got duplicated labels %s."
                      % pretty_names
                  )
              column_labels.extend(psdf._internal.column_labels)
  
              if same_anchor(concat_psdf, psdf):
                  concat_psdf = DataFrame(
                      concat_psdf._internal.with_new_columns(
                          [
                              concat_psdf._psser_for(label)
                              for label in concat_psdf._internal.column_labels
                          ]
                          + [
                              psdf._psser_for(label)
                              for label in psdf._internal.column_labels
                          ]
                      )
                  )
              else:
                  psdfs_not_same_anchor.append(psdf)
  
          if len(psdfs_not_same_anchor) > 0:
  
              @no_type_check
              def resolve_func(
                  psdf, this_column_labels, that_column_labels
              ):
                  raise AssertionError("This should not happen.")
  
              for psdf in psdfs_not_same_anchor:
                  if join == "inner":
                      concat_psdf = align_diff_frames(
                          resolve_func,
                          concat_psdf,
                          psdf,
                          fillna=False,
                          how="inner",
                      )
                  elif join == "outer":
                      concat_psdf = align_diff_frames(
                          resolve_func,
                          concat_psdf,
                          psdf,
                          fillna=False,
                          how="full",
                      )
  
              concat_psdf = concat_psdf[column_labels]
  
          if ignore_index:
              concat_psdf.columns = list(  # type: ignore[assignment]
                  map(str, _range(len(concat_psdf.columns)))
              )
  
          if sort:
              concat_psdf = concat_psdf.sort_index()
  
          columns = concat_psdf.columns
          if isinstance(columns, pd.MultiIndex):
              concat_psdf = concat_psdf.rename_axis(
                  [None] * columns.nlevels, axis="columns"
              )
  
          return concat_psdf
  
      # Series, Series ...
      # We should return Series if objects are all Series.
      should_return_series = all(
          map(lambda obj: isinstance(obj, Series), objs)
      )
  
      # DataFrame, Series ... & Series, Series ...
      # In this case, we should return DataFrame.
      new_objs: List[DataFrame] = []
      num_series = 0
      series_names = set()
      for obj in objs:
          if isinstance(obj, Series):
              num_series += 1
              series_names.add(obj.name)
              new_objs.append(obj.to_frame(DEFAULT_SERIES_NAME))
          else:
              assert isinstance(obj, DataFrame)
              new_objs.append(obj)
  
      column_labels_levels: Set[int] = set(
          obj._internal.column_labels_level for obj in new_objs
      )
      if len(column_labels_levels) != 1:
          raise ValueError(
              "MultiIndex columns should have the same levels"
          )
  
      # DataFrame, DataFrame, ...
      # All Series are converted into DataFrame and then compute concat.
      if not ignore_index:
          indices_of_psdfs = [psdf.index for psdf in new_objs]
          index_of_first_psdf = indices_of_psdfs[0]
          for index_of_psdf in indices_of_psdfs:
              if index_of_first_psdf.names != index_of_psdf.names:
                  raise ValueError(
                      "Index type and names should be same in the objects to concatenate. "
                      "You passed different indices "
                      "{index_of_first_psdf} and {index_of_psdf}".format(
                          index_of_first_psdf=index_of_first_psdf.names,
                          index_of_psdf=index_of_psdf.names,
                      )
                  )
  
      column_labels_of_psdfs = [
          psdf._internal.column_labels for psdf in new_objs
      ]
      index_names_of_psdfs: List[List[Optional[Label]]]
      if ignore_index:
          index_names_of_psdfs = [[] for _ in new_objs]
      else:
          index_names_of_psdfs = [
              psdf._internal.index_names for psdf in new_objs
          ]
  
      if all(
          name == index_names_of_psdfs[0]
          for name in index_names_of_psdfs
      ) and all(
          idx == column_labels_of_psdfs[0]
          for idx in column_labels_of_psdfs
      ):
          # If all columns are in the same order and values, use it.
          psdfs = new_objs
      else:
          if join == "inner":
              interested_columns = set.intersection(
                  *map(lambda x: set(x), column_labels_of_psdfs)
              )
              # Keep the column order with its firsts DataFrame.
              merged_columns = [
                  label
                  for label in column_labels_of_psdfs[0]
                  if label in interested_columns
              ]
  
              # If sort is True, sort to follow pandas 1.4+ behavior.
              if sort:
                  # FIXME: better ordering
                  merged_columns = sorted(
                      merged_columns, key=name_like_string
                  )
  
              psdfs = [psdf[merged_columns] for psdf in new_objs]
          elif join == "outer":
              merged_columns = []
              for labels in column_labels_of_psdfs:
                  merged_columns.extend(
                      label
                      for label in labels
                      if label not in merged_columns
                  )
  
              assert len(merged_columns) > 0
  
              # If sort is True, always sort
              if sort:
                  # FIXME: better ordering
                  merged_columns = sorted(
                      merged_columns, key=name_like_string
                  )
  
              psdfs = []
              for psdf in new_objs:
                  columns_to_add = list(
                      set(merged_columns)
                      - set(psdf._internal.column_labels)
                  )
  
                  # TODO: NaN and None difference for missing values. pandas seems to be filling NaN.
                  sdf = psdf._internal.resolved_copy.spark_frame
                  for label in columns_to_add:
                      sdf = sdf.withColumn(
                          name_like_string(label), F.lit(None)
                      )
  
                  data_columns = (
                      psdf._internal.data_spark_column_names
                      + [
                          name_like_string(label)
                          for label in columns_to_add
                      ]
                  )
                  psdf = DataFrame(
                      psdf._internal.copy(
                          spark_frame=sdf,
                          index_spark_columns=[
                              scol_for(sdf, col)
                              for col in psdf._internal.index_spark_column_names
                          ],
                          column_labels=(
                              psdf._internal.column_labels
                              + columns_to_add
                          ),
                          data_spark_columns=[
                              scol_for(sdf, col) for col in data_columns
                          ],
                          data_fields=(
                              psdf._internal.data_fields
                              + ([None] * len(columns_to_add))
                          ),
                      )
                  )
  
                  psdfs.append(psdf[merged_columns])
  
      if ignore_index:
          sdfs = [
              psdf._internal.spark_frame.select(
                  psdf._internal.data_spark_columns
              )
              for psdf in psdfs
          ]
      else:
          sdfs = [
              psdf._internal.spark_frame.select(
                  psdf._internal.index_spark_columns
                  + psdf._internal.data_spark_columns
              )
              for psdf in psdfs
          ]
      concatenated = reduce(lambda x, y: x.union(y), sdfs)
  
      if ignore_index:
          index_spark_column_names = []
          index_names = []
          index_fields = []
      else:
          index_spark_column_names = psdfs[
              0
          ]._internal.index_spark_column_names
          index_names = psdfs[0]._internal.index_names
          index_fields = psdfs[0]._internal.index_fields
  
      result_psdf: DataFrame = DataFrame(
          psdfs[0]._internal.copy(
              spark_frame=concatenated,
              index_spark_columns=[
                  scol_for(concatenated, col)
                  for col in index_spark_column_names
              ],
              index_names=index_names,
              index_fields=index_fields,
              data_spark_columns=[
                  scol_for(concatenated, col)
                  for col in psdfs[0]._internal.data_spark_column_names
              ],
              data_fields=None,  # TODO: dtypes?
          )
      )
  
      if should_return_series:
          # If all input were Series, we should return Series.
          if len(series_names) == 1:
              name = series_names.pop()
          else:
              name = None
          return first_series(result_psdf).rename(name)
      else:
          return result_psdf
  
imports: from typing import Any, Callable, Dict, List, Optional, Set, Sized, Tuple, Type, Union, cast, no_type_check
  from collections.abc import Iterable
  from datetime import tzinfo
  from functools import reduce
  from io import BytesIO
  import json
  import warnings
  import numpy
  import pandas
  from pandas.api.types import is_datetime64_dtype, is_list_like
  from pandas.tseries.offsets import DateOffset
  import pyarrow
  import pyarrow.parquet
  from pyspark.sql import functions, Column
  from pyspark.sql.functions import pandas_udf
  from pyspark.sql.types import ByteType, ShortType, IntegerType, LongType, FloatType, DoubleType, BooleanType, TimestampType, TimestampNTZType, DecimalType, StringType, DateType, StructType, DataType
  from pyspark.sql.dataframe import DataFrame
  from pyspark import pandas
  from pyspark.pandas._typing import Axis, Dtype, Label, Name
  from pyspark.pandas.base import IndexOpsMixin
  from pyspark.pandas.utils import align_diff_frames, default_session, is_name_like_tuple, is_name_like_value, name_like_string, same_anchor, scol_for, validate_axis, log_advice
  from pyspark.pandas.frame import DataFrame, _reduce_spark_multi
  from pyspark.pandas.internal import InternalFrame, DEFAULT_SERIES_NAME, HIDDEN_COLUMNS, SPARK_INDEX_NAME_FORMAT
  from pyspark.pandas.series import Series, first_series
  from pyspark.pandas.spark.utils import as_nullable_spark_type, force_decimal_precision_scale
  from pyspark.pandas.indexes import Index, DatetimeIndex, TimedeltaIndex
  from pyspark.pandas.indexes.multi import MultiIndex
  from pyspark.sql.utils import get_column_class
label_desc: Use image node_id 20 for calling a global function with example usage: concat(objs, axis, join, ignore_index, sort) and returns: concat_psdf, first_series, result_psdf