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

#java #java-8

#java #java-8

Вопрос:

Задан массив нужной строки в порядке их создания. Поскольку две строки не могут быть равными, та, которая появится позже, будет иметь дополнение к своему имени в форме (k), где k — наименьшее положительное целое число, такое, что полученное имя еще не используется.

 static String[] fileNaming(String[] names) {
        List<String> newNames = new ArrayList<String>();
        LinkedHashMap<String, Integer> wordCount = new LinkedHashMap<String, Integer>();
        Arrays.asList(names).stream().forEach(x -> {
            String str = x;
            if (wordCount.containsKey(x)) {
                str = x   "("   String.valueOf(wordCount.get(x))   ")";
                wordCount.merge(x, 1, Integer::sum);
                wordCount.merge(str, 1, Integer::sum);
            } else {
                wordCount.put(x, 1);
            }

            newNames.add(str);
            System.out.println(wordCount);
        });
    
        return newNames.toArray(new String[names.length]);
    }
  

Тестирование этого кода на двух строках []

 Arrays.toString(fileNaming(new String[] { "doc", "doc",
         "image", "doc(1)", "doc" }))

Arrays.toString(
                fileNaming(new String[] { "a(1)", "a(6)", "a", "a", "a", "a", "a", "a", "a", "a", "a", "a" }))
  

Желаемый результат для них обоих должен быть

 ["doc", "doc(1)", "image", "doc(1)(1)", "doc(2)"].

 ["a(1)", "a(6)",  "a",  "a(2)",  "a(3)",  "a(4)", "a(5)",  "a(7)",  "a(8)",  "a(9)",  "a(10)", "a(11)"]
  

С помощью данного кода я смог правильно сопоставить первый вывод. Но для второго я получаю

 [a(1), a(6), a, a(1), a(2), a(3), a(4), a(5), a(6), a(7), a(8), a(9)]
  

Здесь мы видим, что a(1) и a(6) повторяются. Для чего я поставил галочку, но по-прежнему не получаю желаемый результат.

Комментарии:

1. И как это связано со scala?

2. @Nosrep удалил scala. Хотя я стремился, если бы это можно было сделать в scala более просто, я бы тоже предпочел это.

3. @boilerplate.code Я прочитал заголовок вопроса 3 раза, и я все еще не могу разобрать то, что вы спрашиваете. Что вы имеете в виду, поскольку две строки не могут быть равными ? с каких пор строки не могут быть равными? что это значит -> тот, который появится позже, будет иметь дополнение к своему имени в форме (k), где k — наименьшее положительное целое число, такое, что полученное имя еще не используется. — имеется в виду?

Ответ №1:

Проблема в том, что вы не проверяете свои новые файлы, чтобы увидеть, присутствуют ли они уже. Я думаю, что это может работать так:

 static String[] fileNaming(String[] names) {
        List<String> newNames = new ArrayList<String>();
        var usedNames = new HashSet<String>();
        Arrays.asList(names).stream().forEach(x -> {
            int retries = 0;
            var uniqueName = x;
            while (!usedNames.add(uniqueName)) {
                uniqueName = x   "("     retries   ")";
            }
            newNames.add(uniqueName);
            System.out.println(wordCount);
        });
    
        return newNames.toArray(new String[names.length]);
    }
  

Если у вас много копий одной и той же строки, это будет медленнее, чем ваш исходный код … но это проще и работает, так что это сработает! В этом случае вы могли бы настроить этот код, чтобы он был быстрее, но, вероятно, оно того не стоит (если вы не знаете, что получите много копий ваших строк).

Редактировать: Черт возьми, вот версия O (n):

 static String[] fileNaming(String[] names) {
    List<String> newNames = new ArrayList<String>();
    var usedNames = new HashSet<String>();
    var counts = new HashMap<String, Integer>();
    Arrays.asList(names).stream().forEach(x -> {
        int retries = counts.getOrDefault(x, 0);
        var uniqueName = x;
        while (!usedNames.add(uniqueName)) {
            uniqueName = x   "("     retries   ")";
        }
        newNames.add(uniqueName);
        counts.put(x, retries);
        System.out.println(wordCount);
    });

    return newNames.toArray(new String[names.length]);
}
  

Комментарии:

1. Проблема, которую я хочу в O (n), поскольку у меня может быть много копий.

2. Чтобы сделать это O (n), вам нужно иметь сопоставление от имени до целого числа; начните повторные попытки с этого целого числа, затем выполните шаг вверх и сохраните его, когда найдете уникальное имя. Это означает, что вам нужно будет перебирать usedNames только тогда, когда a (5) уже создано, и вы получите свой пятый «a», который, я думаю, по-прежнему равен O (n), потому что каждое имя может выполнить цикл не более одного раза.

3. Я пытаюсь сделать это, используя карту, но не могу достичь

4. Я отредактировал свой ответ, чтобы добавить код, который должен работать с O (n) . Я не тестировал это, но это выглядит просто.