Рекурсивный, вложенный ход списка

  

Предоставлен вложенный список строк ( который может содержать другие вложенные списки), распечатать содержимое списка и соответствующую глубину.

Вот мое решение:

private static void dumpList(String string, List l) {
    int n = l.size();
    for (int i = 0; i < n; i++) {
        if(l.get(i) instanceof String){
            System.out.println(string+i + " " + l.get(i));
        }
        if(l.get(i) instanceof List){
            dumpList(string+i, (List)l.get(i));
        }
    }
}

Вот main():

public static void main(String[] args) {
    String s = "Foo";
    List l = new ArrayList();
    ArrayList<String> a = new ArrayList<String>();
    ArrayList<String> b = new ArrayList<String>();
    //ArrayList<String> c = new ArrayList<String>();
    a.add("a");
    a.add("b");
    a.add("c");
    b.add("eggs");
    l.add("a string");
    l.add(a);
    l.add("spam");
    l.add("eggs");
    dumpList("Foo", l);
}

Мой вывод:

 Foo0 a string
Foo10 a
Foo11 b
Foo12 c
Foo2 spam
Foo3 eggs

Я не так сильно интересуюсь именами переменных, но и форматированием вывода. Должен ли я использовать StringBuilder вместо + оператор? Должен ли я печатать его по-другому?

11 голосов | спросил user3371223 18 AM000000120000004131 2014, 00:04:41

3 ответа


8

Это в дополнение к тому, что уже сказал @tim.

Метод dumpList принимает код List, а затем вы делаете 2 вызова .get(i) на каждой итерации цикла. Имейте в виду, что интерфейс List не обеспечивает произвольный доступ. Например, я могу вызвать этот метод с помощью параметра LinkedList, в этом случае вызовы .get(i) будут дорогостоящими. Либо измените параметр метода на ArrayList, либо аналогичный список произвольного доступа, или изменить способ повторения (я рекомендую), например, например:

private static void dumpList(String string, List<Object> list) {
    int i = 0;
    for (Object item : list) {
        if (item instanceof List) {
            dumpList(string + i, (List) item);
        } else {
            System.out.println(String.format("%s%d %s", string, i, item));
        }
        ++i;
    }
}

Вместо того, чтобы делать if (item instanceof String), а затем if (item instanceof List), лучше сделать if (item instanceof List) и else , Это решает сразу две проблемы:

  • Добавляет поддержку для других типов элементов, а не только для String и List, которые в противном случае были бы проигнорированы

  • Второй if должен быть либо else if или else, потому что если первый if был истинным, бессмысленно оценивать второй

Я изменил код string + i + " " + l.get(i) на (по-моему) более читаемый String.format("...", ...).

Наконец, я переименовал l в list. Однобуквенные имена переменных приемлемы как счетчики циклов, такие как i, j, k, в противном случае лучше дать значимые имена.

ответил janos 18 PM000000120000004031 2014, 12:15:40
7
  

Должен ли я использовать StringBuilder вместо +

Если производительность является проблемой, тогда да, используйте StringBuilder (см. здесь ).

Другим преимуществом такого подхода является то, что вы отделяете сбор данных от печати данных. Было бы легко изменить команду печати, например, командой для последующей печати. ​​

Поскольку вы используете рекурсию, вам нужно передать ее как параметр:

private static void dumpList(String string, List l, StringBuilder sb) {
    int n = l.size();
    for (int i = 0; i < n; i++) {
        if (l.get(i) instanceof String) {
            sb.append(string).append(i).append(" ").append(l.get(i)).append("\n");
            // or Version 2: 
            // sb.append(string + i + " " + l.get(i) + "\n");
        }
        if (l.get(i) instanceof List) {
            dumpList(string + i, (List) l.get(i), sb);
        }
    }
}

(Вторая версия немного читаема, а первая версия может быть быстрее, в зависимости от реализации Java )

И затем выведите результат в main:

public static void main(String[] args) {
    String s = "Foo";
    StringBuilder sb = new StringBuilder(100);
    [...]
    dumpList("Foo", l, sb);
    System.out.println(sb.toString());
}
  

Должен ли я печатать его по-другому?

Это действительно ваше решение. Я думаю, что то, как вы это делаете, немного запутанно, я бы хотя бы добавил пробел в рекурсивном вызове между строкой и i (поэтому Foo12 становится Foo1 2). Лично я бы предпочел, чтобы результат выглядел примерно так: ["a string" (0), ["a" (1), "b" (1), "c" (1)], "spam" (0), "eggs" (0)] (где цифры - это уровень глубины), но это действительно зависит от что вы хотите сделать с кодом.

Кроме того, прямо сейчас вы не печатаете соответствующую глубину элемента (вы печатаете каждую позицию внутри уровня глубины). Для этого вам понадобится другой аргумент, который вы можете увеличить каждый раз при вызове dumpList:

private static void dumpList(String string, List l, StringBuilder sb, int depth) {
    [...]
            dumpList(string + i, (List) l.get(i), sb, depth + 1);
    [...]
}

И, кстати, вы никогда не используете список b.

ответил tim 18 AM00000020000001231 2014, 02:32:12
7

Это в дополнение к тому, что уже сказал @janos.

Две вещи:

  • Используйте дженерики лучше. List<?> достаточно, когда вы перебираете список. Это позволит передать все типы списка методу, например List<String>, List<MySpecialType>

  • Действительно ли важно быть List конкретно? Нет, вам все равно, что это Iterable. Который также поддержит этот метод для Set s и других Collection s и даже некоторые другие типы. Iterable является более общим, чем только Collection.

С учетом сделанных изменений:

private static void dumpList(String string, Iterable<?> list) {
    int i = 0;
    for (Object item : list) {
        if (item instanceof Iterable) {
            dumpList(string + i, (Iterable<?>) item);
        } else {
            System.out.println(String.format("%s%d %s", string, i, item));
        }
        ++i;
    }
}
ответил Simon Forsberg 18 PM00000010000003631 2014, 13:24:36

Похожие вопросы

Популярные теги

security × 330linux × 316macos × 2827 × 268performance × 244command-line × 241sql-server × 235joomla-3.x × 222java × 189c++ × 186windows × 180cisco × 168bash × 158c# × 142gmail × 139arduino-uno × 139javascript × 134ssh × 133seo × 132mysql × 132