简体   繁体   English

将此递归python方法转换为Java的最佳方法是什么?

[英]What is the best way to translate this recursive python method into Java?

In another question I was provided with a great answer involving generating certain sets for the Chinese Postman Problem. 另一个问题中,我得到了一个很好的答案,其中涉及为中国邮递员问题生成某些集合。

The answer provided was: 提供的答案是:

def get_pairs(s):
    if not s: yield []
    else:
        i = min(s)
        for j in s - set([i]):
           for r in get_pairs(s - set([i, j])):
               yield [(i, j)] + r

for x in get_pairs(set([1,2,3,4,5,6])):
    print x

This will output the desire result of: 这将输出以下结果:

[(1, 2), (3, 4), (5, 6)]  
[(1, 2), (3, 5), (4, 6)]  
[(1, 2), (3, 6), (4, 5)]  
[(1, 3), (2, 4), (5, 6)]  
[(1, 3), (2, 5), (4, 6)]  
[(1, 3), (2, 6), (4, 5)]  
[(1, 4), (2, 3), (5, 6)]  
[(1, 4), (2, 5), (3, 6)]  
[(1, 4), (2, 6), (3, 5)]  
[(1, 5), (2, 3), (4, 6)]  
[(1, 5), (2, 4), (3, 6)]  
[(1, 5), (2, 6), (3, 4)]  
[(1, 6), (2, 3), (4, 5)]  
[(1, 6), (2, 4), (3, 5)]  
[(1, 6), (2, 5), (3, 4)]  

This really shows off the expressiveness of Python because this is almost exactly how I would write the pseudo-code for the algorithm. 这确实展示了Python的表现力,因为这几乎就是我为算法编写伪代码的方式。 I especially like the usage of yield and and the way that sets are treated as first class citizens. 我尤其喜欢收益率的使用以及将集合视为头等公民的方式。

However, there in lies my problem. 但是,这是我的问题所在。

What would be the best way to: 最好的方法是:

1.Duplicate the functionality of the yield return construct in Java? 1.复制Java中的收益回报结构的功能吗? Would it instead be best to maintain a list and append my partial results to this list? 相反,最好是维护一个列表并将我的部分结果附加到此列表中吗? How would you handle the yield keyword. 您将如何处理yield关键字。

2.Handle the dealing with the sets? 2.处理成套物品? I know that I could probably use one of the Java collections which implements that implements the Set interface and then using things like removeAll() to give me a set difference. 我知道我可能会使用实现Set接口的Java集合之一,然后使用removeAll()之类的东西给我带来一些不同。 Is this what you would do in that case? 在这种情况下,您会这样做吗?

Ultimately, I'm looking to reduce this method into as concise and straightforward way as possible in Java. 最终,我希望将这种方法简化为Java中尽可能简洁明了的方法。 I'm thinking the return type of the java version of this method will likely return a list of int arrays or something similar. 我在想这种方法的Java版本的返回类型可能会返回一个int数组或类似的列表。

How would you handle the situations above when converting this method into Java? 将此方法转换为Java时,您将如何处理上述情况?

In order to translate a generator function to Java you have to reimplement it as a Iterable+Iterator. 为了将生成器函数转换为Java,您必须将其重新实现为Iterable + Iterator。 Eg: 例如:

def foo(x):
   for i in xrange(10):
      yield x * i
...
for x in foo(5):
   print(x)

Becomes (warning: code is not tested): 变为(警告:代码未经测试):

import java.util.Iterator;
import java.util.Iterable;

class Foo implements Iterable<Integer> {
   public final int x;

   public Foo(int x) {
      this.x = x;
   }

   public Iterator<Integer> iterate() {
      return new Iterator<Integer> {
         int i = 0;

         public boolean hasNext() {
            return i < 10;
         }

         public Integer next() {
            return x * (i ++);
         }
      };
   }
}
...
for (int x : new Foo(5)) {
   System.out.println(x);
}

For the sets I would indeed use java.util.HashSet . 对于集合,我确实会使用java.util.HashSet

You probably want to run it on a JVM. 您可能想在JVM上运行它。 Why not use Scala? 为什么不使用Scala?

I think you can translate the python code into almost the same kind of code in scala. 我认为您可以在scala中将python代码转换成几乎相同的代码。 Much better then the verbose java stuff. 比冗长的Java东西好得多。 And it's jvm bytecode in the end which will easily blend in/cooperate with your java app. 最后是jvm字节码,可以轻松地与您的Java应用程序融合/配合使用。

This isn't what you asked for, but I wanted to try it out, so here's a solution in C# using LINQ: 这不是您要的,但是我想尝试一下,因此这是使用LINQ的C#解决方案:

static IEnumerable<IEnumerable<int>> getPairs(IEnumerable<int> list)
{
    if (!list.Any())
        return new [] { new int[0] };

    var first = list.First();
    return from second in list.Skip(1)
           from pair in getPairs(list.Skip(1).Where(rest => rest != second))
           select Enumerable.Concat(new [] { first, second }, pair);
}

Doesn't actually return pairs, just ordered lists of integers, but chopping it up by twos after this is easy. 实际上并不返回对,而只是返回整数的有序列表,但是在此之后将其切成二很容易。 Also, nice to see that C# can rival the conciseness of Python. 另外,很高兴看到C#可以与Python的简洁性相媲美。
Testing it out: 测试一下:

foreach (var p in getPairs(new [] { 1, 2, 3, 4, 5, 6 }))
    Console.WriteLine("[" + 
        String.Join(",", p.Select(i => i.ToString()).ToArray()) + "]");

And the output: 并输出:

[1,2,3,4,5,6]
[1,2,3,5,4,6]
[1,2,3,6,4,5]
[1,3,2,4,5,6]
[1,3,2,5,4,6]
[1,3,2,6,4,5]
[1,4,2,3,5,6]
[1,4,2,5,3,6]
[1,4,2,6,3,5]
[1,5,2,3,4,6]
[1,5,2,4,3,6]
[1,5,2,6,3,4]
[1,6,2,3,4,5]
[1,6,2,4,3,5]
[1,6,2,5,3,4]

Credit to Noldorin's answer to another LINQ question for some ideas. 感谢Noldorin对另一个LINQ问题的回答的一些想法。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM