函数式编程中如何使用StringBuilder?

问题描述 投票:0回答:2

我最近正在阅读有关函数式编程的内容。我最常说它带来了很大的好处,但我有一些性能问题,比如渲染一个非常大的字符串时,比如连接很多字符串的 html 页面。 通常我会使用字符串生成器。但我无法在仍然遵循函数式编程范例的情况下使用它。

性能不佳代码:
如您所见

ToListItem
ToUl
是纯函数

    class Program
    {
        static string ToListItem(string s)
        {
            return "<li>" + s + "</li>";
        }
        static string ToUl(string[] items)
        {
            return "<ul>" + String.Join("", items.Select(x => ToListItem(x))) + "</ul>";
        }

        static void Main(string[] args)
        {
            string[] items = new string[]
            {
               "Apple",
               "Orange",
               "Banana"
            };

            string htmlUl = ToUl(items);
            Console.WriteLine(htmlUl);

        }
    }

更快的代码
但正如你所看到的

ToListItem
ToUl
不再是纯函数,我无法提供在纯函数中使用
StringBuilder
的解决方案

    class Program
    {
        static void ToListItem(string s,StringBuilder sb)
        {
            sb.Append("<li>" + s + "</li>");
        }
        static void ToUl(string[] items, StringBuilder sb)
        {
            sb.Append("<ul>");

            foreach (var item in items)
                ToListItem(item, sb);

            sb.Append("</ul>");
        }

        static void Main(string[] args)
        {
            string[] items = new string[]
            {
               "Apple",
               "Orange",
               "Banana"
            };

            StringBuilder sb = new StringBuilder();

            ToUl(items, sb);
            Console.WriteLine(sb.ToString());

        }
    }

所以我的问题是:

可以用函数式编程方式使用StringBuilder吗?如何?如果不是,替代的性能解决方案是什么?

更新1 我举了一些例子。这里的性能并不重要,但随着列表线性增长,性能差距将呈指数级增长。

c# functional-programming stringbuilder
2个回答
2
投票

这并不能完全解决上述情况,但它提供了一个基线,您可以在此基础上使用页眉和页脚参数为您的案例构建一些内容。

using System;
using System.Collections.Generic;
using System.Text;

public static class FunctionalStringBuilder
{
    public static string BuildString<T>(this IEnumerable<T> enumerable, Func<T, string> response)
    {
        var builder = new StringBuilder();

        foreach (var item in enumerable)
        {
            builder.Append(response(item));
        }

        return builder.ToString();
    }
}

你可以这样使用它:

    var list = new List<Employee>
    {
        AutoFaker.Generate<Employee>(),
        AutoFaker.Generate<Employee>(),
        AutoFaker.Generate<Employee>(),
        AutoFaker.Generate<Employee>()
    };
    var result = list.BuildString(
                    e => $"Employee Id: {e.Id}, Name: {e.Name}, DateOfBirth: {e.DateOfBirth}\n");

0
投票

我想你可能会回到什么是函数式编程。要实现函数式编程,您需要函数的返回值作为下一个函数继续执行等。我对您的代码有一些更改建议。

如果您看到 StringBuilder.append() 的 javaDoc,该函数将返回 StringBuilder,因此通过这些知识,您可以通过在另一个追加后调用追加来实现该方法作为函数式编程。

package org.example;

import java.util.Arrays;
import java.util.Optional;

public class StringBuilderFunctionalMain {

  static StringBuilder addListItems(String[] items, StringBuilder sb) {
    Arrays.stream(items)
        .forEach(item -> sb.append("<li>").append(item).append("</li>"));
    return sb;
  }

  static StringBuilder toUl(String[] items, StringBuilder sb) {
    return Optional.of(sb)
        .map(stringBuilder -> stringBuilder.append("<ul>"))
        .map(stringBuilder -> addListItems(items, sb))
        .map(stringBuilder -> stringBuilder.append("</ul>"))
        .get();
  }

  public static void main(String[] args) {
    String[] items = new String[]
        {
            "Apple",
            "Orange",
            "Banana"
        };
    Optional.of(new StringBuilder())
        .map(sb -> toUl(items, sb))
        .ifPresent(System.out::println);
  }
}

这样就可以像函数式编程一样实现StringBuilder了。

© www.soinside.com 2019 - 2024. All rights reserved.