【问题标题】:Increment string if exists如果存在则增加字符串
【发布时间】:2020-02-04 20:35:27
【问题描述】:

我需要一段在“[]”括号中增加字符串结尾的代码,但我对此感到头疼。

问题是,如果给定集合中存在名称“test”,算法应该返回test_[0],如果两者都存在则“test_[1]”等。到目前为止有效。但是,当我尝试将 currentName 值作为“test_[something]”传递时,算法会创建类似test_[0]_[0]test_[0]_[1] 而不是test_[somenthing+someNumber]。有谁知道改变这种行为的方法吗?

//                                           test                   test, test_[2], test_[3]
protected string GetDistinctName2(string currentName, IEnumerable<string> existingNames)
{
    int iteration = 0;
    if (existingNames.Any(n => n.Equals(currentName)))
    {
        do
        {
            if (!currentName.EndsWith($"({iteration})"))
            {
                currentName = $"{currentName}_[{++iteration}]";
            }
        }
        while (existingNames.Any(n => n.Equals(currentName)));
    }

    return currentName;
}

编辑: 到目前为止最好的解决方案是(我敢打赌我在这里看到过,但有人不得不删除)

public static void Main()
{
        var currentOriginal = "test";
        var existingNamesOriginal = new[] { "test", "test_[2]", "test_[3]" };
        string outputOriginal = GetDistinctNameFromSO(currentOriginal, existingNamesOriginal);
        Console.WriteLine("original : " + outputOriginal);

        Console.ReadLine();
}

    protected static string GetDistinctNameFromSO(string currentName,
                                             IEnumerable<string> existingNames)
    {
        if (null == currentName)
            throw new ArgumentNullException(nameof(currentName));
        else if (null == existingNames)
            throw new ArgumentNullException(nameof(existingNames));

        string pattern = $@"^{Regex.Escape(currentName)}(?:_\[(?<Number>[0-9]+)\])?$";

        Regex regex = new Regex(pattern);

        var next = existingNames
          .Select(item => regex.Match(item))
          .Where(match => match.Success)
          .Select(match => string.IsNullOrEmpty(match.Groups["Number"].Value)
             ? 1
             : int.Parse(match.Groups["Number"].Value))
          .DefaultIfEmpty()
          .Max() + 1;

        if (next == 1)
            return currentName; // No existingNames - return currentName
        else
            return $"{currentName}_[{next}]";
    }

对于给定的“test”字符串,它返回“test_[4]”,这很好,但如果给定的字符串是“test_[2]”,它也应该返回“test_[4]”(给定模式的字符串第一个空闲数字),但它返回“test_[2]_[2]”。

【问题讨论】:

  • 感谢您抽出宝贵时间分享您的问题。你的问题质量很低。你的目标和困难是什么?到目前为止你做了什么?请尝试更好地解释您的问题、您的开发环境和数据结构,并分享更多代码(无屏幕截图)、屏幕图像或草图以及用户故事或场景图。为了帮助您改进查询,请考虑阅读 How do I ask a good question
  • 请详细一点,OP
  • 不是传递currentName = "test_[0]"作为参数,而是传递currentName = "test", iteration = 0,所以这两个部分(名称和迭代)在方法签名中都是可变的
  • 基于格式化和比较字符串的迭代解决方案开始遇到几千个项目的性能问题,你同意吗?
  • EndsWith 的测试中,您使用圆括号“()”,但输入包含方括号“[]”

标签: c# string algorithm linq ienumerable


【解决方案1】:

这是一个更简单的重写:

protected string GetDistinctName2(string currentName, IEnumerable<string> existingNames)
{
    int iteration = 0;
    var name = currentName;

    while(existingNames.Contains(name))
    {   
        name = currentName + "_[" + (iteration++) + "]";
    }

    return name;
}

测试:

GetDistinctName2("test", new List<string> {"test", "test_[0]", "test_[2]", "test_[3]"}).Dump();//Out: test_[1]
GetDistinctName2("test", new List<string> {"test", "test_[0]", "test_[1]", "test_[2]", "test_[3]"}).Dump();//Out: test_[4]
GetDistinctName2("test", new List<string> {}).Dump();//Out: test

【讨论】:

  • 我建议将 IEnumerable&lt;string&gt; 复制到 HashSet&lt;string&gt; 是值得的,前提是您可以迭代几次。
【解决方案2】:

我将尝试对您的代码进行最小的调整来回答:

  1. 使用方括号检查名称是否存在
  2. 使用局部变量防止反复添加 [0]
  3. 在每个 do/while 循环中增加 iteration
  4. 如果结果不应该是“测试”,则将其从现有结果中排除

结果看起来像(未经测试,但这应该可以帮助您):

//                                           test                   test, test_[2], test_[3]
protected string GetDistinctName2(string currentName, IEnumerable<string> existingNames)
{
    int iteration = 0;

    // Use a different variable this will prevent you from adding [0] again and again
    var result = currentName;
    if (existingNames.Where(s => s != currentName).Any(n => n.Equals(result)))
    {
        do
        {

            // Use square brackets
            if (!result .EndsWith($"[{iteration}]"))
            {
                result = $"{currentName}_[{iteration}]";
            }
            iteration++; // Increment with every step
        }
        while (existingNames.Any(n => n.Equals(result)));
    }

    return result;
}

【讨论】:

    【解决方案3】:

    你对你的问题的描述和你的代码完全不同。这里将在方括号内增加一个数字,而不附加额外的文本。

    对初始代码的更改解决了问题中提到的一个问题,即在方括号内包含带有数字的文本。您可以在下面将something 替换为其他文本。

    protected string GetDistinctName2(string currentName, IEnumerable<string> existingNames)
    {
        int iteration = 0;
        string nextName = currentName;
        while (existingNames.Contains(nextName))
        {
            nextName = $"{currentName}_[something{iteration}]";
            iteration++;
        }
    
        return nextName;
    }
    

    C# 交互式 shell 示例:

    > GetDistinctName2("test", new List<string>() { "test", "test_[something0]", "test_[something1]"})
    "test_[something2]"
    

    【讨论】:

    • 您能否详细说明这如何解决 OP 问题以及 OP 导致问题的原因?
    • “我没有看到你的迭代变量在你的代码中递增。”那里:currentName = $"{currentName}_[{++iteration}]";(注意++iteration
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-07-05
    • 1970-01-01
    • 2022-08-18
    • 1970-01-01
    • 2019-08-07
    • 1970-01-01
    相关资源
    最近更新 更多