private function filterColumns(array $rows, array $header, array $columnsToDisplay)
    {
        if (empty($columnsToDisplay)) {
            return $rows;
        }

        // The available columns are all the (lower-cased) values and string
        // keys in $header.
        $availableColumns = [];
        foreach ($header as $key => $column) {
            $columnName = is_string($key) ? $key : $column;
            $availableColumns[strtolower($columnName)] = $key;
        }

        // Validate the column names.
        foreach ($columnsToDisplay as &$columnName) {
            $columnNameLowered = strtolower($columnName);
            if (!isset($availableColumns[$columnNameLowered])) {
                throw new InvalidArgumentException(
                    sprintf('Column not found: %s (available columns: %s)', $columnName, implode(', ', array_keys($availableColumns)))
                );
            }
            $columnName = $columnNameLowered;
        }

        // Filter the rows for keys matching those in $availableColumns. If a
        // key doesn't exist in a row, then the cell will be an empty string.
        $newRows = [];
        foreach ($rows as $row) {
            $newRow = [];
            foreach ($columnsToDisplay as $columnNameLowered) {
                $key = $availableColumns[$columnNameLowered];
                $newRow[] = array_key_exists($key, $row) ? $row[$key] : '';
            }
            $newRows[] = $newRow;
        }

        return $newRows;
    }