# Transpose File
**Difficulty:** MEDIUM
[External](https://leetcode.com/problems/transpose-file)
Canonical: https://scaleengineer.com/dsa/problems/transpose-file
---
## Problem
Given a text file `file.txt`, transpose its content.

You may assume that each row has the same number of columns, and each field is separated by the `' '` character.

**Example:**

If `file.txt` has the following content:

name age
alice 21
ryan 30

Output the following:

name alice ryan
age 21 30

# Approaches
## Brute-Force In-Memory Transposition
This approach involves reading the entire file into a 2D array or list of lists. A second 2D array of transposed dimensions is then created. The data is copied from the original matrix to the transposed matrix by swapping the row and column indices. Finally, the transposed matrix is printed to the standard output.
**Time:** O(R * C) · **Space:** O(R * C)
**Pros:** Very straightforward and easy to reason about.; Separates the logic of data loading, transformation, and presentation.
**Cons:** Highest memory usage as it stores two copies of the data (in different layouts).; Not suitable for very large files that cannot fit into memory twice.
### Explanation
This approach is the most direct translation of the matrix transpose operation. It first loads the entire file content into an in-memory 2D data structure, like a `List<String[]>`. This represents the original matrix.

Once the data is loaded, it determines the dimensions (rows `R` and columns `C`). It then allocates a second 2D array with swapped dimensions (`C x R`). A nested loop iterates through the new dimensions, and for each cell `(i, j)` in the transposed matrix, it fetches the corresponding element from the original matrix at `(j, i)`.

After the transposed matrix is fully populated, another loop iterates through it to print each row to the console, with elements separated by spaces.

```java
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

public class Solution {
    public void transposeFile(String filePath) throws IOException {
        List<String[]> lines = new ArrayList<>();
        try (BufferedReader reader = new BufferedReader(new FileReader(filePath))) {
            String line;
            while ((line = reader.readLine()) != null) {
                lines.add(line.split(" "));
            }
        }

        if (lines.isEmpty()) {
            return;
        }

        int rows = lines.size();
        int cols = lines.get(0).length;

        String[][] transposed = new String[cols][rows];

        for (int i = 0; i < cols; i++) {
            for (int j = 0; j < rows; j++) {
                transposed[i][j] = lines.get(j)[i];
            }
        }

        for (int i = 0; i < cols; i++) {
            System.out.println(String.join(" ", transposed[i]));
        }
    }
}
```
### Algorithm
- Read all lines from the file.
- Split each line into words and store them in a 2D list, `originalData`.
- Determine dimensions: `rows = originalData.size()` and `cols = originalData.get(0).size()`.
- Create a new 2D array, `transposedData`, of size `cols x rows`.
- Populate `transposedData` using the formula `transposedData[i][j] = originalData.get(j).get(i)`.
- Print each row of `transposedData`.

## Optimized In-Memory Transposition with Direct Printing
This approach improves on the brute-force method by reducing memory usage. It still reads the entire file into a 2D data structure. However, instead of creating a second, separate transposed matrix, it directly constructs and prints each transposed row. It iterates through the column indices of the original data, and for each column, it builds the corresponding output row by collecting elements from each input row.
**Time:** O(R * C) · **Space:** O(R * C)
**Pros:** More memory-efficient than the brute-force approach as it avoids creating a second large 2D array.; Still relatively simple to implement.
**Cons:** Still requires storing the entire file content in memory, making it unsuitable for very large files.
### Explanation
This method improves upon the brute-force approach by eliminating the need for a second 2D array to store the transposed data. It still begins by loading the entire file into a 2D list in memory.

However, instead of building a complete transposed matrix, it generates the output line by line. The algorithm iterates through the column indices of the original data. For each column index `i`, it constructs the `i`-th row of the output. It does this by iterating through all the rows of the in-memory data and picking out the element at column `i` from each one. These elements are collected into a `StringBuilder`, which is then printed before moving to the next column. This reduces peak memory usage by not holding both the original and transposed matrices simultaneously.

```java
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

public class Solution {
    public void transposeFile(String filePath) throws IOException {
        List<String[]> lines = new ArrayList<>();
        try (BufferedReader reader = new BufferedReader(new FileReader(filePath))) {
            String line;
            while ((line = reader.readLine()) != null) {
                lines.add(line.split(" "));
            }
        }

        if (lines.isEmpty()) {
            return;
        }

        int rows = lines.size();
        int cols = lines.get(0).length;

        for (int i = 0; i < cols; i++) {
            StringBuilder outputLine = new StringBuilder();
            for (int j = 0; j < rows; j++) {
                outputLine.append(lines.get(j)[i]);
                if (j < rows - 1) {
                    outputLine.append(" ");
                }
            }
            System.out.println(outputLine.toString());
        }
    }
}
```
### Algorithm
- Read all lines from the file.
- Split each line into words and store them in a 2D list, `originalData`.
- Determine dimensions: `rows = originalData.size()` and `cols = originalData.get(0).size()`.
- Iterate from `i = 0` to `cols - 1` (for each output row).
- Inside the loop, create a `StringBuilder`.
- Start an inner loop from `j = 0` to `rows - 1` (for each input row).
- Append the element `originalData.get(j).get(i)` to the `StringBuilder`.
- After the inner loop, print the `StringBuilder`'s content.

## Single-Pass Incremental Output Build
This is the most memory-efficient of the in-memory approaches. It mimics the logic of common `awk` solutions. It reads the file line by line only once. It maintains an array of `StringBuilder`s, where each builder corresponds to a column in the input (and a row in the output). As each line is read, its words are appended to the corresponding `StringBuilder`. This avoids storing the entire file content in a 2D array of strings, instead directly building the final output lines.
**Time:** O(R * C) · **Space:** O(R * C)
**Pros:** Processes the input file in a single pass.; Most memory-efficient in-memory solution due to avoiding intermediate data structures like a 2D array of `String` objects, resulting in lower constant factors for memory usage.
**Cons:** Like all in-memory solutions, it will fail if the file is too large to store its content (or transposed content) in memory.
### Explanation
This approach is the most efficient in terms of memory management and processing flow. It processes the input file in a single pass and builds the transposed output lines incrementally. It avoids creating a complete 2D representation of the input file.

It maintains a list of `StringBuilder`s, where the size of the list is equal to the number of columns in the file. As it reads each line from the file, it splits the line into words and appends each word to the corresponding `StringBuilder` in the list. The first line's words initialize the builders, and subsequent lines' words are appended with a space separator. This way, the final output lines are constructed directly without any intermediate 2D data structures, leading to lower object overhead compared to other in-memory methods.

```java
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

public class Solution {
    public void transposeFile(String filePath) throws IOException {
        List<StringBuilder> outputLines = new ArrayList<>();
        boolean isFirstLine = true;

        try (BufferedReader reader = new BufferedReader(new FileReader(filePath))) {
            String line;
            while ((line = reader.readLine()) != null) {
                String[] words = line.split(" ");
                if (isFirstLine) {
                    for (String word : words) {
                        outputLines.add(new StringBuilder(word));
                    }
                    isFirstLine = false;
                } else {
                    for (int i = 0; i < words.length; i++) {
                        outputLines.get(i).append(" ").append(words[i]);
                    }
                }
            }
        }

        for (StringBuilder sb : outputLines) {
            System.out.println(sb.toString());
        }
    }
}
```
### Algorithm
- Initialize an empty list of `StringBuilder`s, `outputBuilders`.
- Read the input file line by line.
- For the first line read, split it into words. For each word, create a new `StringBuilder` in `outputBuilders` and initialize it with the word.
- For each subsequent line, split it into words. For each word at index `i`, append it (with a preceding space) to the `StringBuilder` at `outputBuilders.get(i)`.
- After processing all lines, iterate through `outputBuilders` and print each `StringBuilder`.
