如何迭代数组/集合/列表中的"之间"项?

Ben*_*ack 4 .net c# string iteration

多年来这个问题一直困扰着我,而且当我有一个更好的解决方案时,我总觉得我想要一个黑客.当你想要做的事,以所有列表中的项目,然后添加一些发生在眼前的问题插图中的那些项目.简而言之,我想:

  • 对列表中的每个项目执行某些操作.
  • 除了列表中的最后一项之外的所有其他内容(实际上,在列表中的项目之间执行某些操作).

例如,假设我有一个名为的类Equation:

public class Equation
{
    public string LeftSide { get; set; }
    public string Operator { get; set; }
    public string RightSide { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

我想迭代一个Equations 列表并返回一个格式化这些项目的字符串; 类似以下内容:

public string FormatEquationList(List<Equation> listEquations)
{
    string output = string.Empty;
    foreach (Equation e in listEquations)
    {
        //format the Equation
        string equation = "(" + e.LeftSide + e.Operator + e.RightSide + ")";

        //format the "inbetween" part
        string inbetween = " and ";

        //concatenate the Equation and "inbetween" part to the output
        output += equation + inbetween;
    }
    return ouput;
}
Run Code Online (Sandbox Code Playgroud)

上面代码的问题是它将包含and在返回的字符串的末尾.我知道我可以一起破解一些代码,用循环代替它foreach,只有当它不是最后一项时才for添加inbetween元素; 但这似乎是一个黑客.

有没有一种标准的方法来处理这类问题?

LBu*_*kin 8

你基本上有一些不同的策略来处理这种问题:

  1. 处理循环外的第一个(或最后一个)项.
  2. 执行工作,然后"撤消"无关的步骤.
  3. 检测您正在处理循环内的第一个或最后一个项目.
  4. 使用更高级别的抽象,可以避免这种情况.

任何这些选项都可以是实现"项目之间"算法风格的合法方式.您选择哪一个取决于以下内容:

  • 你喜欢哪种风格
  • "撤消工作"是多么昂贵
  • 每个"加入"步骤的成本是多少
  • 是否有任何副作用

除此之外.对于字符串的具体情况,我个人更喜欢使用string.Join(),因为我发现它最清楚地说明了意图.此外,在字符串的情况下,如果您不使用string.Join(),您应该尝试使用StringBuilder以避免创建太多临时字符串(字符串在.Net中不可变的结果).

使用字符串连接作为示例,不同的选项分解为示例,如下所示.(为简单起见,假设公式ToString()为:"(" + LeftSide + Operator + RightSide + ")"

public string FormatEquation( IEnumerable<Equation> listEquations )
{
    StringBuilder sb = new StringBuilder();

    if( listEquations.Count > 0 )
        sb.Append( listEquations[0].ToString() );
    for( int i = 1; i < listEquations.Count; i++ )
        sb.Append( " and " + listEquations[i].ToString() );
    return sb.ToString();
}
Run Code Online (Sandbox Code Playgroud)

第二个选项如下:

public string FormatEquation( IEnumerable<Equation> listEquations )
{
    StringBuilder sb = new StringBuilder();
    const string separator = " and ";
    foreach( var eq in listEquations )
        sb.Append( eq.ToString() + separator );
    if( listEquations.Count > 1 )
        sb.Remove( sb.Length, separator.Length );
}
Run Code Online (Sandbox Code Playgroud)

第三个看起来像:

public string FormatEquation( IEnumerable<Equation> listEquations )
{
    StringBuilder sb = new StringBuilder();
    const string separator = " and ";
    foreach( var eq in listEquations )
    {
        sb.Append( eq.ToString() );
        if( index == list.Equations.Count-1 )
            break;
        sb.Append( separator );
    }
}
Run Code Online (Sandbox Code Playgroud)

最后一个选项可以在.NET中使用String.Join或Linq:

public string FormatEquation( IEnumerable<Equation> listEquations )
{
    return string.Join( " and ", listEquations.Select( eq => eq.ToString() ).ToArray() );
}
Run Code Online (Sandbox Code Playgroud)

要么:

public string FormatEquation( IEnumerable<Equation> listEquations ) 
{
    return listEquations.Aggregate((a, b) => a.ToString() + " and " + b.ToString() );
}
Run Code Online (Sandbox Code Playgroud)

就个人而言,我避免使用Aggregate()字符串连接,因为它会产生许多中间的,丢弃的字符串.它也不是将一堆结果"加入"在一起的最明显的方式 - 它主要用于以某种随意,调用者定义的方式计算集合的"标量"结果.


Gre*_*ire 6

您可以使用String.Join().

String.Join(" and ",listEquations.Select(e=>String.Format("({0}{1}{2})",e.LeftSide,e.Operator,e.RightSide).ToArray());
Run Code Online (Sandbox Code Playgroud)