【问题标题】:How can I separate the sequential print statements from nested for-loops?如何将顺序打印语句与嵌套的 for 循环分开?
【发布时间】:2015-02-04 18:51:48
【问题描述】:

我有以下方法可以打印出给定数组的所有连续子集。我希望能够将交织在 for 循环中的丑陋 print 语句分离出来并放入一个新函数中。这是可行的吗?

    // Example:  
    // Input: char[] input = new char[] { 'a', 'b', 'c' };
    // Output: 
    //        (a) (a b) (a b c)
    //        (b) (b c)
    //        (c)  

    static void  PrintContSubArrays(char[] arr)
    {
        int len = arr.Length;
        StringBuilder sb1 = new StringBuilder();
        StringBuilder sb2 = new StringBuilder();

        for (int i = 0; i < len; i++)
        {
            for (int j = 1; j <= len; j++)
            {
                sb2.AppendFormat("(");

                for (int k = i; k < j; k++)
                {
                    sb2.AppendFormat("{0} ", arr[k]);
                }

                sb2.Remove(sb2.Length - 1, 1);
                sb2.Append(") ");

                if (sb2.Length > 3) sb1.Append(sb2);
                sb2.Clear();
            }
            sb1.Append(System.Environment.NewLine);
        }

        Console.WriteLine(sb1.ToString());
        Console.ReadLine();
    }

【问题讨论】:

  • 你能写出想要的结果吗,函数会做什么以及如何调用它?
  • 你在说什么印刷品?字符串生成器追加?
  • @usr 是的,在当前的实现中,字符串生成器收集字符并在最后打印出来。我想取消 sb 声明。
  • @Andrei 结果应该和现在一样。我希望能够像函数当前那样调用函数并在控制台上打印结果,但不知何故,将字符从数组发送到另一个负责格式化和打印最终结果的函数。我不确定这是否可行——或者我是否有意义。如果这仍然不清楚,请告诉我。谢谢!

标签: c# for-loop code-separation


【解决方案1】:

根据@usr 的建议实现了这个

而不是进行字符串处理内联提取子数组为 char[] 并使用 yield return 返回它们。这样调用者 接收子数组流。他可以处理、格式化和打印它们 随心所欲。

这就是我所拥有的。但这并不能转化为您的确切输出格式。由于上下文丢失,某些格式会丢失。如果您愿意将原始数组长度传递给 print 方法,则可以通过调整 print 方法中的 for 循环来获得所需的内容。

    // Input: int[] input = new int[] { 1, 2, 3};
    // Call: Console.WriteLine(PrintContSubArrays(GetContSubArrays(input)));
    // Output: 
    //       (1)
    //       (1 2)
    //       (1 2 3)
    //       (2)
    //       (2 3)
    //       (3)

    // Generate subsets
    static IEnumerable<int[]> GetContSubArrays(int[] arr)
    {
        int len = arr.Length;

        for (int i = 0; i < len; i++)
        {
            for (int j = 1; j <= len; j++)
            {
                int[] placeholder = new int[j - i < 0 ? 0 : j - i];
                bool isPlaceholderEmpty = true;

                for (int k = i; k < j; k++)
                {
                    placeholder[k - i] = arr[k];
                    isPlaceholderEmpty = false;
                }
                if (!isPlaceholderEmpty) yield return placeholder;
            }
        }
    }

    // Print
    static string PrintContSubArrays(IEnumerable<int[]> input)
    {
        StringBuilder sb1 = new StringBuilder();

        foreach (int[] intarr in input)
        {
            if (intarr != null)
            {
                sb1.Append("(");
                foreach (int intsingle in intarr)
                {
                    sb1.AppendFormat("{0} ", intsingle);
                }
                sb1.Remove(sb1.Length - 1, 1);
                sb1.Append(")");
            }
            sb1.AppendFormat(Environment.NewLine);
        }

        return sb1.ToString();
    }

【讨论】:

    【解决方案2】:

    不进行字符串处理,而是将子数组提取为char[] 并使用yield return 返回它们。这样调用者就会收到一个子数组流。他可以随心所欲地处理、格式化和打印它们。

    【讨论】:

      【解决方案3】:

      这是简化事情的一种方法:

      static void PrintContiguousSubArrays( char[] input )
      {
        if ( input == null ) throw new ArgumentNullException("input") ;
        if ( input.Length == 0 ) return ;
      
        for ( int offset = 0 ; offset < input.Length ; ++offset )
        {
          string separator = "" ;
      
          for ( int length = 1 ; offset+length <= input.Length ; ++length )
          {
            Console.Write( "{0}[{1}]" ,
              separator ,
              string.Join("," , input.Skip(offset).Take(length).Select( c => new string(c,1) ) )
              );
            separator = " ";
          }
          Console.WriteLine();
      
        }
      
        return ;
      }
      

      这是另一种方式:

      static IEnumerable<IEnumerable<char>> ContiguousSubArraysOf( char[] input )
      {
        if ( input == null ) throw new ArgumentNullException("input") ;
      
        for ( int offset = 0 ; offset < input.Length ; ++offset )
        {
          for ( int length = 1 ; offset+length <= input.Length ; ++length )
          {
            yield return input.Skip(offset).Take(length) ;
          }
        }
      
      }
      

      这会让你说这样的话:

      char[] input = "abc".ToCharArray();
      
      foreach( var item in ContiguousSubArraysOf(input) )
      {
        Console.WriteLine( "[{0}]" ,
          string.Join( "," , item.Select( c => new string(c,1) ) )
        ) ;
      }
      

      【讨论】:

        【解决方案4】:

        这样做怎么样?

        static void PrintContSubArrays(char[] arr)
        {
            Console.WriteLine(String.Join(Environment.NewLine,
                    from n1 in Enumerable.Range(0, arr.Length)
                    select String.Join(" ",
                        from n2 in Enumerable.Range(1, arr.Length - n1)
                        select String.Format("({0})", String.Join(" ", arr.Skip(n1).Take(n2))))));
            Console.ReadLine();
        }
        

        这样你也可以摆脱所有丑陋的循环。

        【讨论】:

        • +1 优雅的代码!我认为这是所提供代码的最佳替代方案。但是,OP 要求将核心操作和打印操作分开。
        猜你喜欢
        • 2020-06-18
        • 2019-02-27
        • 2015-01-18
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-06-05
        • 2019-04-22
        • 1970-01-01
        相关资源
        最近更新 更多