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

发布于 2024-08-21 15:29:32 字数 1192 浏览 3 评论 0原文

这个问题困扰了我很多年,当有更好的解决方案时,我总是觉得我正在想出一个办法。当您想要对列表中的所有项目执行某些操作,然后在这些项目之间添加某些内容时,就会出现当前的问题。简而言之,我想要:

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

例如,假设我有一个名为 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 循环,并仅在不是最后一个时添加 in Between 元素物品;但这似乎是一个黑客。

是否有处理此类问题的标准方法?

This problem has bugged me for years, and I always feel like I'm coming up with a hack when there's a much better solution. The issue at hand occurs when you want to do something to all items in a list and then add something inbetween those items. In short, I want to:

  • Do something to every item in the list.
  • Do something else to all but the last item in the list (in effect, do something "inbetween" the items in the list).

For example, let's say I have a class called Equation:

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

I want to iterate over a list of Equations and return a string that formats these items together; something like the following:

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

The problem with the above code is that it is going to include and at the end of the returned string. I know that I could hack some code together, replace the foreach with a for loop, and add the inbetween element only if it's not the last item; but this seems like a hack.

Is there a standard methodology for how to deal with this type of problem?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

匿名的好友 2024-08-28 15:29:33

我喜欢已经发布的 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();
}

I like the String.Join method already posted.

But when you're not using an Array this has normally been my solution to this problem:

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

Of course, it's usually faster to use a 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();
}
忘羡 2024-08-28 15:29:32

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

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

这些选项中的任何一个都可以是实现“项目之间”样式算法的合法方式。您选择哪一个取决于以下因素:

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

等等。对于字符串的具体情况,我个人更喜欢使用 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();
}

第二个选项看起来像:

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() 进行字符串连接,因为它会产生许多中间的、被丢弃的字符串它也不是将一堆结果“连接”在一起的最明显的方式 - 它主要用于以某种任意的、调用者定义的方式从集合中计算“标量”结果。

You basically have a few different strategies for dealing with this kind problem:

  1. Process the first (or last) item outside of the loop.
  2. Perform the work and then "undo" the extraneous step.
  3. Detect that your're processing the first or last item inside the loop.
  4. Use a higher-level abstraction that allows you to avoid the situation.

Any of these options can be a legitimate way to implement a "between the items" style of algorithm. Which one you choose depends on things like:

  • which style you like
  • how expensive "undoing work" is
  • how expensive each "join" step is
  • whether there are any side effects

Amongst other things. For the specific case of string, I personally prefer using string.Join(), as I find it illustrates the intent most clearly. Also, in the case of strings, if you aren't using string.Join(), you should try to use StringBuilder to avoid creating too many temporary strings (a consequence of strings being immutable in .Net).

Using string concatentation as the example, the different options break down into examples as follows. (For simplicity, assume Equation has ToString() as: "(" + 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();
}

The second option looks like:

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

The third would look something like:

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

The last option can take multiple forms in .NET, using either String.Join or Linq:

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

or:

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

Personally, I avoid using Aggregate() for string concatenation because it results in many intermediate, discarded strings. It's also not the most obvious way to "join" a bunch of results together - it's primarily geared for computing a "scalar" results from a collection in some arbitrary, caller-defined fashion.

花开浅夏 2024-08-28 15:29:32

您可以使用String.Join()

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

You can use String.Join().

String.Join(" and ",listEquations.Select(e=>String.Format("({0}{1}{2})",e.LeftSide,e.Operator,e.RightSide).ToArray());
椵侞 2024-08-28 15:29:32

您可以使用 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 + ")");
}

You can do this with LINQ's Aggregate operator:

public string FormatEquationList(List<Equation> listEquations)
{
    return listEquations.Aggregate((a, b) => 
        "(" + a.LeftSide + a.Operator + a.RightSide + ") and (" + 
              b.LeftSide + b.Operator + b.RightSide + ")");
}
樱桃奶球 2024-08-28 15:29:32

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

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

Using a for loop with counter is perfectly reasonable if you don't want a foreach loop. This is why there is more than one type of looping statement.

If you want to process items pairwise, loop at LINQ's Aggregate operator.

清晰传感 2024-08-28 15:29:32

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

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() 函数,+1 表示 Linqiness 。我的例子是一个更传统的解决方案。

I usualy add it before the condition, and check if its the 1st item.

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

I have to say I would look at the string.Join() function as well, +1 for Linqiness on that. My example is a more of a traditional solution.

jJeQQOZ5 2024-08-28 15:29:32

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

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

I generally try to prefix separators based on a condition rather than add them to the end.

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

0 and 1 and 2 and 3 and 4 and 5 and 6 and 7 and 8 and 9

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文