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

时间:2010-02-09 18:14:44

标签: c# .net string iteration

这个问题多年来一直困扰着我,而且当我有一个更好的解决方案时,我总觉得我想要一个黑客。当您想要对列表中的所有项目执行某些操作然后在之间添加这些项目时,就会出现问题。简而言之,我想:

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

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

public class Equation
{
    public string LeftSide { get; set; }
    public string Operator { get; set; }
    public string RightSide { get; set; }
}

我想迭代一个Equation列表并返回一个将这些项格式化在一起的字符串;如下所示:

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

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

有没有一种标准方法可以解决这类问题?

7 个答案:

答案 0 :(得分:8)

您基本上有一些不同的策略来处理此类问题:

  1. 处理循环外的第一个(或最后一个)项目。
  2. 执行工作,然后“撤消”无关的步骤。
  3. 检测您正在处理循环中的第一个或最后一个项目。
  4. 使用更高级别的抽象,可以避免这种情况。
  5. 这些选项中的任何一个都可以是实现“项目之间”算法风格的合法方式。您选择哪一个取决于:

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

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

    使用字符串连接作为示例,不同的选项分解为示例,如下所示。 (为简单起见,假设公式为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();
    }
    

    第二个选项如下:

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

    第三个看起来像:

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

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

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

    或:

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

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

答案 1 :(得分:6)

您可以使用String.Join()

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

答案 2 :(得分:3)

您可以使用LINQ的Aggregate运算符执行此操作:

public string FormatEquationList(List<Equation> listEquations)
{
    return listEquations.Aggregate((a, b) => 
        "(" + a.LeftSide + a.Operator + a.RightSide + ") and (" + 
              b.LeftSide + b.Operator + b.RightSide + ")");
}

答案 3 :(得分:2)

如果您不想要for循环,则使用带计数器的foreach循环是完全合理的。这就是为什么有多种类型的循环语句。

如果要成对处理项目,请在LINQ的Aggregate运算符处循环。

答案 4 :(得分:2)

我通常在条件之前添加它,并检查它是否是第1项。

public string FormatEquationList(List<Equation> listEquations) 
{ 
    string output = string.Empty;
    foreach (Equation e in listEquations) 
    {
        //use conditional to insert your "between" data:
        output += (output == String.Empty) ? string.Empty : " and "; 

        //format the Equation 
        output += "(" + e.LeftSide + e.Operator + e.RightSide + ")"; 

    } 
    return ouput; 
}

我不得不说我会查看string.Join()函数,对于Linqiness来说就是+1。我的例子是一个传统的解决方案。

答案 5 :(得分:1)

我通常会尝试根据条件为分隔符添加前缀,而不是将它们添加到结尾。

string output = string.Empty;
for (int i = 0; i < 10; i++)
{
   output += output == string.Empty ? i.ToString() : " and " + i.ToString();
}

0和1和2和3以及4和5以及6和7以及8和9

答案 6 :(得分:1)

我喜欢已发布的String.Join方法。

但是当你不使用数组时,这通常是我解决这个问题的方法:

public string FormatEquationList(List<Equation> listEquations)
{
    string output = string.Empty;
    foreach (Equation e in listEquations)
    {
        // only append " and " when there's something to append to
        if (output != string.Empty)
            output += " and ";

        output += "(" + e.LeftSide + e.Operator + e.RightSide + ")";
    }
    return output;
}

当然,使用StringBuilder通常会更快:

public string FormatEquationList(List<Equation> listEquations)
{
    StringBuilder output = new StringBuilder();
    foreach (Equation e in listEquations)
    {
        // only append " and " when there's something to append to
        if (output.Length > 0)
            output.Append(" and ");

        output.Append("(");
        output.Append(e.LeftSide);
        output.Append(e.Operator);
        output.Append(e.RightSide);
        output.Append(")");
    }

    return output.ToString();
}