如何在foreach嵌套循环C#中使用列表将字符串的行转换为列 [英] How to transpose rows of string into columns using lists in a foreach nested loop C#

查看:42
本文介绍了如何在foreach嵌套循环C#中使用列表将字符串的行转换为列的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个结构如下的字符串:

I have a string structured as following:

RLLR
LRRL
RVVL
RRRR

// string was made like:
string s = "RLLR" + "\n" + "LRRL" + "\n" + "RVVL" + "\n" + "RRRR"; 

我想对这个表做的是将行转为列,所以它看起来像:

What I want to do to this table is transpose the rows to columns, so it will look like:

RLRR
LRVR
LRVR
RLLR

到目前为止我所做的是将字符串转换为数组,这样我就可以像这样循环遍历它:

What I've done so far is that I converted the string to an array so i can loop through it like so:

List<string> line_value = new List<string>();//list for one line of array
List<string> single_value = new List<string>();//list for individual characters for those lines

string s = "RLLR" + "\n" + "LRRL" + "\n" + "RVVL" + "\n" + "RRRR"; 
string[] strarray = new string[]{""};
strarray = s.Split("\n");
int z = 0;
foreach(string line in strarray)
{
     line_value.Add(line);//adds single line to list

      foreach(char letter in line_value[z])
      {
        Console.WriteLine(letter.ToString());
        single_value.Add(letter.ToString());
      }
   z++;
}  

通过这样做,我可以像这样打印出字符串,其中一切都是水平的:

By doing it this way, I can print out the string like so, where everything is horizontal:

R
L
L
R
L
R
R
.
.
.
R

但是,我仍然对如何建立字符串感到困惑,因此它会像这样转置:

However, I am still kind of confused on how to establish the string so it will be transposed like so:

RLRR
LRVR
LRVR
RLLR

我将如何转置字符串以便将行变成列?

How would I transpose the string so it would turn the rows into columns?

推荐答案

这样做的简单方法是不使用 foreach 循环,并滥用 for 循环这一事实,即您可以简单地交换列和行索引.

The easy way of doing this is to do it without a foreach loop, and use a for loop abusing the fact that you can simply swap the column and row indexes.

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 循环来执行此操作,您可以这样做:

If you're wanting to do this with a foreach loop with lists, you can do it like:

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));

编辑

为了将输入更改为基本上按空格拆分列而不是假设它们是单个字符,我们可以将第二种方法更改为:

For changing the input to essentially split the columns by space instead of the assumption that they're a single character, we can alter the second method to be like:

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)))));
}

虽然这很快就会变得混乱.对于更具扩展性的解决方案,我们可以创建扩展方法来分离算法的每个阶段并吐出所需的结果.

Although this gets messy really quick. For a more scalable solution, we can create extension methods to separate each stage of the algorithm and spit out the desired result.

我们首先定义一个可以将字符串转换为所需类型的接口,并带有转换小数的实现:

We first define an interface that can convert a string to a desired type with an implementation of converting decimals:

public interface IStringConverter<T>
{
    T ConvertFromString(string input);
}

public class DecimalConverter : IStringConverter<decimal>
{
    public decimal ConvertFromString(string input)
    {
        return decimal.Parse(input);
    }
}

接下来,我们可以定义将网格转置为我们想要的方式所需的所有扩展方法:

Next we can define all the extension methods we'll need to transpose the grid to the way we want:

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(" ");

我个人认为扩展方法的方法更易于维护和扩展,但原始方法更易于调用.

I personally find the extension method approach more maintainable and more extensible, but the original method is easier to call.

这篇关于如何在foreach嵌套循环C#中使用列表将字符串的行转换为列的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆