Repository: tensorflow
Issue: Order of tensorflow.Dataset.concatenate operations
Labels: type:feature,comp:data,type:docs-feature,TF 2.11

<details><summary>Click to expand!</summary> 
 
 ### Issue Type

Documentation Feature Request

### Have you reproduced the bug with TF nightly?

No

### Source

binary

### Tensorflow Version

2.11.0

### Custom Code

No

### OS Platform and Distribution

Linux Ubuntu 20.04

### Mobile device

_No response_

### Python version

3.9.7

### Bazel version

_No response_

### GCC/Compiler version

9.4.9

### CUDA/cuDNN version

_No response_

### GPU model and memory

NVIDIA RTX A4000 15.74GiB

### Current Behaviour?

If I have a long list of datasets that I wish to concatenate, it matters whether I concatenate them pairwise with heavy left-hand sides or heavy right-hand sides.  I would like to see this in the documentation so that others don't have to learn this on their own.  (Additionally, a static tf.Dataset.concatenate_from_list function that does the right thing for the user would be nice.)  Specifically, for my large list of datasets that contain large amounts of image data that are read from disk via py_functions, batched, and prefetched, the following code snippets give different performances.  `concatenate_by_appending` causes the process to be killed, likely due to an out-of-memory condition.  In contrast, `concatenate_by_prepending` and `concatenate_by_splitting` work well.  I suspect that if I used an aggressive form of `shuffle` then only `concatenate_by_splitting` would work well.

I should clarify it is not the creation of the `concatenate_by_appending` dataset that causes the process to be killed.  The process is killed only once I attempt to `predict` using the combined dataset.  The pre-pending approach is right-heavy for each concatenation operation, and the left-most dataset can be found immediately, as the left branch of the top-most concatenation.  In contrast, the appending approach is left-heavy for each concatenation operation, requires descending through all concatenations to find the left-most dataset, and causes the process to be killed, likely due to resource exhaustion, specifically likely an out-of-memory condition.  At least I think that is what is happening.
### Standalone code to reproduce the issue

```python
def concatenate_by_prepending(dataset_list):
    response = None
    # Note: list traversal is reversed
    for dataset in reversed(dataset_list):
        if response is None:
            response = dataset
        else:
            # Note: Right-heavy concatenation
            response = dataset.concatenate(response)
    return response

def concatenate_by_appending(dataset_list):
    response = None
    # Note: list traversal is forward
    for dataset in dataset_list:
        if response is None:
            response = dataset
        else:
            # Note: Left-heavy concatenation
            response = response.concatenate(dataset)
    return response

def concatenate_by_splitting(dataset_list):
    # Note: recursive, rather than list traversing
    length = len(dataset_list)
    if length == 1:
        return dataset_list[0]
    if length > 1:
        # Note: Left and right are of roughly equal size
        return concatenate_by_splitting(dataset_list[0 : length // 2]).concatenate(
            concatenate_by_splitting(dataset_list[length // 2 : length])
        )
    return None
```


### Relevant log output

_No response_</details>