Инкрементная строка, если существует - PullRequest
0 голосов
/ 07 октября 2019

Мне нужен фрагмент кода, который увеличивает конец строки в скобках «[]», но у меня от этого болит голова.

Дело в том, что если в данной коллекции существует имя «test», алгоритм должен вернутьtest_[0], если оба существуют, то "test_ [1]" и т. Д. Это работает до сих пор. Но когда я попытался передать в качестве значения currentName «test_ [что-то]», алгоритм создает что-то вроде 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]».

Ответы [ 3 ]

0 голосов
/ 07 октября 2019

Вот более простая перезапись:

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
0 голосов
/ 07 октября 2019

Я постараюсь ответить с минимальными изменениями в вашем коде:

  1. Используйте квадратные скобки, чтобы проверить, существует ли имя
  2. Используйте локальную переменную, чтобы предотвратить добавление [0] снова и снова
  3. приращение iteration в каждом цикле do / while
  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;
}
0 голосов
/ 07 октября 2019

Ваше описание вашей проблемы и ваш код и совершенно разные. Здесь будет увеличиваться число в квадратных скобках без добавления дополнительного текста.

Изменение исходного кода решает проблему, упомянутую в вопросе о включении текста в квадратные скобки с числом. Ниже вы можете заменить 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 # пример интерактивной оболочки:

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