Самый простой способ сделать это - сделать это без foreach l oop и использовать вместо l oop, злоупотребляя тем фактом, что вы можете просто поменять местами индексы столбца и строки.
using System.Text;
static string TransposeRowsToColumns(string rowString)
{
string[] rows = rowString.Split("\n");
StringBuilder columnBuilder = new StringBuilder();
for (int columnIndex = 0; columnIndex < rows[0].Length; columnIndex++)
{
for (int rowIndex = 0; rowIndex < rows.Length; rowIndex++)
{
columnBuilder.Append(rows[rowIndex][columnIndex]);
}
columnBuilder.Append("\n");
}
return columnBuilder.ToString();
}
Обратите внимание, что приведенный выше код основан на том факте, что количество столбцов одинаково.
Если вы хотите сделать это с помощью foreach l oop со списками, вы можно сделать это так:
static string TransposeRowsToColumnsList(string rowString)
{
string[] rows = rowString.Split("\n");
List<List<string>> grid = new List<List<string>>();
int columnIndex = 0;
foreach (string row in rows)
{
grid.Add(new List<string>());
foreach (string column in rows.Select(r => string.Concat(r.Skip(columnIndex).Take(1))))
{
grid[columnIndex].Add(column);
}
columnIndex++;
}
return string.Join("\n", grid.Select(r => string.Concat(r.Select(c => c))));
}
Использование:
string s = "RLLR" + "\n" + "LRRL" + "\n" + "RVVL" + "\n" + "RRRR";
Console.WriteLine(TransposeRowsToColumns(s));
Console.WriteLine(TransposeRowsToColumnsList(s));
Edit
Для изменения ввода по существу разделите столбцы по пробелу вместо того, чтобы предполагать, что они являются одним символом, мы можем изменить второй метод, чтобы он выглядел так:
static string TransposeRowsToColumnsList(string inputString, string columnSplitBy = "", string rowSplitBy = "\n")
{
IEnumerable<IEnumerable<string>> inputGrid = inputString.Split(rowSplitBy).Select(r =>
{
return columnSplitBy == "" ? r.Select(c => new string(c, 1)).ToArray() : r.Split(columnSplitBy);
});
List<List<string>> outputGrid = new List<List<string>>();
int columnIndex = 0;
foreach (IEnumerable<string> row in inputGrid)
{
outputGrid.Add(new List<string>());
foreach (string column in inputGrid.Select(r => string.Concat(r.Skip(columnIndex).Take(1))))
{
outputGrid[columnIndex].Add(column);
}
columnIndex++;
}
return string.Join(rowSplitBy, outputGrid.Select(r => string.Concat(string.Join(columnSplitBy, r.Select(c => c)))));
}
Хотя это очень быстро становится беспорядочным. Для более масштабируемого решения мы можем создать методы расширения, чтобы отделить каждый этап алгоритма и выдать желаемый результат.
Сначала мы определяем интерфейс, который может преобразовывать строку в желаемый тип с реализацией преобразования десятичные дроби:
public interface IStringConverter<T>
{
T ConvertFromString(string input);
}
public class DecimalConverter : IStringConverter<decimal>
{
public decimal ConvertFromString(string input)
{
return decimal.Parse(input);
}
}
Затем мы можем определить все методы расширения, которые нам понадобятся, чтобы транспонировать сетку так, как мы хотим:
public static class CustomExtensions
{
public static IEnumerable<string> ForceSplit(this string input, string pattern)
{
return pattern != string.Empty ? input.Split(pattern) : input.Select(x => x.ToString());
}
public static IEnumerable<IEnumerable<string>> ConvertToGrid(this string input, string columnSplit = "", string rowSplit = "\n")
{
return input.Split(rowSplit).Select(r => r.ForceSplit(columnSplit));
}
public static IEnumerable<IEnumerable<T>> ConvertToGrid<T>(this string input, IStringConverter<T> converter, string columnSplit = "", string rowSplit = "\n")
{
return input.Split(rowSplit).Select(r => r.ForceSplit(columnSplit).Select(converter.ConvertFromString));
}
public static IEnumerable<IEnumerable<T>> PivotGrid<T>(this IEnumerable<IEnumerable<T>> input)
{
return input
.SelectMany(r => r.Select((c, index) => new {column = c, index}))
.GroupBy(i => i.index, i => i.column)
.Select(g => g.ToList());
}
public static string ConvertToString<T>(this IEnumerable<IEnumerable<T>> input, string columnSplit = "", string rowSplit = "\n")
{
return string.Join(rowSplit, input.Select(r => string.Join(columnSplit, r)));
}
}
Примечания:
- Теперь мы конвертируем каждый элемент в ячейку желаемого типа через
ConvertToGrid
- Мы можем перемещать сетку из строк в столбцы (спасибо за этот ответ )
- Затем при желании мы можем преобразовать сетку обратно в строковый формат
Использование
string letters = "RLLR" + "\n" + "LRRL" + "\n" + "RVVL" + "\n" + "RRRR";
string numbers = "25.0 45.7 23" + "\n" + "12.4 67.4 0.0" + "\n" + "0.00 0.00 0.00" + "\n" + "67.8 98.4 0.00";
string transposedLetters = TransposeRowsToColumnsList(letters);
string transposedNumbers = TransposeRowsToColumnsList(numbers, " ");
string pivotedLetters = letters
.ConvertToGrid()
.PivotGrid()
.ConvertToString();
string pivotedNumbers = numbers
.ConvertToGrid(new DecimalConverter(), " ")
.PivotGrid()
.ConvertToString(" ");
Я лично нахожу способ расширения подход более удобен в обслуживании и более расширяемый, но исходный метод легче вызвать.