Есть ли более элегантные способы обработки списков в Java?(Python VS Java) - PullRequest
7 голосов
/ 11 января 2011

Мне нравится, как я могу обрабатывать списки в Python.Это делает любое рекурсивное решение выглядеть легко и чисто.Например, типичная проблема получения всех перестановок элементов в списке в Python выглядит следующим образом:

def permutation_recursion(numbers,sol):
    if not numbers:
        print "this is a permutation", sol
    for i in range(len(numbers)):
        permutation_recursion(numbers[:i] + numbers[i+1:], sol + [numbers[i]])

def get_permutations(numbers):
    permutation_recursion(numbers,list())

if __name__ == "__main__":
    get_permutations([1,2,3])

Мне нравится способ, которым я могу просто получить новые экземпляры измененных списков, выполняя такие вещи, как numbers[:i] + numbers[i+1:] или sol + [numbers[i]]

Если я пытаюсь кодировать точно так же в Java, это выглядит следующим образом:

import java.util.ArrayList;
import java.util.Arrays;

class rec {
    static void permutation_recursion(ArrayList<Integer> numbers, ArrayList<Integer> sol) {
       if (numbers.size() == 0)
            System.out.println("permutation="+Arrays.toString(sol.toArray()));
       for(int i=0;i<numbers.size();i++) {
             int n = numbers.get(i);

             ArrayList<Integer> remaining = new ArrayList<Integer>(numbers);
             remaining.remove(i);

             ArrayList<Integer> sol_rec = new ArrayList<Integer>(sol);
             sol_rec.add(n);

             permutation_recursion(remaining,sol_rec);
       }
    }
    static void get_permutation(ArrayList<Integer> numbers) {
        permutation_recursion(numbers,new ArrayList<Integer>());
    }
    public static void main(String args[]) {
        Integer[] numbers = {1,2,3};
        get_permutation(new ArrayList<Integer>(Arrays.asList(numbers)));
    }
}

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

ArrayList<Integer> remaining = new ArrayList<Integer>(numbers);
remaining.remove(i);

ArrayList<Integer> sol_rec = new ArrayList<Integer>(sol);
sol_rec.add(n);

Что довольно уродливо, и оно ухудшается для более сложных решений.Как и в в этом примере

Так что мой вопрос ... есть ли какие-либо встроенные операторы или вспомогательные функции в Java API, которые сделали бы это решение более "Pythonic"?

Ответы [ 5 ]

8 голосов
/ 11 января 2011

Нет.

Но именно поэтому Мартин Одерски создал Scala . Он даже сказал, что одной из его целей для Scala является то, что это будет Python из мира Java. Scala компилируется в байт-код Java и легко взаимодействует с скомпилированными классами Java.

Если это не вариант, вы можете взглянуть на библиотеку Commons Collection .

2 голосов
/ 11 января 2011

Вы можете использовать функцию clone() в списках, чтобы получить их мелкую копию.Таким образом, вам не придется создавать экземпляр нового объекта самостоятельно, а просто использовать копию.

ArrayList<Integer> remaining = remaining.clone().remove(i);

Кроме этого, нет, java не имеет таких операторов для списков.

1 голос
/ 12 января 2011

Для разных языков требуются разные стили.Попытка выполнить mylist[:i] + mylist[i+1:] в Java - это все равно, что использовать молоток с винтом.Да, вы можете сделать это, но это не очень аккуратно.Я полагаю, что эквивалентом может быть что-то вроде ArrayList temp = new ArrayList(list); temp.remove(index);

. Я считаю, что следующее выполняет ту же задачу, но делает это немного по-другому, но не испытывает проблем с читаемостью.Вместо того, чтобы создавать новый список, он изменяет список, передает его и возвращает список в его предыдущее состояние, когда возвращается рекурсивный вызов.

import java.util.Arrays;
import java.util.List;
import java.util.ArrayList;

public class Permutation {

   public static void main(String[] args) {

      List<List<Integer>> result = permutations(
                                       Arrays.asList( 
                                          new Integer[] {1,2,3}));

      for (List<Integer> permutation : result) {
         System.out.println(permutation);  
      }
   }


   public static <T> List<List<T>> permutations(List<T> input) {
      List<List<T>> out = new ArrayList<List<T>>();
      permutationsSlave(input, new ArrayList<T>(), out);
      return out;
   }

   public static <T> void permutationsSlave(List<T> input, 
            ArrayList<T> permutation, List<List<T>> result) {

      if (input.size() == chosen.size()) {
         result.add(new ArrayList<T>(permutation));
         return;
      }

      for (T obj : input) {
         if (!permutation.contains(obj)) {
            permutation.add(obj);
            permutationsSlave(input, permutation, result);
            permutation.remove(permutation.size()-1);
         }
      } 

   }
}

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

Но тогда и мое собственное решение не слишком эффективно - вместо создания нескольких новыхобъекты, которые он выполняет избыточные сравнения (хотя некоторые из них могут быть смягчены с помощью аккумуляторов).

1 голос
/ 11 января 2011

Apache Commons решает множество подобных проблем. Посмотрите на ArrayUtils , чтобы сделать нарезку. В Java не так много синтаксического сахара, как в языках сценариев по разным причинам.

0 голосов
/ 11 января 2011

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

2 цикл for можно записать так: для (Число n: цифры)

...